blob: 3b58a8911d83524f8258a082276cea7d4291dc09 [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>
Karl Schultz2e5ed332017-12-12 10:33:01 -050035#if defined(__APPLE__)
36#include <CoreFoundation/CoreFoundation.h>
37#include <sys/param.h>
38#endif
Chia-I Wu13a61a52014-08-04 11:18:20 +080039#include <sys/types.h>
Johannes van Waveren9bd805012015-10-28 11:45:00 -050040#if defined(_WIN32)
Ian Elliott2d4ab1e2015-01-13 17:52:38 -070041#include "dirent_on_windows.h"
Mark Lobodzinski64318ba2017-01-26 13:34:13 -070042#else // _WIN32
Chia-I Wu13a61a52014-08-04 11:18:20 +080043#include <dirent.h>
Mark Lobodzinski64318ba2017-01-26 13:34:13 -070044#endif // _WIN32
Tobin Ehlisb835d1b2015-07-03 10:34:49 -060045#include "vk_loader_platform.h"
Chia-I Wu19300602014-08-04 08:03:57 +080046#include "loader.h"
Jon Ashburn27cd5842015-05-12 17:26:48 -060047#include "gpa_helper.h"
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060048#include "debug_report.h"
Ian Elliott954fa342015-10-30 15:28:23 -060049#include "wsi.h"
David Pinedo9316d3b2015-11-06 12:54:48 -070050#include "vulkan/vk_icd.h"
Jon Ashburn2077e382015-06-29 11:25:34 -060051#include "cJSON.h"
Jon Ashburnfc1031e2015-11-17 15:31:02 -070052#include "murmurhash.h"
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080053
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +020054#if defined(_WIN32)
55#include <Cfgmgr32.h>
56#include <initguid.h>
57#include <Devpkey.h>
58#endif
59
Mark Youngba7ee022017-03-09 10:41:25 -070060// This is a CMake generated file with #defines for any functions/includes
61// that it found present. This is currently necessary to properly determine
62// if secure_getenv or __secure_getenv are present
Jamie Madille09268a2017-03-21 13:48:13 -040063#if !defined(VULKAN_NON_CMAKE_BUILD)
Mark Youngba7ee022017-03-09 10:41:25 -070064#include "loader_cmake_config.h"
Jamie Madille09268a2017-03-21 13:48:13 -040065#endif // !defined(VULKAN_NON_CMAKE_BUILD)
Mark Youngba7ee022017-03-09 10:41:25 -070066
Mark Young0f183a82017-02-28 09:58:04 -070067// Generated file containing all the extension data
68#include "vk_loader_extensions.c"
69
Jon Ashburn27cd5842015-05-12 17:26:48 -060070struct loader_struct loader = {0};
Jon Ashburn87d6aa92015-08-28 15:19:27 -060071// TLS for instance for alloc/free callbacks
72THREAD_LOCAL_DECL struct loader_instance *tls_instance;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080073
Courtney Goeltzenleuchter0ef13a02015-12-16 16:19:46 -070074static size_t loader_platform_combine_path(char *dest, size_t len, ...);
Daniel Dadap00b4aba2015-09-30 11:50:51 -050075
Jon Ashburn24cd4be2015-11-01 14:04:06 -070076struct loader_phys_dev_per_icd {
77 uint32_t count;
78 VkPhysicalDevice *phys_devs;
Mark Young0153e0b2016-11-03 14:27:13 -060079 struct loader_icd_term *this_icd_term;
Jon Ashburn24cd4be2015-11-01 14:04:06 -070080};
81
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -060082enum loader_debug {
Jon Ashburn23d36b12016-02-02 17:47:28 -070083 LOADER_INFO_BIT = 0x01,
84 LOADER_WARN_BIT = 0x02,
85 LOADER_PERF_BIT = 0x04,
86 LOADER_ERROR_BIT = 0x08,
87 LOADER_DEBUG_BIT = 0x10,
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -060088};
89
90uint32_t g_loader_debug = 0;
91uint32_t g_loader_log_msgs = 0;
92
Jon Ashburn23d36b12016-02-02 17:47:28 -070093// thread safety lock for accessing global data structures such as "loader"
Jon Ashburn6301a0f2015-05-29 13:15:39 -060094// all entrypoints on the instance chain need to be locked except GPA
Jon Ashburn2077e382015-06-29 11:25:34 -060095// additionally CreateDevice and DestroyDevice needs to be locked
Jon Ashburn6301a0f2015-05-29 13:15:39 -060096loader_platform_thread_mutex loader_lock;
Jon Ashburn6461ef22015-09-22 13:11:00 -060097loader_platform_thread_mutex loader_json_lock;
Jon Ashburn6301a0f2015-05-29 13:15:39 -060098
Lenny Komow23342982018-01-19 11:22:28 -070099LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_init);
100
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700101void *loader_instance_heap_alloc(const struct loader_instance *instance, size_t size, VkSystemAllocationScope alloc_scope) {
Mark Young0ad83132016-06-30 13:02:42 -0600102 void *pMemory = NULL;
103#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
104 {
105#else
Chia-I Wu3432a0c2015-10-27 18:04:07 +0800106 if (instance && instance->alloc_callbacks.pfnAllocation) {
Mark Young0f183a82017-02-28 09:58:04 -0700107 // These are internal structures, so it's best to align everything to
108 // the largest unit size which is the size of a uint64_t.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700109 pMemory = instance->alloc_callbacks.pfnAllocation(instance->alloc_callbacks.pUserData, size, sizeof(uint64_t), alloc_scope);
Mark Young0ad83132016-06-30 13:02:42 -0600110 } else {
111#endif
112 pMemory = malloc(size);
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600113 }
Mark Youngf2079b92017-05-02 10:49:46 -0600114
Mark Young0ad83132016-06-30 13:02:42 -0600115 return pMemory;
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600116}
117
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700118void loader_instance_heap_free(const struct loader_instance *instance, void *pMemory) {
Mark Young0ad83132016-06-30 13:02:42 -0600119 if (pMemory != NULL) {
120#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
121 {
122#else
123 if (instance && instance->alloc_callbacks.pfnFree) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700124 instance->alloc_callbacks.pfnFree(instance->alloc_callbacks.pUserData, pMemory);
Mark Young0ad83132016-06-30 13:02:42 -0600125 } else {
126#endif
127 free(pMemory);
Mark Youngd077f992016-06-30 11:03:59 -0600128 }
Mark Young4b0b9222016-06-29 18:33:53 -0600129 }
Mark Young4b0b9222016-06-29 18:33:53 -0600130}
131
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700132void *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 -0600133 VkSystemAllocationScope alloc_scope) {
134 void *pNewMem = NULL;
135 if (pMemory == NULL || orig_size == 0) {
136 pNewMem = loader_instance_heap_alloc(instance, size, alloc_scope);
137 } else if (size == 0) {
138 loader_instance_heap_free(instance, pMemory);
139#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
140#else
141 } else if (instance && instance->alloc_callbacks.pfnReallocation) {
Mark Young0f183a82017-02-28 09:58:04 -0700142 // These are internal structures, so it's best to align everything to
143 // the largest unit size which is the size of a uint64_t.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700144 pNewMem = instance->alloc_callbacks.pfnReallocation(instance->alloc_callbacks.pUserData, pMemory, size, sizeof(uint64_t),
145 alloc_scope);
Mark Young0ad83132016-06-30 13:02:42 -0600146#endif
147 } else {
148 pNewMem = realloc(pMemory, size);
149 }
150 return pNewMem;
Mark Young4b0b9222016-06-29 18:33:53 -0600151}
152
Mark Young0ad83132016-06-30 13:02:42 -0600153void *loader_instance_tls_heap_alloc(size_t size) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700154 return loader_instance_heap_alloc(tls_instance, size, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Mark Young4b0b9222016-06-29 18:33:53 -0600155}
Mark Young4b0b9222016-06-29 18:33:53 -0600156
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700157void loader_instance_tls_heap_free(void *pMemory) { loader_instance_heap_free(tls_instance, pMemory); }
Mark Young0ad83132016-06-30 13:02:42 -0600158
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700159void *loader_device_heap_alloc(const struct loader_device *device, size_t size, VkSystemAllocationScope alloc_scope) {
Mark Young0ad83132016-06-30 13:02:42 -0600160 void *pMemory = NULL;
161#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
162 {
163#else
164 if (device && device->alloc_callbacks.pfnAllocation) {
Mark Young0f183a82017-02-28 09:58:04 -0700165 // These are internal structures, so it's best to align everything to
166 // the largest unit size which is the size of a uint64_t.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700167 pMemory = device->alloc_callbacks.pfnAllocation(device->alloc_callbacks.pUserData, size, sizeof(uint64_t), alloc_scope);
Mark Young0ad83132016-06-30 13:02:42 -0600168 } else {
169#endif
170 pMemory = malloc(size);
171 }
172 return pMemory;
173}
174
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700175void loader_device_heap_free(const struct loader_device *device, void *pMemory) {
Mark Young0ad83132016-06-30 13:02:42 -0600176 if (pMemory != NULL) {
177#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
178 {
179#else
180 if (device && device->alloc_callbacks.pfnFree) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700181 device->alloc_callbacks.pfnFree(device->alloc_callbacks.pUserData, pMemory);
Mark Young0ad83132016-06-30 13:02:42 -0600182 } else {
183#endif
184 free(pMemory);
185 }
186 }
187}
188
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700189void *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 -0600190 VkSystemAllocationScope alloc_scope) {
191 void *pNewMem = NULL;
192 if (pMemory == NULL || orig_size == 0) {
193 pNewMem = loader_device_heap_alloc(device, size, alloc_scope);
194 } else if (size == 0) {
195 loader_device_heap_free(device, pMemory);
196#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
197#else
198 } else if (device && device->alloc_callbacks.pfnReallocation) {
Mark Young0f183a82017-02-28 09:58:04 -0700199 // These are internal structures, so it's best to align everything to
200 // the largest unit size which is the size of a uint64_t.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700201 pNewMem = device->alloc_callbacks.pfnReallocation(device->alloc_callbacks.pUserData, pMemory, size, sizeof(uint64_t),
202 alloc_scope);
Mark Young0ad83132016-06-30 13:02:42 -0600203#endif
204 } else {
205 pNewMem = realloc(pMemory, size);
206 }
207 return pNewMem;
208}
209
210// Environment variables
Karl Schultz2e5ed332017-12-12 10:33:01 -0500211#if defined(__linux__) || defined(__APPLE__)
Mark Young0ad83132016-06-30 13:02:42 -0600212
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700213static inline char *loader_getenv(const char *name, const struct loader_instance *inst) {
Mark Young0ad83132016-06-30 13:02:42 -0600214 // No allocation of memory necessary for Linux, but we should at least touch
215 // the inst pointer to get rid of compiler warnings.
216 (void)inst;
Mark Youngd8c6b692017-03-09 11:39:41 -0700217 return getenv(name);
218}
219
Mark Youngd8c6b692017-03-09 11:39:41 -0700220static inline char *loader_secure_getenv(const char *name, const struct loader_instance *inst) {
Karl Schultz2e5ed332017-12-12 10:33:01 -0500221#if defined(__APPLE__)
222 // Apple does not appear to have a secure getenv implementation.
223 // The main difference between secure getenv and getenv is that secure getenv
224 // returns NULL if the process is being run with elevated privileges by a normal user.
225 // The idea is to prevent the reading of malicious environment variables by a process
226 // that can do damage.
227 // This algorithm is derived from glibc code that sets an internal
228 // variable (__libc_enable_secure) if the process is running under setuid or setgid.
229 return geteuid() != getuid() || getegid() != getgid() ? NULL : loader_getenv(name, inst);
230#else
231// Linux
Mark Youngba7ee022017-03-09 10:41:25 -0700232#ifdef HAVE_SECURE_GETENV
Karl Schultz2e5ed332017-12-12 10:33:01 -0500233 (void)inst;
Mark Youngba7ee022017-03-09 10:41:25 -0700234 return secure_getenv(name);
235#elif defined(HAVE___SECURE_GETENV)
Karl Schultz2e5ed332017-12-12 10:33:01 -0500236 (void)inst;
Mark Youngf2f2a662017-03-08 10:11:52 -0700237 return __secure_getenv(name);
238#else
Mark Youngf2079b92017-05-02 10:49:46 -0600239#pragma message( \
240 "Warning: Falling back to non-secure getenv for environmental lookups! Consider" \
241 " updating to a different libc.")
Mark Youngd8c6b692017-03-09 11:39:41 -0700242 return loader_getenv(name, inst);
Mark Youngf2f2a662017-03-08 10:11:52 -0700243#endif
Karl Schultz2e5ed332017-12-12 10:33:01 -0500244#endif
Mark Young0ad83132016-06-30 13:02:42 -0600245}
Mark Youngf2f2a662017-03-08 10:11:52 -0700246
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700247static inline void loader_free_getenv(char *val, const struct loader_instance *inst) {
Mark Young0ad83132016-06-30 13:02:42 -0600248 // No freeing of memory necessary for Linux, but we should at least touch
249 // the val and inst pointers to get rid of compiler warnings.
250 (void)val;
251 (void)inst;
252}
253
254#elif defined(WIN32)
255
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700256static inline char *loader_getenv(const char *name, const struct loader_instance *inst) {
Mark Young0ad83132016-06-30 13:02:42 -0600257 char *retVal;
258 DWORD valSize;
259
260 valSize = GetEnvironmentVariableA(name, NULL, 0);
261
262 // valSize DOES include the null terminator, so for any set variable
263 // will always be at least 1. If it's 0, the variable wasn't set.
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700264 if (valSize == 0) return NULL;
Mark Young0ad83132016-06-30 13:02:42 -0600265
266 // Allocate the space necessary for the registry entry
267 if (NULL != inst && NULL != inst->alloc_callbacks.pfnAllocation) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700268 retVal = (char *)inst->alloc_callbacks.pfnAllocation(inst->alloc_callbacks.pUserData, valSize, sizeof(char *),
269 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Mark Young0ad83132016-06-30 13:02:42 -0600270 } else {
271 retVal = (char *)malloc(valSize);
272 }
273
274 if (NULL != retVal) {
275 GetEnvironmentVariableA(name, retVal, valSize);
276 }
277
278 return retVal;
279}
280
Mark Youngd8c6b692017-03-09 11:39:41 -0700281static inline char *loader_secure_getenv(const char *name, const struct loader_instance *inst) {
Mark Youngbb3a29c2017-05-19 12:29:43 -0600282 // No secure version for Windows as far as I know
Mark Youngd8c6b692017-03-09 11:39:41 -0700283 return loader_getenv(name, inst);
284}
285
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700286static inline void loader_free_getenv(char *val, const struct loader_instance *inst) {
Mark Young0ad83132016-06-30 13:02:42 -0600287 if (NULL != inst && NULL != inst->alloc_callbacks.pfnFree) {
288 inst->alloc_callbacks.pfnFree(inst->alloc_callbacks.pUserData, val);
289 } else {
290 free((void *)val);
291 }
292}
293
294#else
295
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700296static inline char *loader_getenv(const char *name, const struct loader_instance *inst) {
Mark Young0ad83132016-06-30 13:02:42 -0600297 // stub func
298 (void)inst;
299 (void)name;
300 return NULL;
301}
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700302static inline void loader_free_getenv(char *val, const struct loader_instance *inst) {
Mark Young0ad83132016-06-30 13:02:42 -0600303 // stub func
304 (void)val;
305 (void)inst;
306}
307
308#endif
309
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700310void loader_log(const struct loader_instance *inst, VkFlags msg_type, int32_t msg_code, const char *format, ...) {
Jon Ashburn86723b02015-07-31 15:47:59 -0600311 char msg[512];
Mark Young2c84c0c2017-01-13 10:27:03 -0700312 char cmd_line_msg[512];
Mark Young5de3af72017-04-25 08:08:29 -0600313 size_t cmd_line_size = sizeof(cmd_line_msg);
Jon Ashburnffad94d2015-06-30 14:46:22 -0700314 va_list ap;
315 int ret;
316
Jon Ashburnffad94d2015-06-30 14:46:22 -0700317 va_start(ap, format);
318 ret = vsnprintf(msg, sizeof(msg), format, ap);
Jon Ashburn23d36b12016-02-02 17:47:28 -0700319 if ((ret >= (int)sizeof(msg)) || ret < 0) {
320 msg[sizeof(msg) - 1] = '\0';
Jon Ashburnffad94d2015-06-30 14:46:22 -0700321 }
322 va_end(ap);
323
Courtney Goeltzenleuchter73477392015-12-03 13:48:01 -0700324 if (inst) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700325 util_DebugReportMessage(inst, msg_type, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, (uint64_t)(uintptr_t)inst, 0, msg_code,
326 "loader", msg);
Courtney Goeltzenleuchter73477392015-12-03 13:48:01 -0700327 }
328
329 if (!(msg_type & g_loader_log_msgs)) {
330 return;
331 }
332
Mark Young2c84c0c2017-01-13 10:27:03 -0700333 cmd_line_msg[0] = '\0';
Mark Young5de3af72017-04-25 08:08:29 -0600334 cmd_line_size -= 1;
335 size_t original_size = cmd_line_size;
Mark Young2c84c0c2017-01-13 10:27:03 -0700336
337 va_start(ap, format);
338 if ((msg_type & LOADER_INFO_BIT) != 0) {
Mark Young6ef95f42017-02-17 09:02:23 -0700339 strncat(cmd_line_msg, "INFO", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700340 cmd_line_size -= 4;
341 }
342 if ((msg_type & LOADER_WARN_BIT) != 0) {
Mark Young5de3af72017-04-25 08:08:29 -0600343 if (cmd_line_size != original_size) {
Mark Young6ef95f42017-02-17 09:02:23 -0700344 strncat(cmd_line_msg, " | ", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700345 cmd_line_size -= 3;
346 }
Mark Young6ef95f42017-02-17 09:02:23 -0700347 strncat(cmd_line_msg, "WARNING", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700348 cmd_line_size -= 7;
349 }
350 if ((msg_type & LOADER_PERF_BIT) != 0) {
Mark Young5de3af72017-04-25 08:08:29 -0600351 if (cmd_line_size != original_size) {
Mark Young6ef95f42017-02-17 09:02:23 -0700352 strncat(cmd_line_msg, " | ", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700353 cmd_line_size -= 3;
354 }
Mark Young6ef95f42017-02-17 09:02:23 -0700355 strncat(cmd_line_msg, "PERF", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700356 cmd_line_size -= 4;
357 }
358 if ((msg_type & LOADER_ERROR_BIT) != 0) {
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 -= 3;
362 }
Mark Young6ef95f42017-02-17 09:02:23 -0700363 strncat(cmd_line_msg, "ERROR", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700364 cmd_line_size -= 5;
365 }
366 if ((msg_type & LOADER_DEBUG_BIT) != 0) {
Mark Young5de3af72017-04-25 08:08:29 -0600367 if (cmd_line_size != original_size) {
Mark Young6ef95f42017-02-17 09:02:23 -0700368 strncat(cmd_line_msg, " | ", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700369 cmd_line_size -= 3;
370 }
Mark Young6ef95f42017-02-17 09:02:23 -0700371 strncat(cmd_line_msg, "DEBUG", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700372 cmd_line_size -= 5;
373 }
Mark Young5de3af72017-04-25 08:08:29 -0600374 if (cmd_line_size != original_size) {
Mark Young6ef95f42017-02-17 09:02:23 -0700375 strncat(cmd_line_msg, ": ", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700376 cmd_line_size -= 2;
377 }
Mark Young5de3af72017-04-25 08:08:29 -0600378
379 if (0 < cmd_line_size) {
380 // If the message is too long, trim it down
381 if (strlen(msg) > cmd_line_size) {
382 msg[cmd_line_size - 1] = '\0';
383 }
384 strncat(cmd_line_msg, msg, cmd_line_size);
385 } else {
386 // Shouldn't get here, but check to make sure if we've already overrun
387 // the string boundary
388 assert(false);
389 }
Mark Young2c84c0c2017-01-13 10:27:03 -0700390
Ian Elliott4470a302015-02-17 10:33:47 -0700391#if defined(WIN32)
Mark Young2c84c0c2017-01-13 10:27:03 -0700392 OutputDebugString(cmd_line_msg);
mschottb9cdb782015-07-22 14:11:29 +0200393 OutputDebugString("\n");
Jon Ashburnffad94d2015-06-30 14:46:22 -0700394#endif
Mark Young5de3af72017-04-25 08:08:29 -0600395
Mark Young2c84c0c2017-01-13 10:27:03 -0700396 fputs(cmd_line_msg, stderr);
Jon Ashburnffad94d2015-06-30 14:46:22 -0700397 fputc('\n', stderr);
398}
399
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700400VKAPI_ATTR VkResult VKAPI_CALL vkSetInstanceDispatch(VkInstance instance, void *object) {
Jon Ashburnc3c58772016-03-29 11:16:01 -0600401 struct loader_instance *inst = loader_get_instance(instance);
402 if (!inst) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700403 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
404 "vkSetInstanceDispatch: Can not retrieve Instance "
405 "dispatch table.");
Jon Ashburnc3c58772016-03-29 11:16:01 -0600406 return VK_ERROR_INITIALIZATION_FAILED;
407 }
408 loader_set_dispatch(object, inst->disp);
409 return VK_SUCCESS;
410}
411
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700412VKAPI_ATTR VkResult VKAPI_CALL vkSetDeviceDispatch(VkDevice device, void *object) {
Jon Ashburned8f2312016-03-31 10:52:22 -0600413 struct loader_device *dev;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700414 struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, NULL);
Jon Ashburned8f2312016-03-31 10:52:22 -0600415
Mark Young0153e0b2016-11-03 14:27:13 -0600416 if (NULL == icd_term) {
Jon Ashburned8f2312016-03-31 10:52:22 -0600417 return VK_ERROR_INITIALIZATION_FAILED;
418 }
419 loader_set_dispatch(object, &dev->loader_dispatch);
420 return VK_SUCCESS;
421}
422
Lenny Komowf7c09382017-08-31 16:35:08 -0600423#if defined(_WIN32)
Norbert Garnys7dc9a592018-02-13 16:32:03 +0100424
425// Append the JSON path data to the list and allocate/grow the list if it's not large enough.
426// Function returns true if filename was appended to reg_data list.
427// Caller should free reg_data.
428static bool loaderAddJsonEntry(const struct loader_instance *inst,
429 char **reg_data, // list of JSON files
430 PDWORD total_size, // size of reg_data
431 LPCTSTR key_name, // key name - used for debug prints - i.e. VulkanDriverName
432 DWORD key_type, // key data type
433 LPSTR json_path, // JSON string to add to the list reg_data
434 DWORD json_size, // size in bytes of json_path
435 VkResult *result) {
436 if (NULL == *reg_data) {
437 *reg_data = loader_instance_heap_alloc(inst, *total_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
438 if (NULL == *reg_data) {
439 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
440 "loaderAddJsonEntry: Failed to allocate space for registry data for key %s", json_path);
441 *result = VK_ERROR_OUT_OF_HOST_MEMORY;
442 return false;
443 }
444 *reg_data[0] = '\0';
445 } else if (strlen(*reg_data) + json_size + 1 > *total_size) {
446 void *new_ptr =
447 loader_instance_heap_realloc(inst, *reg_data, *total_size, *total_size * 2, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
448 if (NULL == new_ptr) {
449 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
450 "loaderAddJsonEntry: Failed to reallocate space for registry value of size %d for key %s", *total_size * 2,
451 json_path);
452 *result = VK_ERROR_OUT_OF_HOST_MEMORY;
453 return false;
454 }
455 *reg_data = new_ptr;
456 *total_size *= 2;
457 }
458
459 for (char *curr_filename = json_path; curr_filename[0] != '\0'; curr_filename += strlen(curr_filename) + 1) {
460 if (strlen(*reg_data) == 0) {
461 (void)snprintf(*reg_data, json_size + 1, "%s", curr_filename);
462 } else {
463 (void)snprintf(*reg_data + strlen(*reg_data), json_size + 2, "%c%s", PATH_SEPARATOR, curr_filename);
464 }
465 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "%s: Located json file \"%s\" from PnP registry: %s", __FUNCTION__,
466 curr_filename, key_name);
467
468 if (key_type == REG_SZ) {
469 break;
470 }
471 }
472 return true;
473}
474
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200475// Find the list of registry files (names VulkanDriverName/VulkanDriverNameWow) in hkr.
476//
477// This function looks for filename in given device handle, filename is then added to return list
478// function return true if filename was appended to reg_data list
479// If error occures result is updated with failure reason
Lenny Komowf7c09382017-08-31 16:35:08 -0600480bool 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 +0200481{
482 HKEY hkrKey = INVALID_HANDLE_VALUE;
Lenny Komowf7c09382017-08-31 16:35:08 -0600483 DWORD requiredSize, data_type;
484 char *manifest_path = NULL;
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200485 bool found = false;
486
487 if (NULL == total_size || NULL == reg_data) {
488 *result = VK_ERROR_INITIALIZATION_FAILED;
489 return false;
490 }
491
Lenny Komowf7c09382017-08-31 16:35:08 -0600492 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 +0200493 if (status != CR_SUCCESS) {
494 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komowf7c09382017-08-31 16:35:08 -0600495 "loaderGetDeviceRegistryEntry: Failed to open registry key for DeviceID(%d)", dev_id);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200496 *result = VK_ERROR_INITIALIZATION_FAILED;
497 return false;
498 }
499
500 // query value
501 LSTATUS ret = RegQueryValueEx(
502 hkrKey,
Lenny Komowf7c09382017-08-31 16:35:08 -0600503 value_name,
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200504 NULL,
505 NULL,
506 NULL,
507 &requiredSize);
508
509 if (ret != ERROR_SUCCESS) {
Lenny Komowf7c09382017-08-31 16:35:08 -0600510 if (ret == ERROR_FILE_NOT_FOUND) {
511 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
512 "loaderGetDeviceRegistryEntry: Device ID(%d) Does not contain a value for \"%s\"", dev_id, value_name);
513 } else {
514 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
515 "loaderGetDeviceRegistryEntry: DeviceID(%d) Failed to obtain %s size", dev_id, value_name);
516 }
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200517 goto out;
518 }
519
Lenny Komowf7c09382017-08-31 16:35:08 -0600520 manifest_path = loader_instance_heap_alloc(inst, requiredSize, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
521 if (manifest_path == NULL) {
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200522 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
523 "loaderGetDeviceRegistryEntry: Failed to allocate space for DriverName.");
524 *result = VK_ERROR_OUT_OF_HOST_MEMORY;
525 goto out;
526 }
527
528 ret = RegQueryValueEx(
529 hkrKey,
Lenny Komowf7c09382017-08-31 16:35:08 -0600530 value_name,
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200531 NULL,
Lenny Komowf7c09382017-08-31 16:35:08 -0600532 &data_type,
Jamie Madilla11ae0b2017-11-08 14:48:32 -0500533 (BYTE *)manifest_path,
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200534 &requiredSize
535 );
536
537 if (ret != ERROR_SUCCESS) {
538 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Lenny Komowf7c09382017-08-31 16:35:08 -0600539 "loaderGetDeviceRegistryEntry: DeviceID(%d) Failed to obtain %s", value_name);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200540
541 *result = VK_ERROR_INITIALIZATION_FAILED;
542 goto out;
543 }
544
Lenny Komowf7c09382017-08-31 16:35:08 -0600545 if (data_type != REG_SZ && data_type != REG_MULTI_SZ) {
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200546 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Lenny Komowf7c09382017-08-31 16:35:08 -0600547 "loaderGetDeviceRegistryEntry: Invalid %s data type. Expected REG_SZ or REG_MULTI_SZ.", value_name);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200548 *result = VK_ERROR_INITIALIZATION_FAILED;
549 goto out;
550 }
551
Norbert Garnys7dc9a592018-02-13 16:32:03 +0100552 found = loaderAddJsonEntry(inst, reg_data, total_size, value_name, data_type, manifest_path, requiredSize, result);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200553
554out:
Lenny Komowf7c09382017-08-31 16:35:08 -0600555 if (manifest_path != NULL) {
556 loader_instance_heap_free(inst, manifest_path);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200557 }
558 RegCloseKey(hkrKey);
559 return found;
560}
561
562// Find the list of registry files (names VulkanDriverName/VulkanDriverNameWow) in hkr .
563//
564// This function looks for display devices and childish software components
565// for a list of files which are added to a returned list (function return
566// value).
567// Function return is a string with a ';' separated list of filenames.
568// Function return is NULL if no valid name/value pairs are found in the key,
569// or the key is not found.
570//
571// *reg_data contains a string list of filenames as pointer.
572// When done using the returned string list, the caller should free the pointer.
Lenny Komowf7c09382017-08-31 16:35:08 -0600573VkResult loaderGetDeviceRegistryFiles(const struct loader_instance *inst, char **reg_data, PDWORD reg_data_size, LPCTSTR value_name) {
Slawomir Cyganad34df22018-01-25 13:51:17 +0100574 static const wchar_t *softwareComponentGUID = L"{5c4c3332-344d-483c-8739-259e934c9cc8}";
575 static const wchar_t *displayGUID = L"{4d36e968-e325-11ce-bfc1-08002be10318}";
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200576 const ULONG flags = CM_GETIDLIST_FILTER_CLASS | CM_GETIDLIST_FILTER_PRESENT;
Slawomir Cyganad34df22018-01-25 13:51:17 +0100577
578 wchar_t childGuid[MAX_GUID_STRING_LEN + 2]; // +2 for brackets {}
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200579 ULONG childGuidSize = sizeof(childGuid);
580
581 DEVINST devID = 0, childID = 0;
Slawomir Cygana589d422018-01-25 13:48:54 +0100582 wchar_t *pDeviceNames = NULL;
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200583 ULONG deviceNamesSize = 0;
584 VkResult result = VK_SUCCESS;
585 bool found = false;
586
587 if (NULL == reg_data) {
588 result = VK_ERROR_INITIALIZATION_FAILED;
589 return result;
590 }
591
592 // if after obtaining the DeviceNameSize, new device is added start over
593 do {
Slawomir Cygana589d422018-01-25 13:48:54 +0100594 CM_Get_Device_ID_List_SizeW(&deviceNamesSize, displayGUID, flags);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200595
596 if (pDeviceNames != NULL) {
597 loader_instance_heap_free(inst, pDeviceNames);
598 }
599
Slawomir Cygana589d422018-01-25 13:48:54 +0100600 pDeviceNames = loader_instance_heap_alloc(inst, deviceNamesSize * sizeof(wchar_t), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200601 if (pDeviceNames == NULL) {
602 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
603 "loaderGetDeviceRegistryFiles: Failed to allocate space for display device names.");
604 result = VK_ERROR_OUT_OF_HOST_MEMORY;
Slawomir Cygan018bfd52017-08-25 10:54:03 +0200605 return result;
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200606 }
Slawomir Cygana589d422018-01-25 13:48:54 +0100607 } while (CM_Get_Device_ID_ListW(displayGUID, pDeviceNames, deviceNamesSize, flags) == CR_BUFFER_SMALL);
608
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200609 if (pDeviceNames) {
Slawomir Cygana589d422018-01-25 13:48:54 +0100610 for (wchar_t *deviceName = pDeviceNames; *deviceName; deviceName += wcslen(deviceName) + 1) {
611 CONFIGRET status = CM_Locate_DevNodeW(&devID, deviceName, CM_LOCATE_DEVNODE_NORMAL);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200612 if (CR_SUCCESS != status) {
Norbert Garnys7dc9a592018-02-13 16:32:03 +0100613 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, "loaderGetDeviceRegistryFiles: failed to open DevNode %s",
614 deviceName);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200615 continue;
616 }
617 ULONG ulStatus, ulProblem;
618 status = CM_Get_DevNode_Status(&ulStatus, &ulProblem, devID, 0);
619
620 if (CR_SUCCESS != status)
621 {
Norbert Garnys7dc9a592018-02-13 16:32:03 +0100622 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, "loaderGetDeviceRegistryFiles: failed to probe device status %s",
623 deviceName);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200624 continue;
625 }
626 if ((ulStatus & DN_HAS_PROBLEM) && (ulProblem == CM_PROB_NEED_RESTART || ulProblem == DN_NEED_RESTART))
627 {
Lenny Komowe17a12a2017-08-10 09:25:49 -0600628 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Norbert Garnys7dc9a592018-02-13 16:32:03 +0100629 "loaderGetDeviceRegistryFiles: device %s is pending reboot, skipping ...", deviceName);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200630 continue;
631 }
632
Norbert Garnys7dc9a592018-02-13 16:32:03 +0100633 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "loaderGetDeviceRegistryFiles: opening device %s", deviceName);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200634
Lenny Komowf7c09382017-08-31 16:35:08 -0600635 if (loaderGetDeviceRegistryEntry(inst, reg_data, reg_data_size, devID, value_name, &result)) {
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200636 found = true;
637 continue;
638 }
Igor Ostrowski21532732017-10-06 18:26:23 +0200639 else if (result == VK_ERROR_OUT_OF_HOST_MEMORY) {
640 break;
641 }
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200642
643 status = CM_Get_Child(&childID, devID, 0);
644 if (status != CR_SUCCESS) {
Lenny Komowe17a12a2017-08-10 09:25:49 -0600645 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Norbert Garnys7dc9a592018-02-13 16:32:03 +0100646 "loaderGetDeviceRegistryFiles: unable to open child-device error:%d", status);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200647 continue;
648 }
649
650 do {
Slawomir Cygana589d422018-01-25 13:48:54 +0100651 wchar_t buffer[MAX_DEVICE_ID_LEN];
652 CM_Get_Device_IDW(childID, buffer, MAX_DEVICE_ID_LEN, 0);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200653
Lenny Komowe17a12a2017-08-10 09:25:49 -0600654 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Norbert Garnys7dc9a592018-02-13 16:32:03 +0100655 "loaderGetDeviceRegistryFiles: Opening child device %d - %s", childID, buffer);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200656
Slawomir Cygana589d422018-01-25 13:48:54 +0100657 status = CM_Get_DevNode_Registry_PropertyW(childID, CM_DRP_CLASSGUID, NULL, &childGuid, &childGuidSize, 0);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200658 if (status != CR_SUCCESS) {
659 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Norbert Garnys7dc9a592018-02-13 16:32:03 +0100660 "loaderGetDeviceRegistryFiles: unable to obtain GUID for:%d error:%d", childID, status);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200661
662 result = VK_ERROR_INITIALIZATION_FAILED;
663 continue;
664 }
665
Slawomir Cygana589d422018-01-25 13:48:54 +0100666 if (wcscmp(childGuid, softwareComponentGUID) != 0) {
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200667 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
Norbert Garnys7dc9a592018-02-13 16:32:03 +0100668 "loaderGetDeviceRegistryFiles: GUID for %d is not SoftwareComponent skipping", childID);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200669 continue;
670 }
671
Lenny Komowf7c09382017-08-31 16:35:08 -0600672 if (loaderGetDeviceRegistryEntry(inst, reg_data, reg_data_size, childID, value_name, &result)) {
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200673 found = true;
674 break; // check next-display-device
675 }
676
677 } while (CM_Get_Sibling(&childID, childID, 0) == CR_SUCCESS);
678 }
679
680 loader_instance_heap_free(inst, pDeviceNames);
681 }
682
683 if (!found && result != VK_ERROR_OUT_OF_HOST_MEMORY) {
684 result = VK_ERROR_INITIALIZATION_FAILED;
685 }
686
687 return result;
688}
689
Tony Barbourea968902015-07-29 14:26:21 -0600690static char *loader_get_next_path(char *path);
Mark Young2c84c0c2017-01-13 10:27:03 -0700691
692// Find the list of registry files (names within a key) in key "location".
693//
694// This function looks in the registry (hive = DEFAULT_VK_REGISTRY_HIVE) key as
695// given in "location"
696// for a list or name/values which are added to a returned list (function return
697// value).
698// The DWORD values within the key must be 0 or they are skipped.
699// Function return is a string with a ';' separated list of filenames.
700// Function return is NULL if no valid name/value pairs are found in the key,
701// or the key is not found.
702//
703// *reg_data contains a string list of filenames as pointer.
704// When done using the returned string list, the caller should free the pointer.
Slawomir Cygan8f9f2552017-08-09 11:36:52 +0200705VkResult 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 -0700706 LONG rtn_value;
Lenny Komowda849dc2017-03-01 17:22:29 -0700707 HKEY hive = DEFAULT_VK_REGISTRY_HIVE, key;
Piers Daniell524ec732015-11-05 16:58:26 -0700708 DWORD access_flags;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700709 char name[2048];
Tony Barbourea968902015-07-29 14:26:21 -0600710 char *loc = location;
711 char *next;
Lenny Komowda849dc2017-03-01 17:22:29 -0700712 DWORD idx;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700713 DWORD name_size = sizeof(name);
714 DWORD value;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700715 DWORD value_size = sizeof(value);
Mark Young2c84c0c2017-01-13 10:27:03 -0700716 VkResult result = VK_SUCCESS;
717 bool found = false;
718
719 if (NULL == reg_data) {
720 result = VK_ERROR_INITIALIZATION_FAILED;
721 goto out;
722 }
Tony Barbourea968902015-07-29 14:26:21 -0600723
Jon Ashburn23d36b12016-02-02 17:47:28 -0700724 while (*loc) {
Tony Barbourea968902015-07-29 14:26:21 -0600725 next = loader_get_next_path(loc);
Piers Daniell524ec732015-11-05 16:58:26 -0700726 access_flags = KEY_QUERY_VALUE;
Tony Barbourea968902015-07-29 14:26:21 -0600727 rtn_value = RegOpenKeyEx(hive, loc, 0, access_flags, &key);
Lenny Komowda849dc2017-03-01 17:22:29 -0700728 if (ERROR_SUCCESS == rtn_value) {
729 idx = 0;
730 while ((rtn_value = RegEnumValue(key, idx++, name, &name_size, NULL, NULL, (LPBYTE)&value, &value_size)) ==
731 ERROR_SUCCESS) {
732 if (value_size == sizeof(value) && value == 0) {
733 if (NULL == *reg_data) {
Slawomir Cygan8f9f2552017-08-09 11:36:52 +0200734 *reg_data = loader_instance_heap_alloc(inst, *reg_data_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Lenny Komowda849dc2017-03-01 17:22:29 -0700735 if (NULL == *reg_data) {
736 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngbb3a29c2017-05-19 12:29:43 -0600737 "loaderGetRegistryFiles: Failed to allocate space for registry data for key %s", name);
Slawomir Cygane5830322018-01-16 17:17:07 +0100738 RegCloseKey(key);
Lenny Komowda849dc2017-03-01 17:22:29 -0700739 result = VK_ERROR_OUT_OF_HOST_MEMORY;
740 goto out;
741 }
742 *reg_data[0] = '\0';
Slawomir Cygan8f9f2552017-08-09 11:36:52 +0200743 } else if (strlen(*reg_data) + name_size + 1 > *reg_data_size) {
744 void *new_ptr = loader_instance_heap_realloc(inst, *reg_data, *reg_data_size, *reg_data_size * 2,
Mark Youngbb3a29c2017-05-19 12:29:43 -0600745 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
746 if (NULL == new_ptr) {
747 loader_log(
748 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
749 "loaderGetRegistryFiles: Failed to reallocate space for registry value of size %d for key %s",
Slawomir Cygan8f9f2552017-08-09 11:36:52 +0200750 *reg_data_size * 2, name);
Slawomir Cygane5830322018-01-16 17:17:07 +0100751 RegCloseKey(key);
Lenny Komowda849dc2017-03-01 17:22:29 -0700752 result = VK_ERROR_OUT_OF_HOST_MEMORY;
753 goto out;
754 }
Mark Youngbb3a29c2017-05-19 12:29:43 -0600755 *reg_data = new_ptr;
Slawomir Cygan8f9f2552017-08-09 11:36:52 +0200756 *reg_data_size *= 2;
Lenny Komowda849dc2017-03-01 17:22:29 -0700757 }
Mark Youngf2079b92017-05-02 10:49:46 -0600758 loader_log(
759 inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Located json file \"%s\" from registry \"%s\\%s\"", name,
760 hive == DEFAULT_VK_REGISTRY_HIVE ? DEFAULT_VK_REGISTRY_HIVE_STR : SECONDARY_VK_REGISTRY_HIVE_STR, location);
Lenny Komowda849dc2017-03-01 17:22:29 -0700761 if (strlen(*reg_data) == 0) {
Norbert Garnys7dc9a592018-02-13 16:32:03 +0100762 // The list is emtpy. Add the first entry.
Lenny Komowda849dc2017-03-01 17:22:29 -0700763 (void)snprintf(*reg_data, name_size + 1, "%s", name);
Norbert Garnys7dc9a592018-02-13 16:32:03 +0100764 found = true;
Lenny Komowda849dc2017-03-01 17:22:29 -0700765 } else {
Norbert Garnys7dc9a592018-02-13 16:32:03 +0100766 // At this point the reg_data variable contains other JSON paths, likely from the PNP/device section
767 // of the registry that we want to have precendence over this non-device specific section of the registry.
768 // To make sure we avoid enumerating old JSON files/drivers that might be present in the non-device specific
769 // area of the registry when a newer device specific JSON file is present, do a check before adding.
770 // Find the file name, without path, of the JSON file found in the non-device specific registry location.
771 // If the same JSON file name is already found in the list, don't add it again.
772 bool foundDuplicate = false;
773 char *pLastSlashName = strrchr(name, '\\');
774 if (pLastSlashName != NULL) {
775 char *foundMatch = strstr(*reg_data, pLastSlashName + 1);
776 if (foundMatch != NULL) {
777 foundDuplicate = true;
778 }
779 }
780
781 if (foundDuplicate == false) {
782 // Add the new entry to the list.
783 (void)snprintf(*reg_data + strlen(*reg_data), name_size + 2, "%c%s", PATH_SEPARATOR, name);
784 found = true;
785 } else {
786 loader_log(
787 inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
788 "Skipping adding of json file \"%s\" from registry \"%s\\%s\" to the list due to duplication", name,
789 hive == DEFAULT_VK_REGISTRY_HIVE ? DEFAULT_VK_REGISTRY_HIVE_STR : SECONDARY_VK_REGISTRY_HIVE_STR,
790 location);
791 }
Lenny Komowda849dc2017-03-01 17:22:29 -0700792 }
Lenny Komowda849dc2017-03-01 17:22:29 -0700793 }
794 name_size = 2048;
795 }
Slawomir Cygane5830322018-01-16 17:17:07 +0100796 RegCloseKey(key);
Jon Ashburnffad94d2015-06-30 14:46:22 -0700797 }
Tony Barbourea968902015-07-29 14:26:21 -0600798
Lenny Komowda849dc2017-03-01 17:22:29 -0700799 // Advance the location - if the next location is in the secondary hive, then reset the locations and advance the hive
800 if (use_secondary_hive && (hive == DEFAULT_VK_REGISTRY_HIVE) && (*next == '\0')) {
801 loc = location;
802 hive = SECONDARY_VK_REGISTRY_HIVE;
803 } else {
804 loc = next;
Tony Barbourea968902015-07-29 14:26:21 -0600805 }
Jon Ashburnffad94d2015-06-30 14:46:22 -0700806 }
Tony Barbourea968902015-07-29 14:26:21 -0600807
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200808 if (!found && result != VK_ERROR_OUT_OF_HOST_MEMORY) {
Mark Young2c84c0c2017-01-13 10:27:03 -0700809 result = VK_ERROR_INITIALIZATION_FAILED;
810 }
811
812out:
813
814 return result;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700815}
816
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700817#endif // WIN32
Ian Elliott4470a302015-02-17 10:33:47 -0700818
Mark Young0f183a82017-02-28 09:58:04 -0700819// Combine path elements, separating each element with the platform-specific
820// directory separator, and save the combined string to a destination buffer,
Mark Youngdee312c2017-03-08 13:38:35 -0700821// not exceeding the given length. Path elements are given as variable args,
Mark Young0f183a82017-02-28 09:58:04 -0700822// with a NULL element terminating the list.
823//
824// \returns the total length of the combined string, not including an ASCII
825// NUL termination character. This length may exceed the available storage:
826// in this case, the written string will be truncated to avoid a buffer
827// overrun, and the return value will greater than or equal to the storage
828// size. A NULL argument may be provided as the destination buffer in order
829// to determine the required string length without actually writing a string.
Jon Ashburn23d36b12016-02-02 17:47:28 -0700830static size_t loader_platform_combine_path(char *dest, size_t len, ...) {
Courtney Goeltzenleuchter0ef13a02015-12-16 16:19:46 -0700831 size_t required_len = 0;
Daniel Dadap00b4aba2015-09-30 11:50:51 -0500832 va_list ap;
833 const char *component;
834
835 va_start(ap, len);
836
Jon Ashburn23d36b12016-02-02 17:47:28 -0700837 while ((component = va_arg(ap, const char *))) {
Daniel Dadap00b4aba2015-09-30 11:50:51 -0500838 if (required_len > 0) {
839 // This path element is not the first non-empty element; prepend
840 // a directory separator if space allows
841 if (dest && required_len + 1 < len) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700842 (void)snprintf(dest + required_len, len - required_len, "%c", DIRECTORY_SYMBOL);
Daniel Dadap00b4aba2015-09-30 11:50:51 -0500843 }
844 required_len++;
845 }
846
847 if (dest && required_len < len) {
848 strncpy(dest + required_len, component, len - required_len);
849 }
850 required_len += strlen(component);
851 }
852
853 va_end(ap);
854
855 // strncpy(3) won't add a NUL terminating byte in the event of truncation.
856 if (dest && required_len >= len) {
857 dest[len - 1] = '\0';
858 }
859
860 return required_len;
861}
862
Mark Young0f183a82017-02-28 09:58:04 -0700863// Given string of three part form "maj.min.pat" convert to a vulkan version number.
Mark Young60861ac2016-09-02 11:39:26 -0600864static uint32_t loader_make_version(char *vers_str) {
Jon Ashburn23d36b12016-02-02 17:47:28 -0700865 uint32_t vers = 0, major = 0, minor = 0, patch = 0;
Mark Young60861ac2016-09-02 11:39:26 -0600866 char *vers_tok;
Jon Ashburnc7237a72015-08-03 09:08:46 -0600867
Mark Young60861ac2016-09-02 11:39:26 -0600868 if (!vers_str) {
Jon Ashburnc7237a72015-08-03 09:08:46 -0600869 return vers;
Jon Ashburnc7237a72015-08-03 09:08:46 -0600870 }
Mark Young60861ac2016-09-02 11:39:26 -0600871
872 vers_tok = strtok(vers_str, ".\"\n\r");
873 if (NULL != vers_tok) {
874 major = (uint16_t)atoi(vers_tok);
875 vers_tok = strtok(NULL, ".\"\n\r");
876 if (NULL != vers_tok) {
877 minor = (uint16_t)atoi(vers_tok);
878 vers_tok = strtok(NULL, ".\"\n\r");
879 if (NULL != vers_tok) {
880 patch = (uint16_t)atoi(vers_tok);
881 }
882 }
883 }
Jon Ashburnc7237a72015-08-03 09:08:46 -0600884
885 return VK_MAKE_VERSION(major, minor, patch);
Jon Ashburnc7237a72015-08-03 09:08:46 -0600886}
887
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700888bool compare_vk_extension_properties(const VkExtensionProperties *op1, const VkExtensionProperties *op2) {
Chia-I Wu3432a0c2015-10-27 18:04:07 +0800889 return strcmp(op1->extensionName, op2->extensionName) == 0 ? true : false;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600890}
891
Mark Young0f183a82017-02-28 09:58:04 -0700892// Search the given ext_array for an extension matching the given vk_ext_prop
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700893bool has_vk_extension_property_array(const VkExtensionProperties *vk_ext_prop, const uint32_t count,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700894 const VkExtensionProperties *ext_array) {
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600895 for (uint32_t i = 0; i < count; i++) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700896 if (compare_vk_extension_properties(vk_ext_prop, &ext_array[i])) return true;
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600897 }
898 return false;
899}
900
Mark Young0f183a82017-02-28 09:58:04 -0700901// Search the given ext_list for an extension matching the given vk_ext_prop
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700902bool has_vk_extension_property(const VkExtensionProperties *vk_ext_prop, const struct loader_extension_list *ext_list) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600903 for (uint32_t i = 0; i < ext_list->count; i++) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700904 if (compare_vk_extension_properties(&ext_list->list[i], vk_ext_prop)) return true;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600905 }
906 return false;
907}
908
Mark Young0f183a82017-02-28 09:58:04 -0700909// Search the given ext_list for a device extension matching the given ext_prop
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700910bool has_vk_dev_ext_property(const VkExtensionProperties *ext_prop, const struct loader_device_extension_list *ext_list) {
Jon Ashburnb8726962016-04-08 15:03:35 -0600911 for (uint32_t i = 0; i < ext_list->count; i++) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700912 if (compare_vk_extension_properties(&ext_list->list[i].props, ext_prop)) return true;
Jon Ashburnb8726962016-04-08 15:03:35 -0600913 }
914 return false;
915}
916
Mark Young0f183a82017-02-28 09:58:04 -0700917// Search the given layer list for a layer matching the given layer name
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700918static 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 -0600919 for (uint32_t i = 0; i < layer_list->count; i++) {
920 const VkLayerProperties *item = &layer_list->list[i].info;
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700921 if (strcmp(name, item->layerName) == 0) return &layer_list->list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600922 }
923 return NULL;
924}
925
Mark Young0f183a82017-02-28 09:58:04 -0700926// Get the next unused layer property in the list. Init the property to zero.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700927static struct loader_layer_properties *loader_get_next_layer_property(const struct loader_instance *inst,
928 struct loader_layer_list *layer_list) {
Jon Ashburne13ecc92015-08-03 17:19:30 -0600929 if (layer_list->capacity == 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700930 layer_list->list =
931 loader_instance_heap_alloc(inst, sizeof(struct loader_layer_properties) * 64, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburne13ecc92015-08-03 17:19:30 -0600932 if (layer_list->list == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700933 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
934 "loader_get_next_layer_property: Out of memory can "
935 "not add any layer properties to list");
Jon Ashburne13ecc92015-08-03 17:19:30 -0600936 return NULL;
937 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700938 memset(layer_list->list, 0, sizeof(struct loader_layer_properties) * 64);
Jon Ashburne13ecc92015-08-03 17:19:30 -0600939 layer_list->capacity = sizeof(struct loader_layer_properties) * 64;
940 }
941
Mark Young0f183a82017-02-28 09:58:04 -0700942 // Ensure enough room to add an entry
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700943 if ((layer_list->count + 1) * sizeof(struct loader_layer_properties) > layer_list->capacity) {
Mark Youngbb3a29c2017-05-19 12:29:43 -0600944 void *new_ptr = loader_instance_heap_realloc(inst, layer_list->list, layer_list->capacity, layer_list->capacity * 2,
945 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
946 if (NULL == new_ptr) {
947 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 -0600948 return NULL;
Jon Ashburne13ecc92015-08-03 17:19:30 -0600949 }
Mark Youngbb3a29c2017-05-19 12:29:43 -0600950 layer_list->list = new_ptr;
Jon Ashburne13ecc92015-08-03 17:19:30 -0600951 layer_list->capacity *= 2;
952 }
953
954 layer_list->count++;
955 return &(layer_list->list[layer_list->count - 1]);
956}
957
Mark Youngdee312c2017-03-08 13:38:35 -0700958// Remove all layer properties entries from the list
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700959void loader_delete_layer_properties(const struct loader_instance *inst, struct loader_layer_list *layer_list) {
Cort Stratton6974a132017-11-28 12:11:05 -0800960 uint32_t i, j, k;
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700961 struct loader_device_extension_list *dev_ext_list;
Cort Stratton6974a132017-11-28 12:11:05 -0800962 struct loader_dev_ext_props *ext_props;
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700963 if (!layer_list) return;
Jon Ashburnb82c1852015-08-11 14:49:54 -0600964
Jon Ashburne13ecc92015-08-03 17:19:30 -0600965 for (i = 0; i < layer_list->count; i++) {
Mark Youngf2079b92017-05-02 10:49:46 -0600966 if (NULL != layer_list->list[i].component_layer_names) {
967 loader_instance_heap_free(inst, layer_list->list[i].component_layer_names);
968 layer_list->list[i].component_layer_names = NULL;
969 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700970 loader_destroy_generic_list(inst, (struct loader_generic_list *)&layer_list->list[i].instance_extension_list);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700971 dev_ext_list = &layer_list->list[i].device_extension_list;
Cort Stratton6974a132017-11-28 12:11:05 -0800972 if (dev_ext_list->capacity > 0 && NULL != dev_ext_list->list) {
973 for (j = 0; j < dev_ext_list->count; j++) {
974 ext_props = &dev_ext_list->list[j];
975 if (ext_props->entrypoint_count > 0) {
976 for (k = 0; k < ext_props->entrypoint_count; k++) {
977 loader_instance_heap_free(inst, ext_props->entrypoints[k]);
978 }
979 loader_instance_heap_free(inst, ext_props->entrypoints);
980 }
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700981 }
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700982 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700983 loader_destroy_generic_list(inst, (struct loader_generic_list *)dev_ext_list);
Jon Ashburne13ecc92015-08-03 17:19:30 -0600984 }
985 layer_list->count = 0;
986
Jon Ashburnb82c1852015-08-11 14:49:54 -0600987 if (layer_list->capacity > 0) {
988 layer_list->capacity = 0;
Mark Young0ad83132016-06-30 13:02:42 -0600989 loader_instance_heap_free(inst, layer_list->list);
Jon Ashburnb82c1852015-08-11 14:49:54 -0600990 }
Jon Ashburne13ecc92015-08-03 17:19:30 -0600991}
992
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700993static VkResult loader_add_instance_extensions(const struct loader_instance *inst,
994 const PFN_vkEnumerateInstanceExtensionProperties fp_get_props, const char *lib_name,
995 struct loader_extension_list *ext_list) {
Courtney Goeltzenleuchter36eeb742015-12-21 16:41:47 -0700996 uint32_t i, count = 0;
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600997 VkExtensionProperties *ext_props;
Mark Young3a587792016-08-19 15:25:08 -0600998 VkResult res = VK_SUCCESS;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600999
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -06001000 if (!fp_get_props) {
Mark Young0f183a82017-02-28 09:58:04 -07001001 // No EnumerateInstanceExtensionProperties defined
Mark Young3a587792016-08-19 15:25:08 -06001002 goto out;
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -06001003 }
1004
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001005 res = fp_get_props(NULL, &count, NULL);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001006 if (res != VK_SUCCESS) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001007 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1008 "loader_add_instance_extensions: Error getting Instance "
1009 "extension count from %s",
Mark Youngb6399312017-01-10 14:22:15 -07001010 lib_name);
Mark Young3a587792016-08-19 15:25:08 -06001011 goto out;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001012 }
Jon Ashburn953bb3c2015-06-10 16:11:42 -06001013
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -06001014 if (count == 0) {
Mark Young0f183a82017-02-28 09:58:04 -07001015 // No ExtensionProperties to report
Mark Young3a587792016-08-19 15:25:08 -06001016 goto out;
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -06001017 }
1018
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001019 ext_props = loader_stack_alloc(count * sizeof(VkExtensionProperties));
Mark Young39389872017-01-19 21:10:49 -07001020 if (NULL == ext_props) {
1021 res = VK_ERROR_OUT_OF_HOST_MEMORY;
1022 goto out;
1023 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001024
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001025 res = fp_get_props(NULL, &count, ext_props);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001026 if (res != VK_SUCCESS) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001027 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1028 "loader_add_instance_extensions: Error getting Instance "
1029 "extensions from %s",
Mark Youngb6399312017-01-10 14:22:15 -07001030 lib_name);
Mark Young3a587792016-08-19 15:25:08 -06001031 goto out;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001032 }
Tony Barbour59a47322015-06-24 16:06:58 -06001033
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001034 for (i = 0; i < count; i++) {
Courtney Goeltzenleuchter53043732015-07-12 13:20:05 -06001035 char spec_version[64];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001036
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001037 bool ext_unsupported = wsi_unsupported_instance_extension(&ext_props[i]);
Jon Ashburn6fa520f2016-03-25 12:49:35 -06001038 if (!ext_unsupported) {
Mark Young02df1a82017-04-18 19:52:18 -06001039 (void)snprintf(spec_version, sizeof(spec_version), "%d.%d.%d", VK_VERSION_MAJOR(ext_props[i].specVersion),
1040 VK_VERSION_MINOR(ext_props[i].specVersion), VK_VERSION_PATCH(ext_props[i].specVersion));
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001041 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Instance Extension: %s (%s) version %s", ext_props[i].extensionName,
1042 lib_name, spec_version);
Mark Young6267ae62017-01-12 12:27:19 -07001043
Mark Young3a587792016-08-19 15:25:08 -06001044 res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
1045 if (res != VK_SUCCESS) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001046 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1047 "loader_add_instance_extensions: Failed to add %s "
1048 "to Instance extension list",
Mark Young3a587792016-08-19 15:25:08 -06001049 lib_name);
1050 goto out;
1051 }
Jon Ashburn6fa520f2016-03-25 12:49:35 -06001052 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001053 }
Mark Young6267ae62017-01-12 12:27:19 -07001054
Mark Young3a587792016-08-19 15:25:08 -06001055out:
1056 return res;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001057}
1058
Mark Young0f183a82017-02-28 09:58:04 -07001059// Initialize ext_list with the physical device extensions.
1060// The extension properties are passed as inputs in count and ext_props.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001061static VkResult loader_init_device_extensions(const struct loader_instance *inst, struct loader_physical_device_term *phys_dev_term,
1062 uint32_t count, VkExtensionProperties *ext_props,
1063 struct loader_extension_list *ext_list) {
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001064 VkResult res;
1065 uint32_t i;
1066
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001067 res = loader_init_generic_list(inst, (struct loader_generic_list *)ext_list, sizeof(VkExtensionProperties));
Mark Young3a587792016-08-19 15:25:08 -06001068 if (VK_SUCCESS != res) {
1069 return res;
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001070 }
1071
1072 for (i = 0; i < count; i++) {
1073 char spec_version[64];
Mark Young02df1a82017-04-18 19:52:18 -06001074 (void)snprintf(spec_version, sizeof(spec_version), "%d.%d.%d", VK_VERSION_MAJOR(ext_props[i].specVersion),
1075 VK_VERSION_MINOR(ext_props[i].specVersion), VK_VERSION_PATCH(ext_props[i].specVersion));
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001076 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Device Extension: %s (%s) version %s", ext_props[i].extensionName,
1077 phys_dev_term->this_icd_term->scanned_icd->lib_name, spec_version);
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001078 res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001079 if (res != VK_SUCCESS) return res;
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001080 }
1081
1082 return VK_SUCCESS;
1083}
1084
Jon Ashburn1530c342016-02-26 13:14:27 -07001085VkResult loader_add_device_extensions(const struct loader_instance *inst,
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001086 PFN_vkEnumerateDeviceExtensionProperties fpEnumerateDeviceExtensionProperties,
1087 VkPhysicalDevice physical_device, const char *lib_name,
Jon Ashburn1530c342016-02-26 13:14:27 -07001088 struct loader_extension_list *ext_list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001089 uint32_t i, count;
1090 VkResult res;
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001091 VkExtensionProperties *ext_props;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001092
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001093 res = fpEnumerateDeviceExtensionProperties(physical_device, NULL, &count, NULL);
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001094 if (res == VK_SUCCESS && count > 0) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001095 ext_props = loader_stack_alloc(count * sizeof(VkExtensionProperties));
Mark Young9a3ddd42016-10-21 16:25:47 -06001096 if (!ext_props) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001097 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1098 "loader_add_device_extensions: Failed to allocate space"
1099 " for device extension properties.");
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001100 return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young9a3ddd42016-10-21 16:25:47 -06001101 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001102 res = fpEnumerateDeviceExtensionProperties(physical_device, NULL, &count, ext_props);
Mark Young9a3ddd42016-10-21 16:25:47 -06001103 if (res != VK_SUCCESS) {
Jon Ashburn24cd4be2015-11-01 14:04:06 -07001104 return res;
Mark Young9a3ddd42016-10-21 16:25:47 -06001105 }
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001106 for (i = 0; i < count; i++) {
1107 char spec_version[64];
Mark Young02df1a82017-04-18 19:52:18 -06001108 (void)snprintf(spec_version, sizeof(spec_version), "%d.%d.%d", VK_VERSION_MAJOR(ext_props[i].specVersion),
1109 VK_VERSION_MINOR(ext_props[i].specVersion), VK_VERSION_PATCH(ext_props[i].specVersion));
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001110 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Device Extension: %s (%s) version %s", ext_props[i].extensionName,
1111 lib_name, spec_version);
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001112 res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
Mark Youngb6399312017-01-10 14:22:15 -07001113 if (res != VK_SUCCESS) {
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001114 return res;
Mark Youngb6399312017-01-10 14:22:15 -07001115 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001116 }
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001117 } else {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001118 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1119 "loader_add_device_extensions: Error getting physical "
1120 "device extension info count from library %s",
Jon Ashburn23d36b12016-02-02 17:47:28 -07001121 lib_name);
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001122 return res;
1123 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001124
Jon Ashburn24cd4be2015-11-01 14:04:06 -07001125 return VK_SUCCESS;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001126}
1127
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001128VkResult 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 -06001129 size_t capacity = 32 * element_size;
1130 list_info->count = 0;
1131 list_info->capacity = 0;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001132 list_info->list = loader_instance_heap_alloc(inst, capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburn6e6a2162015-12-10 08:51:10 -07001133 if (list_info->list == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001134 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1135 "loader_init_generic_list: Failed to allocate space "
1136 "for generic list");
Mark Young3a587792016-08-19 15:25:08 -06001137 return VK_ERROR_OUT_OF_HOST_MEMORY;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001138 }
Mark Young84ba0482016-09-02 11:45:00 -06001139 memset(list_info->list, 0, capacity);
1140 list_info->capacity = capacity;
Mark Young3a587792016-08-19 15:25:08 -06001141 return VK_SUCCESS;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001142}
1143
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001144void loader_destroy_generic_list(const struct loader_instance *inst, struct loader_generic_list *list) {
Mark Young0ad83132016-06-30 13:02:42 -06001145 loader_instance_heap_free(inst, list->list);
Jon Ashburn6e6a2162015-12-10 08:51:10 -07001146 list->count = 0;
1147 list->capacity = 0;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001148}
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001149
Mark Young0f183a82017-02-28 09:58:04 -07001150// Append non-duplicate extension properties defined in props to the given ext_list.
1151// Return - Vk_SUCCESS on success
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001152VkResult loader_add_to_ext_list(const struct loader_instance *inst, struct loader_extension_list *ext_list,
1153 uint32_t prop_list_count, const VkExtensionProperties *props) {
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001154 uint32_t i;
1155 const VkExtensionProperties *cur_ext;
1156
1157 if (ext_list->list == NULL || ext_list->capacity == 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001158 VkResult res = loader_init_generic_list(inst, (struct loader_generic_list *)ext_list, sizeof(VkExtensionProperties));
Mark Young3a587792016-08-19 15:25:08 -06001159 if (VK_SUCCESS != res) {
1160 return res;
1161 }
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001162 }
1163
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001164 for (i = 0; i < prop_list_count; i++) {
1165 cur_ext = &props[i];
1166
1167 // look for duplicates
1168 if (has_vk_extension_property(cur_ext, ext_list)) {
1169 continue;
1170 }
1171
1172 // add to list at end
1173 // check for enough capacity
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001174 if (ext_list->count * sizeof(VkExtensionProperties) >= ext_list->capacity) {
Mark Youngbb3a29c2017-05-19 12:29:43 -06001175 void *new_ptr = loader_instance_heap_realloc(inst, ext_list->list, ext_list->capacity, ext_list->capacity * 2,
1176 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1177 if (new_ptr == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001178 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1179 "loader_add_to_ext_list: Failed to reallocate "
1180 "space for extension list");
Jon Ashburn24cd4be2015-11-01 14:04:06 -07001181 return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Youngb6399312017-01-10 14:22:15 -07001182 }
Mark Youngbb3a29c2017-05-19 12:29:43 -06001183 ext_list->list = new_ptr;
Jon Ashburn24cd4be2015-11-01 14:04:06 -07001184
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001185 // double capacity
1186 ext_list->capacity *= 2;
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001187 }
1188
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001189 memcpy(&ext_list->list[ext_list->count], cur_ext, sizeof(VkExtensionProperties));
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001190 ext_list->count++;
1191 }
Jon Ashburn24cd4be2015-11-01 14:04:06 -07001192 return VK_SUCCESS;
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001193}
1194
Mark Youngdee312c2017-03-08 13:38:35 -07001195// Append one extension property defined in props with entrypoints defined in entries to the given
Mark Young0f183a82017-02-28 09:58:04 -07001196// ext_list. Do not append if a duplicate.
1197// Return - Vk_SUCCESS on success
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001198VkResult loader_add_to_dev_ext_list(const struct loader_instance *inst, struct loader_device_extension_list *ext_list,
1199 const VkExtensionProperties *props, uint32_t entry_count, char **entrys) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001200 uint32_t idx;
1201 if (ext_list->list == NULL || ext_list->capacity == 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001202 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 -06001203 if (VK_SUCCESS != res) {
1204 return res;
1205 }
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001206 }
1207
Jon Ashburnb8726962016-04-08 15:03:35 -06001208 // look for duplicates
1209 if (has_vk_dev_ext_property(props, ext_list)) {
1210 return VK_SUCCESS;
1211 }
1212
Jon Ashburn23d36b12016-02-02 17:47:28 -07001213 idx = ext_list->count;
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001214 // add to list at end
1215 // check for enough capacity
Jon Ashburn23d36b12016-02-02 17:47:28 -07001216 if (idx * sizeof(struct loader_dev_ext_props) >= ext_list->capacity) {
Mark Youngbb3a29c2017-05-19 12:29:43 -06001217 void *new_ptr = loader_instance_heap_realloc(inst, ext_list->list, ext_list->capacity, ext_list->capacity * 2,
1218 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001219
Mark Youngbb3a29c2017-05-19 12:29:43 -06001220 if (NULL == new_ptr) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001221 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngbb3a29c2017-05-19 12:29:43 -06001222 "loader_add_to_dev_ext_list: Failed to reallocate space for device extension list");
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001223 return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Youngb6399312017-01-10 14:22:15 -07001224 }
Mark Youngbb3a29c2017-05-19 12:29:43 -06001225 ext_list->list = new_ptr;
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001226
1227 // double capacity
1228 ext_list->capacity *= 2;
1229 }
1230
Gabríel Arthúr Pétursson71510142017-06-03 01:38:49 +00001231 memcpy(&ext_list->list[idx].props, props, sizeof(*props));
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001232 ext_list->list[idx].entrypoint_count = entry_count;
Mark Young3f7a3b32017-06-26 14:03:08 -06001233 if (entry_count == 0) {
1234 ext_list->list[idx].entrypoints = NULL;
1235 } else {
1236 ext_list->list[idx].entrypoints =
1237 loader_instance_heap_alloc(inst, sizeof(char *) * entry_count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1238 if (ext_list->list[idx].entrypoints == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001239 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1240 "loader_add_to_dev_ext_list: Failed to allocate space "
Mark Young3f7a3b32017-06-26 14:03:08 -06001241 "for device extension entrypoint list in list %d",
1242 idx);
1243 ext_list->list[idx].entrypoint_count = 0;
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001244 return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young0ad83132016-06-30 13:02:42 -06001245 }
Mark Young3f7a3b32017-06-26 14:03:08 -06001246 for (uint32_t i = 0; i < entry_count; i++) {
1247 ext_list->list[idx].entrypoints[i] =
1248 loader_instance_heap_alloc(inst, strlen(entrys[i]) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1249 if (ext_list->list[idx].entrypoints[i] == NULL) {
1250 for (uint32_t j = 0; j < i; j++) {
1251 loader_instance_heap_free(inst, ext_list->list[idx].entrypoints[j]);
1252 }
1253 loader_instance_heap_free(inst, ext_list->list[idx].entrypoints);
1254 ext_list->list[idx].entrypoint_count = 0;
1255 ext_list->list[idx].entrypoints = NULL;
1256 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1257 "loader_add_to_dev_ext_list: Failed to allocate space "
1258 "for device extension entrypoint %d name",
1259 i);
1260 return VK_ERROR_OUT_OF_HOST_MEMORY;
1261 }
1262 strcpy(ext_list->list[idx].entrypoints[i], entrys[i]);
1263 }
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001264 }
1265 ext_list->count++;
1266
1267 return VK_SUCCESS;
1268}
1269
Mark Youngf2079b92017-05-02 10:49:46 -06001270// Prototype of loader_add_meta_layer function since we use it in the loader_add_implicit_layer, but can also
1271// call loader_add_implicit_layer from loader_add_meta_layer.
1272bool loader_add_meta_layer(const struct loader_instance *inst, const struct loader_layer_properties *prop,
Mark Young283fe1c2017-05-04 12:16:35 -06001273 struct loader_layer_list *target_list, struct loader_layer_list *expanded_target_list,
1274 const struct loader_layer_list *source_list);
1275
1276// Search the given layer list for a list matching the given VkLayerProperties
1277bool has_vk_layer_property(const VkLayerProperties *vk_layer_prop, const struct loader_layer_list *list) {
1278 for (uint32_t i = 0; i < list->count; i++) {
1279 if (strcmp(vk_layer_prop->layerName, list->list[i].info.layerName) == 0) return true;
1280 }
1281 return false;
1282}
1283
1284// Search the given layer list for a layer matching the given name
1285bool has_layer_name(const char *name, const struct loader_layer_list *list) {
1286 for (uint32_t i = 0; i < list->count; i++) {
1287 if (strcmp(name, list->list[i].info.layerName) == 0) return true;
1288 }
1289 return false;
1290}
Mark Youngf2079b92017-05-02 10:49:46 -06001291
Mark Young0f183a82017-02-28 09:58:04 -07001292// Search the given search_list for any layers in the props list. Add these to the
1293// output layer_list. Don't add duplicates to the output layer_list.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001294static 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 -06001295 struct loader_layer_list *expanded_output_list, uint32_t name_count,
1296 const char *const *names, const struct loader_layer_list *source_list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001297 struct loader_layer_properties *layer_prop;
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06001298 VkResult err = VK_SUCCESS;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001299
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001300 for (uint32_t i = 0; i < name_count; i++) {
Mark Young283fe1c2017-05-04 12:16:35 -06001301 const char *source_name = names[i];
1302 layer_prop = loader_get_layer_property(source_name, source_list);
Mark Youngf2079b92017-05-02 10:49:46 -06001303 if (NULL == layer_prop) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001304 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1305 "loader_add_layer_names_to_list: Unable to find layer"
1306 " %s",
Mark Young283fe1c2017-05-04 12:16:35 -06001307 source_name);
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06001308 err = VK_ERROR_LAYER_NOT_PRESENT;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001309 continue;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001310 }
1311
Mark Youngf2079b92017-05-02 10:49:46 -06001312 // If not a meta-layer, simply add it.
1313 if (0 == (layer_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
Mark Young283fe1c2017-05-04 12:16:35 -06001314 if (!has_vk_layer_property(&layer_prop->info, output_list)) {
1315 loader_add_to_layer_list(inst, output_list, 1, layer_prop);
1316 }
1317 if (!has_vk_layer_property(&layer_prop->info, expanded_output_list)) {
1318 loader_add_to_layer_list(inst, expanded_output_list, 1, layer_prop);
1319 }
Mark Youngf2079b92017-05-02 10:49:46 -06001320 } else {
Mark Young283fe1c2017-05-04 12:16:35 -06001321 if (!has_vk_layer_property(&layer_prop->info, output_list) ||
1322 !has_vk_layer_property(&layer_prop->info, expanded_output_list)) {
1323 loader_add_meta_layer(inst, layer_prop, output_list, expanded_output_list, source_list);
Mark Youngf2079b92017-05-02 10:49:46 -06001324 }
1325 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001326 }
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06001327
1328 return err;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001329}
1330
Mark Young0f183a82017-02-28 09:58:04 -07001331// Manage lists of VkLayerProperties
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001332static bool loader_init_layer_list(const struct loader_instance *inst, struct loader_layer_list *list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001333 list->capacity = 32 * sizeof(struct loader_layer_properties);
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001334 list->list = loader_instance_heap_alloc(inst, list->capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001335 if (list->list == NULL) {
1336 return false;
1337 }
1338 memset(list->list, 0, list->capacity);
1339 list->count = 0;
1340 return true;
1341}
1342
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001343void loader_destroy_layer_list(const struct loader_instance *inst, struct loader_device *device,
Jon Ashburn23d36b12016-02-02 17:47:28 -07001344 struct loader_layer_list *layer_list) {
Mark Young0ad83132016-06-30 13:02:42 -06001345 if (device) {
1346 loader_device_heap_free(device, layer_list->list);
1347 } else {
1348 loader_instance_heap_free(inst, layer_list->list);
1349 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001350 layer_list->count = 0;
1351 layer_list->capacity = 0;
1352}
1353
Mark Young0f183a82017-02-28 09:58:04 -07001354// Append non-duplicate layer properties defined in prop_list to the given layer_info list
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001355VkResult 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 -06001356 const struct loader_layer_properties *props) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001357 uint32_t i;
Lenny Komow397f9d42017-10-25 15:26:15 -06001358 uint16_t layer_api_major_version;
1359 uint16_t layer_api_minor_version;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001360 struct loader_layer_properties *layer;
1361
1362 if (list->list == NULL || list->capacity == 0) {
Jon Ashburne39a4f82015-08-28 13:38:21 -06001363 loader_init_layer_list(inst, list);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001364 }
1365
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001366 if (list->list == NULL) return VK_SUCCESS;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001367
1368 for (i = 0; i < prop_list_count; i++) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001369 layer = (struct loader_layer_properties *)&props[i];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001370
Mark Youngf2079b92017-05-02 10:49:46 -06001371 // Look for duplicates, and skip
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001372 if (has_vk_layer_property(&layer->info, list)) {
1373 continue;
1374 }
1375
Mark Youngf2079b92017-05-02 10:49:46 -06001376 // Check for enough capacity
1377 if (((list->count + 1) * sizeof(struct loader_layer_properties)) >= list->capacity) {
1378 size_t new_capacity = list->capacity * 2;
Mark Youngbb3a29c2017-05-19 12:29:43 -06001379 void *new_ptr =
Mark Youngf2079b92017-05-02 10:49:46 -06001380 loader_instance_heap_realloc(inst, list->list, list->capacity, new_capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Youngbb3a29c2017-05-19 12:29:43 -06001381 if (NULL == new_ptr) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001382 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngbb3a29c2017-05-19 12:29:43 -06001383 "loader_add_to_layer_list: Realloc failed for when attempting to add new layer");
Mark Young0ad83132016-06-30 13:02:42 -06001384 return VK_ERROR_OUT_OF_HOST_MEMORY;
1385 }
Mark Youngbb3a29c2017-05-19 12:29:43 -06001386 list->list = new_ptr;
Mark Youngf2079b92017-05-02 10:49:46 -06001387 list->capacity = new_capacity;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001388 }
1389
Lenny Komow397f9d42017-10-25 15:26:15 -06001390 // Verify that the layer api version is at least that of the application's request, if not, throw a warning since
1391 // undefined behavior could occur.
1392 layer_api_major_version = VK_VERSION_MAJOR(props[i].info.specVersion);
1393 layer_api_minor_version = VK_VERSION_MINOR(props[i].info.specVersion);
1394 if (inst->app_api_major_version > layer_api_major_version ||
1395 (inst->app_api_major_version == layer_api_major_version && inst->app_api_minor_version > layer_api_minor_version)) {
1396 loader_log(
1397 inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
1398 "loader_add_to_layer_list: Explicit layer %s is using an old API version %d.%d versus application requested %d.%d",
1399 props[i].info.layerName, layer_api_major_version, layer_api_minor_version, inst->app_api_major_version,- inst->app_api_minor_version);
1400 }
1401
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001402 memcpy(&list->list[list->count], layer, sizeof(struct loader_layer_properties));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001403 list->count++;
1404 }
Mark Young0ad83132016-06-30 13:02:42 -06001405
1406 return VK_SUCCESS;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001407}
1408
Mark Youngf2079b92017-05-02 10:49:46 -06001409// Check the individual implicit layer for the enable/disable environment variable settings. Only add it after
1410// every check has passed indicating it should be used.
1411static void loader_add_implicit_layer(const struct loader_instance *inst, const struct loader_layer_properties *prop,
Mark Young283fe1c2017-05-04 12:16:35 -06001412 struct loader_layer_list *target_list, struct loader_layer_list *expanded_target_list,
1413 const struct loader_layer_list *source_list) {
Jean-Francois Roybd7ceab2017-07-06 14:10:13 -07001414 bool enable = loader_is_implicit_layer_enabled(inst, prop);
Lenny Komow397f9d42017-10-25 15:26:15 -06001415
1416 // If the implicit layer is supposed to be enable, make sure the layer supports at least the same API version
1417 // that the application is asking (i.e. layer's API >= app's API). If it's not, disable this layer.
1418 if (enable) {
1419 uint16_t layer_api_major_version = VK_VERSION_MAJOR(prop->info.specVersion);
1420 uint16_t layer_api_minor_version = VK_VERSION_MINOR(prop->info.specVersion);
1421 if (inst->app_api_major_version > layer_api_major_version ||
1422 (inst->app_api_major_version == layer_api_major_version && inst->app_api_minor_version > layer_api_minor_version)) {
1423 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
1424 "loader_add_implicit_layer: Disabling implicit layer %s for using an old API version %d.%d versus "
1425 "application requested %d.%d",
1426 prop->info.layerName, layer_api_major_version, layer_api_minor_version, inst->app_api_major_version,
1427 inst->app_api_minor_version);
1428 enable = false;
1429 }
1430 }
1431
Mark Youngf2079b92017-05-02 10:49:46 -06001432 if (enable) {
Mark Youngf2079b92017-05-02 10:49:46 -06001433 if (0 == (prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
Mark Youngc8b807a2017-07-14 17:11:31 -06001434 if (NULL != target_list && !has_vk_layer_property(&prop->info, target_list)) {
Mark Young283fe1c2017-05-04 12:16:35 -06001435 loader_add_to_layer_list(inst, target_list, 1, prop);
1436 }
1437 if (NULL != expanded_target_list && !has_vk_layer_property(&prop->info, expanded_target_list)) {
1438 loader_add_to_layer_list(inst, expanded_target_list, 1, prop);
1439 }
Mark Youngf2079b92017-05-02 10:49:46 -06001440 } else {
Mark Young283fe1c2017-05-04 12:16:35 -06001441 if (!has_vk_layer_property(&prop->info, target_list) ||
1442 (NULL != expanded_target_list && !has_vk_layer_property(&prop->info, expanded_target_list))) {
1443 loader_add_meta_layer(inst, prop, target_list, expanded_target_list, source_list);
1444 }
Mark Youngf2079b92017-05-02 10:49:46 -06001445 }
1446 }
1447}
1448
1449// Add the component layers of a meta-layer to the active list of layers
1450bool loader_add_meta_layer(const struct loader_instance *inst, const struct loader_layer_properties *prop,
Mark Young283fe1c2017-05-04 12:16:35 -06001451 struct loader_layer_list *target_list, struct loader_layer_list *expanded_target_list,
1452 const struct loader_layer_list *source_list) {
Mark Youngf2079b92017-05-02 10:49:46 -06001453 bool found = true;
1454
1455 // We need to add all the individual component layers
1456 for (uint32_t comp_layer = 0; comp_layer < prop->num_component_layers; comp_layer++) {
1457 bool found_comp = false;
1458 const struct loader_layer_properties *search_prop =
1459 loader_get_layer_property(prop->component_layer_names[comp_layer], source_list);
1460 if (search_prop != NULL) {
1461 found_comp = true;
Mark Young283fe1c2017-05-04 12:16:35 -06001462
1463 // If the component layer is itself an implicit layer, we need to do the implicit layer enable
1464 // checks
Mark Youngf2079b92017-05-02 10:49:46 -06001465 if (0 == (search_prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER)) {
Mark Young283fe1c2017-05-04 12:16:35 -06001466 loader_add_implicit_layer(inst, search_prop, target_list, expanded_target_list, source_list);
Mark Youngf2079b92017-05-02 10:49:46 -06001467 } else {
Mark Young283fe1c2017-05-04 12:16:35 -06001468 if (NULL != expanded_target_list && !has_vk_layer_property(&search_prop->info, expanded_target_list)) {
1469 loader_add_to_layer_list(inst, expanded_target_list, 1, search_prop);
1470 }
Mark Youngf2079b92017-05-02 10:49:46 -06001471 }
1472 }
1473 if (!found_comp) {
1474 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
1475 "loader_add_meta_layer: Failed to find layer name %s component layer "
1476 "%s to activate",
1477 search_prop->info.layerName, prop->component_layer_names[comp_layer]);
1478 found = false;
1479 }
1480 }
Mark Youngc8b807a2017-07-14 17:11:31 -06001481
1482 // Add this layer to the overall target list (not the expanded one)
1483 if (found && !has_vk_layer_property(&prop->info, target_list)) {
1484 loader_add_to_layer_list(inst, target_list, 1, prop);
1485 }
1486
Mark Youngf2079b92017-05-02 10:49:46 -06001487 return found;
1488}
1489
1490// Search the source_list for any layer with a name that matches the given name and a type
1491// that matches the given type. Add all matching layers to the target_list.
1492// Do not add if found loader_layer_properties is already on the target_list.
1493void 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 -06001494 const struct loader_layer_list *source_list, struct loader_layer_list *target_list,
1495 struct loader_layer_list *expanded_target_list) {
Jon Ashburn56151d62015-10-05 09:03:21 -06001496 bool found = false;
Mark Youngf2079b92017-05-02 10:49:46 -06001497 for (uint32_t i = 0; i < source_list->count; i++) {
1498 struct loader_layer_properties *source_prop = &source_list->list[i];
1499 if (0 == strcmp(source_prop->info.layerName, name) && (source_prop->type_flags & type_flags) == type_flags) {
Mark Youngf2079b92017-05-02 10:49:46 -06001500 // If not a meta-layer, simply add it.
1501 if (0 == (source_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
Mark Youngc8b807a2017-07-14 17:11:31 -06001502 if (NULL != target_list && !has_vk_layer_property(&source_prop->info, target_list) &&
Mark Young283fe1c2017-05-04 12:16:35 -06001503 VK_SUCCESS == loader_add_to_layer_list(inst, target_list, 1, source_prop)) {
1504 found = true;
1505 }
Mark Youngc8b807a2017-07-14 17:11:31 -06001506 if (NULL != expanded_target_list && !has_vk_layer_property(&source_prop->info, expanded_target_list) &&
Mark Young283fe1c2017-05-04 12:16:35 -06001507 VK_SUCCESS == loader_add_to_layer_list(inst, expanded_target_list, 1, source_prop)) {
Mark Youngf2079b92017-05-02 10:49:46 -06001508 found = true;
1509 }
1510 } else {
Mark Young283fe1c2017-05-04 12:16:35 -06001511 found = loader_add_meta_layer(inst, source_prop, target_list, expanded_target_list, source_list);
Mark Young0ad83132016-06-30 13:02:42 -06001512 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001513 }
1514 }
Jon Ashburn56151d62015-10-05 09:03:21 -06001515 if (!found) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001516 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Youngf2079b92017-05-02 10:49:46 -06001517 "loader_find_layer_name_add_list: Failed to find layer name %s to activate", name);
Jon Ashburn56151d62015-10-05 09:03:21 -06001518 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001519}
1520
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001521static VkExtensionProperties *get_extension_property(const char *name, const struct loader_extension_list *list) {
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06001522 for (uint32_t i = 0; i < list->count; i++) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001523 if (strcmp(name, list->list[i].extensionName) == 0) return &list->list[i];
Jon Ashburnfc2e38c2015-04-14 09:15:32 -06001524 }
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06001525 return NULL;
Jon Ashburnfc2e38c2015-04-14 09:15:32 -06001526}
1527
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001528static VkExtensionProperties *get_dev_extension_property(const char *name, const struct loader_device_extension_list *list) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001529 for (uint32_t i = 0; i < list->count; i++) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001530 if (strcmp(name, list->list[i].props.extensionName) == 0) return &list->list[i].props;
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001531 }
1532 return NULL;
1533}
1534
Mark Young0f183a82017-02-28 09:58:04 -07001535// For Instance extensions implemented within the loader (i.e. DEBUG_REPORT
1536// the extension must provide two entry points for the loader to use:
1537// - "trampoline" entry point - this is the address returned by GetProcAddr
1538// and will always do what's necessary to support a
1539// global call.
1540// - "terminator" function - this function will be put at the end of the
1541// instance chain and will contain the necessary logic
1542// to call / process the extension for the appropriate
1543// ICDs that are available.
1544// There is no generic mechanism for including these functions, the references
1545// must be placed into the appropriate loader entry points.
1546// GetInstanceProcAddr: call extension GetInstanceProcAddr to check for GetProcAddr
1547// requests
1548// loader_coalesce_extensions(void) - add extension records to the list of global
1549// extension available to the app.
1550// instance_disp - add function pointer for terminator function
1551// to this array.
1552// The extension itself should be in a separate file that will be linked directly
1553// with the loader.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001554VkResult loader_get_icd_loader_instance_extensions(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list,
1555 struct loader_extension_list *inst_exts) {
Jon Ashburn5c6a46f2015-08-14 14:49:22 -06001556 struct loader_extension_list icd_exts;
Mark Young3a587792016-08-19 15:25:08 -06001557 VkResult res = VK_SUCCESS;
Mark Young2b2ece72017-02-10 11:19:02 -07001558 char *env_value;
1559 bool filter_extensions = true;
Mark Young3a587792016-08-19 15:25:08 -06001560
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001561 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Build ICD instance extension list");
Mark Young3a587792016-08-19 15:25:08 -06001562
Mark Young2b2ece72017-02-10 11:19:02 -07001563 // Check if a user wants to disable the instance extension filtering behavior
1564 env_value = loader_getenv("VK_LOADER_DISABLE_INST_EXT_FILTER", inst);
1565 if (NULL != env_value && atoi(env_value) != 0) {
1566 filter_extensions = false;
1567 }
1568 loader_free_getenv(env_value, inst);
1569
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001570 // traverse scanned icd list adding non-duplicate extensions to the list
Mark Young0153e0b2016-11-03 14:27:13 -06001571 for (uint32_t i = 0; i < icd_tramp_list->count; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001572 res = loader_init_generic_list(inst, (struct loader_generic_list *)&icd_exts, sizeof(VkExtensionProperties));
Mark Young3a587792016-08-19 15:25:08 -06001573 if (VK_SUCCESS != res) {
1574 goto out;
1575 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001576 res = loader_add_instance_extensions(inst, icd_tramp_list->scanned_list[i].EnumerateInstanceExtensionProperties,
1577 icd_tramp_list->scanned_list[i].lib_name, &icd_exts);
Mark Young3a587792016-08-19 15:25:08 -06001578 if (VK_SUCCESS == res) {
Mark Young2b2ece72017-02-10 11:19:02 -07001579 if (filter_extensions) {
1580 // Remove any extensions not recognized by the loader
1581 for (int32_t j = 0; j < (int32_t)icd_exts.count; j++) {
1582 // See if the extension is in the list of supported extensions
1583 bool found = false;
1584 for (uint32_t k = 0; LOADER_INSTANCE_EXTENSIONS[k] != NULL; k++) {
1585 if (strcmp(icd_exts.list[j].extensionName, LOADER_INSTANCE_EXTENSIONS[k]) == 0) {
1586 found = true;
1587 break;
1588 }
Lenny Komow4053b812016-12-29 16:27:28 -07001589 }
Lenny Komow4053b812016-12-29 16:27:28 -07001590
Mark Young2b2ece72017-02-10 11:19:02 -07001591 // If it isn't in the list, remove it
1592 if (!found) {
1593 for (uint32_t k = j + 1; k < icd_exts.count; k++) {
1594 icd_exts.list[k - 1] = icd_exts.list[k];
1595 }
1596 --icd_exts.count;
1597 --j;
Lenny Komow4053b812016-12-29 16:27:28 -07001598 }
Lenny Komow4053b812016-12-29 16:27:28 -07001599 }
1600 }
1601
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001602 res = loader_add_to_ext_list(inst, inst_exts, icd_exts.count, icd_exts.list);
Mark Young3a587792016-08-19 15:25:08 -06001603 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001604 loader_destroy_generic_list(inst, (struct loader_generic_list *)&icd_exts);
Mark Young3a587792016-08-19 15:25:08 -06001605 if (VK_SUCCESS != res) {
1606 goto out;
1607 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001608 };
1609
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001610 // Traverse loader's extensions, adding non-duplicate extensions to the list
Jon Ashburne39a4f82015-08-28 13:38:21 -06001611 debug_report_add_instance_extensions(inst, inst_exts);
Mark Young3a587792016-08-19 15:25:08 -06001612
1613out:
1614 return res;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001615}
1616
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001617struct 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 -06001618 *found_dev = NULL;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001619 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
Lenny Komow27167312017-03-31 13:43:35 -06001620 uint32_t index = 0;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001621 for (struct loader_icd_term *icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
1622 for (struct loader_device *dev = icd_term->logical_device_list; dev; dev = dev->next)
Mark Young65cb3662016-11-07 13:27:02 -07001623 // Value comparison of device prevents object wrapping by layers
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001624 if (loader_get_dispatch(dev->icd_device) == loader_get_dispatch(device) ||
1625 loader_get_dispatch(dev->chain_device) == loader_get_dispatch(device)) {
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001626 *found_dev = dev;
Mark Young16573c72016-06-28 10:52:43 -06001627 if (NULL != icd_index) {
1628 *icd_index = index;
1629 }
Mark Young0153e0b2016-11-03 14:27:13 -06001630 return icd_term;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001631 }
Mark Young16573c72016-06-28 10:52:43 -06001632 index++;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001633 }
1634 }
1635 return NULL;
1636}
1637
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001638void loader_destroy_logical_device(const struct loader_instance *inst, struct loader_device *dev,
Mark Young0ad83132016-06-30 13:02:42 -06001639 const VkAllocationCallbacks *pAllocator) {
1640 if (pAllocator) {
1641 dev->alloc_callbacks = *pAllocator;
1642 }
Mark Young283fe1c2017-05-04 12:16:35 -06001643 if (NULL != dev->expanded_activated_layer_list.list) {
1644 loader_deactivate_layers(inst, dev, &dev->expanded_activated_layer_list);
1645 }
1646 if (NULL != dev->app_activated_layer_list.list) {
1647 loader_destroy_layer_list(inst, dev, &dev->app_activated_layer_list);
Mark Young0ad83132016-06-30 13:02:42 -06001648 }
1649 loader_device_heap_free(dev, dev);
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001650}
1651
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001652struct loader_device *loader_create_logical_device(const struct loader_instance *inst, const VkAllocationCallbacks *pAllocator) {
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001653 struct loader_device *new_dev;
Mark Young0ad83132016-06-30 13:02:42 -06001654#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
1655 {
1656#else
1657 if (pAllocator) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001658 new_dev = (struct loader_device *)pAllocator->pfnAllocation(pAllocator->pUserData, sizeof(struct loader_device),
1659 sizeof(int *), VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
Mark Young0ad83132016-06-30 13:02:42 -06001660 } else {
1661#endif
1662 new_dev = (struct loader_device *)malloc(sizeof(struct loader_device));
1663 }
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001664
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001665 if (!new_dev) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001666 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1667 "loader_create_logical_device: Failed to alloc struct "
1668 "loader_device");
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001669 return NULL;
1670 }
1671
1672 memset(new_dev, 0, sizeof(struct loader_device));
Mark Young0ad83132016-06-30 13:02:42 -06001673 if (pAllocator) {
1674 new_dev->alloc_callbacks = *pAllocator;
1675 }
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001676
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001677 return new_dev;
1678}
1679
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001680void 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 -06001681 dev->next = icd_term->logical_device_list;
1682 icd_term->logical_device_list = dev;
Piers Daniell295fe402016-03-29 11:51:11 -06001683}
1684
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001685void loader_remove_logical_device(const struct loader_instance *inst, struct loader_icd_term *icd_term,
1686 struct loader_device *found_dev, const VkAllocationCallbacks *pAllocator) {
Jon Ashburn781a7ae2015-11-19 15:43:26 -07001687 struct loader_device *dev, *prev_dev;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001688
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001689 if (!icd_term || !found_dev) return;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001690
1691 prev_dev = NULL;
Mark Young0153e0b2016-11-03 14:27:13 -06001692 dev = icd_term->logical_device_list;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001693 while (dev && dev != found_dev) {
1694 prev_dev = dev;
1695 dev = dev->next;
1696 }
1697
1698 if (prev_dev)
1699 prev_dev->next = found_dev->next;
1700 else
Mark Young0153e0b2016-11-03 14:27:13 -06001701 icd_term->logical_device_list = found_dev->next;
Mark Young0ad83132016-06-30 13:02:42 -06001702 loader_destroy_logical_device(inst, found_dev, pAllocator);
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001703}
1704
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001705static void loader_icd_destroy(struct loader_instance *ptr_inst, struct loader_icd_term *icd_term,
Mark Young0ad83132016-06-30 13:02:42 -06001706 const VkAllocationCallbacks *pAllocator) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001707 ptr_inst->total_icd_count--;
Mark Young0153e0b2016-11-03 14:27:13 -06001708 for (struct loader_device *dev = icd_term->logical_device_list; dev;) {
Courtney Goeltzenleuchter1f157ac2015-06-14 19:57:15 -06001709 struct loader_device *next_dev = dev->next;
Mark Young0ad83132016-06-30 13:02:42 -06001710 loader_destroy_logical_device(ptr_inst, dev, pAllocator);
Courtney Goeltzenleuchter1f157ac2015-06-14 19:57:15 -06001711 dev = next_dev;
1712 }
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001713
Mark Young0153e0b2016-11-03 14:27:13 -06001714 loader_instance_heap_free(ptr_inst, icd_term);
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001715}
1716
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001717static struct loader_icd_term *loader_icd_create(const struct loader_instance *inst) {
Mark Young0153e0b2016-11-03 14:27:13 -06001718 struct loader_icd_term *icd_term;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001719
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001720 icd_term = loader_instance_heap_alloc(inst, sizeof(struct loader_icd_term), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0153e0b2016-11-03 14:27:13 -06001721 if (!icd_term) {
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001722 return NULL;
Mark Youngdb13a2a2016-09-06 13:53:03 -06001723 }
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001724
Mark Young0153e0b2016-11-03 14:27:13 -06001725 memset(icd_term, 0, sizeof(struct loader_icd_term));
Courtney Goeltzenleuchter55001bb2014-10-28 10:29:27 -06001726
Mark Young0153e0b2016-11-03 14:27:13 -06001727 return icd_term;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001728}
1729
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001730static 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 -06001731 struct loader_icd_term *icd_term;
Chia-I Wu13a61a52014-08-04 11:18:20 +08001732
Mark Young0153e0b2016-11-03 14:27:13 -06001733 icd_term = loader_icd_create(ptr_inst);
1734 if (!icd_term) {
Chia-I Wu13a61a52014-08-04 11:18:20 +08001735 return NULL;
Mark Youngdb13a2a2016-09-06 13:53:03 -06001736 }
Chia-I Wu13a61a52014-08-04 11:18:20 +08001737
Mark Young0153e0b2016-11-03 14:27:13 -06001738 icd_term->scanned_icd = scanned_icd;
1739 icd_term->this_instance = ptr_inst;
Jon Ashburn3d002332015-08-20 16:35:30 -06001740
Mark Young0f183a82017-02-28 09:58:04 -07001741 // Prepend to the list
Mark Young0153e0b2016-11-03 14:27:13 -06001742 icd_term->next = ptr_inst->icd_terms;
1743 ptr_inst->icd_terms = icd_term;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001744 ptr_inst->total_icd_count++;
Chia-I Wu13a61a52014-08-04 11:18:20 +08001745
Mark Young0153e0b2016-11-03 14:27:13 -06001746 return icd_term;
Chia-I Wu13a61a52014-08-04 11:18:20 +08001747}
Mark Young0153e0b2016-11-03 14:27:13 -06001748
Mark Young0f183a82017-02-28 09:58:04 -07001749// Determine the ICD interface version to use.
1750// @param icd
1751// @param pVersion Output parameter indicating which version to use or 0 if
1752// the negotiation API is not supported by the ICD
1753// @return bool indicating true if the selected interface version is supported
1754// by the loader, false indicates the version is not supported
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001755bool loader_get_icd_interface_version(PFN_vkNegotiateLoaderICDInterfaceVersion fp_negotiate_icd_version, uint32_t *pVersion) {
Jon Ashburn17b4c862016-04-25 11:09:37 -06001756 if (fp_negotiate_icd_version == NULL) {
1757 // ICD does not support the negotiation API, it supports version 0 or 1
1758 // calling code must determine if it is version 0 or 1
1759 *pVersion = 0;
1760 } else {
1761 // ICD supports the negotiation API, so call it with the loader's
1762 // latest version supported
1763 *pVersion = CURRENT_LOADER_ICD_INTERFACE_VERSION;
1764 VkResult result = fp_negotiate_icd_version(pVersion);
1765
1766 if (result == VK_ERROR_INCOMPATIBLE_DRIVER) {
1767 // ICD no longer supports the loader's latest interface version so
1768 // fail loading the ICD
1769 return false;
1770 }
1771 }
1772
1773#if MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION > 0
1774 if (*pVersion < MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION) {
1775 // Loader no longer supports the ICD's latest interface version so fail
1776 // loading the ICD
1777 return false;
1778 }
1779#endif
1780 return true;
1781}
Chia-I Wu13a61a52014-08-04 11:18:20 +08001782
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001783void loader_scanned_icd_clear(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list) {
Mark Youngf2079b92017-05-02 10:49:46 -06001784 if (0 != icd_tramp_list->capacity) {
1785 for (uint32_t i = 0; i < icd_tramp_list->count; i++) {
1786 loader_platform_close_library(icd_tramp_list->scanned_list[i].handle);
1787 loader_instance_heap_free(inst, icd_tramp_list->scanned_list[i].lib_name);
1788 }
1789 loader_instance_heap_free(inst, icd_tramp_list->scanned_list);
1790 icd_tramp_list->capacity = 0;
1791 icd_tramp_list->count = 0;
1792 icd_tramp_list->scanned_list = NULL;
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001793 }
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001794}
1795
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001796static 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 -06001797 VkResult err = VK_SUCCESS;
Mark Young0153e0b2016-11-03 14:27:13 -06001798 loader_scanned_icd_clear(inst, icd_tramp_list);
1799 icd_tramp_list->capacity = 8 * sizeof(struct loader_scanned_icd);
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001800 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 -06001801 if (NULL == icd_tramp_list->scanned_list) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001802 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1803 "loader_scanned_icd_init: Realloc failed for layer list when "
1804 "attempting to add new layer");
Mark Young0ad83132016-06-30 13:02:42 -06001805 err = VK_ERROR_OUT_OF_HOST_MEMORY;
1806 }
1807 return err;
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001808}
1809
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001810static VkResult loader_scanned_icd_add(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list,
1811 const char *filename, uint32_t api_version) {
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001812 loader_platform_dl_handle handle;
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06001813 PFN_vkCreateInstance fp_create_inst;
Jon Ashburnfd4d09d2016-01-07 09:44:27 -07001814 PFN_vkEnumerateInstanceExtensionProperties fp_get_inst_ext_props;
Jon Ashburnc624c882015-07-16 10:17:29 -06001815 PFN_vkGetInstanceProcAddr fp_get_proc_addr;
Mark Young39389872017-01-19 21:10:49 -07001816 PFN_GetPhysicalDeviceProcAddr fp_get_phys_dev_proc_addr = NULL;
Jon Ashburn17b4c862016-04-25 11:09:37 -06001817 PFN_vkNegotiateLoaderICDInterfaceVersion fp_negotiate_icd_version;
Mark Young0153e0b2016-11-03 14:27:13 -06001818 struct loader_scanned_icd *new_scanned_icd;
Jon Ashburn17b4c862016-04-25 11:09:37 -06001819 uint32_t interface_vers;
Mark Young3a587792016-08-19 15:25:08 -06001820 VkResult res = VK_SUCCESS;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001821
Mark Young0f183a82017-02-28 09:58:04 -07001822 // TODO implement smarter opening/closing of libraries. For now this
1823 // function leaves libraries open and the scanned_icd_clear closes them
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001824 handle = loader_platform_open_library(filename);
Mark Youngb6399312017-01-10 14:22:15 -07001825 if (NULL == handle) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001826 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, loader_platform_open_library_error(filename));
Mark Young3a587792016-08-19 15:25:08 -06001827 goto out;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001828 }
1829
Jon Ashburn17b4c862016-04-25 11:09:37 -06001830 // Get and settle on an ICD interface version
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001831 fp_negotiate_icd_version = loader_platform_get_proc_address(handle, "vk_icdNegotiateLoaderICDInterfaceVersion");
Jon Ashburn17b4c862016-04-25 11:09:37 -06001832
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001833 if (!loader_get_icd_interface_version(fp_negotiate_icd_version, &interface_vers)) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001834 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1835 "loader_scanned_icd_add: ICD %s doesn't support interface"
1836 " version compatible with loader, skip this ICD.",
Mark Young0ad83132016-06-30 13:02:42 -06001837 filename);
Mark Young3a587792016-08-19 15:25:08 -06001838 goto out;
Jon Ashburn17b4c862016-04-25 11:09:37 -06001839 }
1840
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001841 fp_get_proc_addr = loader_platform_get_proc_address(handle, "vk_icdGetInstanceProcAddr");
Mark Youngb6399312017-01-10 14:22:15 -07001842 if (NULL == fp_get_proc_addr) {
Jon Ashburn17b4c862016-04-25 11:09:37 -06001843 assert(interface_vers == 0);
1844 // Use deprecated interface from version 0
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001845 fp_get_proc_addr = loader_platform_get_proc_address(handle, "vkGetInstanceProcAddr");
Mark Youngb6399312017-01-10 14:22:15 -07001846 if (NULL == fp_get_proc_addr) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001847 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngdee312c2017-03-08 13:38:35 -07001848 "loader_scanned_icd_add: Attempt to retrieve either "
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001849 "\'vkGetInstanceProcAddr\' or "
1850 "\'vk_icdGetInstanceProcAddr\' from ICD %s failed.",
Mark Youngb6399312017-01-10 14:22:15 -07001851 filename);
Mark Young3a587792016-08-19 15:25:08 -06001852 goto out;
Jon Ashburnfd4d09d2016-01-07 09:44:27 -07001853 } else {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001854 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
1855 "loader_scanned_icd_add: Using deprecated ICD "
1856 "interface of \'vkGetInstanceProcAddr\' instead of "
1857 "\'vk_icdGetInstanceProcAddr\' for ICD %s",
Mark Young0ad83132016-06-30 13:02:42 -06001858 filename);
Jon Ashburnfd4d09d2016-01-07 09:44:27 -07001859 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001860 fp_create_inst = loader_platform_get_proc_address(handle, "vkCreateInstance");
Mark Youngb6399312017-01-10 14:22:15 -07001861 if (NULL == fp_create_inst) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001862 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1863 "loader_scanned_icd_add: Failed querying "
1864 "\'vkCreateInstance\' via dlsym/loadlibrary for "
1865 "ICD %s",
Mark Young0ad83132016-06-30 13:02:42 -06001866 filename);
Mark Young3a587792016-08-19 15:25:08 -06001867 goto out;
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001868 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001869 fp_get_inst_ext_props = loader_platform_get_proc_address(handle, "vkEnumerateInstanceExtensionProperties");
Mark Youngb6399312017-01-10 14:22:15 -07001870 if (NULL == fp_get_inst_ext_props) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001871 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1872 "loader_scanned_icd_add: Could not get \'vkEnumerate"
1873 "InstanceExtensionProperties\' via dlsym/loadlibrary "
1874 "for ICD %s",
Mark Young0ad83132016-06-30 13:02:42 -06001875 filename);
Mark Young3a587792016-08-19 15:25:08 -06001876 goto out;
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001877 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07001878 } else {
Jon Ashburn17b4c862016-04-25 11:09:37 -06001879 // Use newer interface version 1 or later
Mark Young39389872017-01-19 21:10:49 -07001880 if (interface_vers == 0) {
Jon Ashburn17b4c862016-04-25 11:09:37 -06001881 interface_vers = 1;
Mark Young39389872017-01-19 21:10:49 -07001882 }
Jon Ashburn17b4c862016-04-25 11:09:37 -06001883
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001884 fp_create_inst = (PFN_vkCreateInstance)fp_get_proc_addr(NULL, "vkCreateInstance");
Mark Youngb6399312017-01-10 14:22:15 -07001885 if (NULL == fp_create_inst) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001886 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1887 "loader_scanned_icd_add: Could not get "
1888 "\'vkCreateInstance\' via \'vk_icdGetInstanceProcAddr\'"
1889 " for ICD %s",
Mark Young0ad83132016-06-30 13:02:42 -06001890 filename);
Mark Young3a587792016-08-19 15:25:08 -06001891 goto out;
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001892 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07001893 fp_get_inst_ext_props =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001894 (PFN_vkEnumerateInstanceExtensionProperties)fp_get_proc_addr(NULL, "vkEnumerateInstanceExtensionProperties");
Mark Youngb6399312017-01-10 14:22:15 -07001895 if (NULL == fp_get_inst_ext_props) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001896 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1897 "loader_scanned_icd_add: Could not get \'vkEnumerate"
1898 "InstanceExtensionProperties\' via "
1899 "\'vk_icdGetInstanceProcAddr\' for ICD %s",
Mark Young0ad83132016-06-30 13:02:42 -06001900 filename);
Mark Young3a587792016-08-19 15:25:08 -06001901 goto out;
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001902 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001903 fp_get_phys_dev_proc_addr = loader_platform_get_proc_address(handle, "vk_icdGetPhysicalDeviceProcAddr");
Jon Ashburnfd4d09d2016-01-07 09:44:27 -07001904 }
Jon Ashburn46d1f582015-01-28 11:01:35 -07001905
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001906 // check for enough capacity
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001907 if ((icd_tramp_list->count * sizeof(struct loader_scanned_icd)) >= icd_tramp_list->capacity) {
Mark Youngbb3a29c2017-05-19 12:29:43 -06001908 void *new_ptr = loader_instance_heap_realloc(inst, icd_tramp_list->scanned_list, icd_tramp_list->capacity,
1909 icd_tramp_list->capacity * 2, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1910 if (NULL == new_ptr) {
Mark Young3a587792016-08-19 15:25:08 -06001911 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001912 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngbb3a29c2017-05-19 12:29:43 -06001913 "loader_scanned_icd_add: Realloc failed on icd library list for ICD %s", filename);
Mark Young3a587792016-08-19 15:25:08 -06001914 goto out;
Mark Young0ad83132016-06-30 13:02:42 -06001915 }
Mark Youngbb3a29c2017-05-19 12:29:43 -06001916 icd_tramp_list->scanned_list = new_ptr;
1917
Jon Ashburn23d36b12016-02-02 17:47:28 -07001918 // double capacity
Mark Young0153e0b2016-11-03 14:27:13 -06001919 icd_tramp_list->capacity *= 2;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001920 }
1921
Mark Young39389872017-01-19 21:10:49 -07001922 new_scanned_icd = &(icd_tramp_list->scanned_list[icd_tramp_list->count]);
Mark Young0153e0b2016-11-03 14:27:13 -06001923 new_scanned_icd->handle = handle;
1924 new_scanned_icd->api_version = api_version;
1925 new_scanned_icd->GetInstanceProcAddr = fp_get_proc_addr;
Mark Young39389872017-01-19 21:10:49 -07001926 new_scanned_icd->GetPhysicalDeviceProcAddr = fp_get_phys_dev_proc_addr;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001927 new_scanned_icd->EnumerateInstanceExtensionProperties = fp_get_inst_ext_props;
Mark Young0153e0b2016-11-03 14:27:13 -06001928 new_scanned_icd->CreateInstance = fp_create_inst;
1929 new_scanned_icd->interface_version = interface_vers;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001930
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001931 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 -06001932 if (NULL == new_scanned_icd->lib_name) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001933 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 -06001934 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young3a587792016-08-19 15:25:08 -06001935 goto out;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001936 }
Mark Young0153e0b2016-11-03 14:27:13 -06001937 strcpy(new_scanned_icd->lib_name, filename);
1938 icd_tramp_list->count++;
Mark Young3a587792016-08-19 15:25:08 -06001939
1940out:
1941
1942 return res;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001943}
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001944
Jon Ashburn23d36b12016-02-02 17:47:28 -07001945static void loader_debug_init(void) {
Mark Young0ad83132016-06-30 13:02:42 -06001946 char *env, *orig;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001947
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001948 if (g_loader_debug > 0) return;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001949
1950 g_loader_debug = 0;
1951
Mark Young0f183a82017-02-28 09:58:04 -07001952 // Parse comma-separated debug options
Mark Young0ad83132016-06-30 13:02:42 -06001953 orig = env = loader_getenv("VK_LOADER_DEBUG", NULL);
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001954 while (env) {
Mark Young0ad83132016-06-30 13:02:42 -06001955 char *p = strchr(env, ',');
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001956 size_t len;
1957
1958 if (p)
1959 len = p - env;
1960 else
1961 len = strlen(env);
1962
1963 if (len > 0) {
Michael Worcester25c73e72015-12-10 18:06:24 +00001964 if (strncmp(env, "all", len) == 0) {
1965 g_loader_debug = ~0u;
1966 g_loader_log_msgs = ~0u;
1967 } else if (strncmp(env, "warn", len) == 0) {
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001968 g_loader_debug |= LOADER_WARN_BIT;
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07001969 g_loader_log_msgs |= VK_DEBUG_REPORT_WARNING_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001970 } else if (strncmp(env, "info", len) == 0) {
1971 g_loader_debug |= LOADER_INFO_BIT;
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07001972 g_loader_log_msgs |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001973 } else if (strncmp(env, "perf", len) == 0) {
1974 g_loader_debug |= LOADER_PERF_BIT;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001975 g_loader_log_msgs |= VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001976 } else if (strncmp(env, "error", len) == 0) {
1977 g_loader_debug |= LOADER_ERROR_BIT;
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07001978 g_loader_log_msgs |= VK_DEBUG_REPORT_ERROR_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001979 } else if (strncmp(env, "debug", len) == 0) {
1980 g_loader_debug |= LOADER_DEBUG_BIT;
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07001981 g_loader_log_msgs |= VK_DEBUG_REPORT_DEBUG_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001982 }
1983 }
1984
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001985 if (!p) break;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001986
1987 env = p + 1;
1988 }
Jon Ashburn38a497f2016-01-04 14:01:38 -07001989
Mark Young0ad83132016-06-30 13:02:42 -06001990 loader_free_getenv(orig, NULL);
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001991}
1992
Jon Ashburn23d36b12016-02-02 17:47:28 -07001993void loader_initialize(void) {
Jon Ashburn6461ef22015-09-22 13:11:00 -06001994 // initialize mutexs
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001995 loader_platform_thread_create_mutex(&loader_lock);
Jon Ashburn6461ef22015-09-22 13:11:00 -06001996 loader_platform_thread_create_mutex(&loader_json_lock);
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001997
1998 // initialize logging
1999 loader_debug_init();
Jon Ashburn87d6aa92015-08-28 15:19:27 -06002000
2001 // initial cJSON to use alloc callbacks
2002 cJSON_Hooks alloc_fns = {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002003 .malloc_fn = loader_instance_tls_heap_alloc, .free_fn = loader_instance_tls_heap_free,
Jon Ashburn87d6aa92015-08-28 15:19:27 -06002004 };
2005 cJSON_InitHooks(&alloc_fns);
Jon Ashburn8810c5f2015-08-18 18:04:47 -06002006}
2007
Jon Ashburn2077e382015-06-29 11:25:34 -06002008struct loader_manifest_files {
2009 uint32_t count;
2010 char **filename_list;
2011};
2012
Lenny Komow158e9d92018-01-15 15:43:36 -07002013void loader_release() {
2014 // release mutexs
2015 loader_platform_thread_delete_mutex(&loader_lock);
2016 loader_platform_thread_delete_mutex(&loader_json_lock);
2017}
2018
Mark Young0f183a82017-02-28 09:58:04 -07002019// Get next file or dirname given a string list or registry key path
2020//
2021// \returns
2022// A pointer to first char in the next path.
2023// The next path (or NULL) in the list is returned in next_path.
2024// Note: input string is modified in some cases. PASS IN A COPY!
Jon Ashburn23d36b12016-02-02 17:47:28 -07002025static char *loader_get_next_path(char *path) {
Jon Ashburn2077e382015-06-29 11:25:34 -06002026 uint32_t len;
2027 char *next;
2028
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002029 if (path == NULL) return NULL;
Frank Henigman57173102016-11-24 22:15:20 -05002030 next = strchr(path, PATH_SEPARATOR);
Jon Ashburn2077e382015-06-29 11:25:34 -06002031 if (next == NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07002032 len = (uint32_t)strlen(path);
Jon Ashburn2077e382015-06-29 11:25:34 -06002033 next = path + len;
Jon Ashburn23d36b12016-02-02 17:47:28 -07002034 } else {
Jon Ashburn2077e382015-06-29 11:25:34 -06002035 *next = '\0';
2036 next++;
2037 }
2038
2039 return next;
2040}
2041
Mark Young0f183a82017-02-28 09:58:04 -07002042// Given a path which is absolute or relative, expand the path if relative or
2043// leave the path unmodified if absolute. The base path to prepend to relative
2044// paths is given in rel_base.
2045//
2046// @return - A string in out_fullpath of the full absolute path
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002047static 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 -06002048 if (loader_platform_is_path_absolute(path)) {
Daniel Dadap00b4aba2015-09-30 11:50:51 -05002049 // do not prepend a base to an absolute path
2050 rel_base = "";
Jon Ashburn15315172015-07-07 15:06:25 -06002051 }
Daniel Dadap00b4aba2015-09-30 11:50:51 -05002052
2053 loader_platform_combine_path(out_fullpath, out_size, rel_base, path, NULL);
Jon Ashburn15315172015-07-07 15:06:25 -06002054}
2055
Mark Young0f183a82017-02-28 09:58:04 -07002056// Given a filename (file) and a list of paths (dir), try to find an existing
2057// file in the paths. If filename already is a path then no searching in the given paths.
2058//
2059// @return - A string in out_fullpath of either the full path or file.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002060static void loader_get_fullpath(const char *file, const char *dirs, size_t out_size, char *out_fullpath) {
Daniel Dadap00b4aba2015-09-30 11:50:51 -05002061 if (!loader_platform_is_path(file) && *dirs) {
2062 char *dirs_copy, *dir, *next_dir;
2063
2064 dirs_copy = loader_stack_alloc(strlen(dirs) + 1);
2065 strcpy(dirs_copy, dirs);
2066
Jon Ashburn23d36b12016-02-02 17:47:28 -07002067 // find if file exists after prepending paths in given list
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002068 for (dir = dirs_copy; *dir && (next_dir = loader_get_next_path(dir)); dir = next_dir) {
2069 loader_platform_combine_path(out_fullpath, out_size, dir, file, NULL);
Jon Ashburn2077e382015-06-29 11:25:34 -06002070 if (loader_platform_file_exists(out_fullpath)) {
2071 return;
2072 }
Jon Ashburn2077e382015-06-29 11:25:34 -06002073 }
2074 }
Daniel Dadap00b4aba2015-09-30 11:50:51 -05002075
Karl Schultze2ef9e62017-01-13 14:01:35 -07002076 (void)snprintf(out_fullpath, out_size, "%s", file);
Jon Ashburn2077e382015-06-29 11:25:34 -06002077}
2078
Mark Young0f183a82017-02-28 09:58:04 -07002079// Read a JSON file into a buffer.
2080//
2081// @return - A pointer to a cJSON object representing the JSON parse tree.
2082// This returned buffer should be freed by caller.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002083static VkResult loader_get_json(const struct loader_instance *inst, const char *filename, cJSON **json) {
Mark Young3a587792016-08-19 15:25:08 -06002084 FILE *file = NULL;
Jon Ashburn2077e382015-06-29 11:25:34 -06002085 char *json_buf;
Mark Young93ecb1d2016-01-13 13:47:16 -07002086 size_t len;
Mark Young3a587792016-08-19 15:25:08 -06002087 VkResult res = VK_SUCCESS;
2088
2089 if (NULL == json) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002090 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, "loader_get_json: Received invalid JSON file");
Mark Young3a587792016-08-19 15:25:08 -06002091 res = VK_ERROR_INITIALIZATION_FAILED;
2092 goto out;
2093 }
2094
2095 *json = NULL;
2096
Jon Ashburn23d36b12016-02-02 17:47:28 -07002097 file = fopen(filename, "rb");
Jon Ashburnaa4ea472015-08-27 08:30:50 -06002098 if (!file) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002099 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 -07002100 res = VK_ERROR_INITIALIZATION_FAILED;
Mark Young3a587792016-08-19 15:25:08 -06002101 goto out;
Jon Ashburnaa4ea472015-08-27 08:30:50 -06002102 }
Jon Ashburn2077e382015-06-29 11:25:34 -06002103 fseek(file, 0, SEEK_END);
2104 len = ftell(file);
2105 fseek(file, 0, SEEK_SET);
Jon Ashburn23d36b12016-02-02 17:47:28 -07002106 json_buf = (char *)loader_stack_alloc(len + 1);
Jon Ashburn2077e382015-06-29 11:25:34 -06002107 if (json_buf == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002108 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2109 "loader_get_json: Failed to allocate space for "
2110 "JSON file %s buffer of length %d",
Mark Youngb6399312017-01-10 14:22:15 -07002111 filename, len);
2112 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young3a587792016-08-19 15:25:08 -06002113 goto out;
Jon Ashburn2077e382015-06-29 11:25:34 -06002114 }
2115 if (fread(json_buf, sizeof(char), len, file) != len) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002116 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 -07002117 res = VK_ERROR_INITIALIZATION_FAILED;
Mark Young3a587792016-08-19 15:25:08 -06002118 goto out;
Jon Ashburn2077e382015-06-29 11:25:34 -06002119 }
Jon Ashburn2077e382015-06-29 11:25:34 -06002120 json_buf[len] = '\0';
2121
Mark Young0f183a82017-02-28 09:58:04 -07002122 // Parse text from file
Mark Young3a587792016-08-19 15:25:08 -06002123 *json = cJSON_Parse(json_buf);
2124 if (*json == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002125 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2126 "loader_get_json: Failed to parse JSON file %s, "
2127 "this is usually because something ran out of "
2128 "memory.",
Mark Youngb6399312017-01-10 14:22:15 -07002129 filename);
2130 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young3a587792016-08-19 15:25:08 -06002131 goto out;
2132 }
2133
2134out:
2135 if (NULL != file) {
2136 fclose(file);
2137 }
2138
2139 return res;
Jon Ashburn2077e382015-06-29 11:25:34 -06002140}
2141
Mark Young0f183a82017-02-28 09:58:04 -07002142// Do a deep copy of the loader_layer_properties structure.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002143VkResult loader_copy_layer_properties(const struct loader_instance *inst, struct loader_layer_properties *dst,
Mark Young0ad83132016-06-30 13:02:42 -06002144 struct loader_layer_properties *src) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07002145 uint32_t cnt, i;
Jon Ashburn23d36b12016-02-02 17:47:28 -07002146 memcpy(dst, src, sizeof(*src));
Mark Youngb6399312017-01-10 14:22:15 -07002147 dst->instance_extension_list.list = loader_instance_heap_alloc(
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002148 inst, sizeof(VkExtensionProperties) * src->instance_extension_list.count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0ad83132016-06-30 13:02:42 -06002149 if (NULL == dst->instance_extension_list.list) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002150 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2151 "loader_copy_layer_properties: Failed to allocate space "
2152 "for instance extension list of size %d.",
Mark Youngb6399312017-01-10 14:22:15 -07002153 src->instance_extension_list.count);
Mark Young0ad83132016-06-30 13:02:42 -06002154 return VK_ERROR_OUT_OF_HOST_MEMORY;
2155 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002156 dst->instance_extension_list.capacity = sizeof(VkExtensionProperties) * src->instance_extension_list.count;
2157 memcpy(dst->instance_extension_list.list, src->instance_extension_list.list, dst->instance_extension_list.capacity);
Mark Youngb6399312017-01-10 14:22:15 -07002158 dst->device_extension_list.list = loader_instance_heap_alloc(
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002159 inst, sizeof(struct loader_dev_ext_props) * src->device_extension_list.count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0ad83132016-06-30 13:02:42 -06002160 if (NULL == dst->device_extension_list.list) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002161 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2162 "loader_copy_layer_properties: Failed to allocate space "
2163 "for device extension list of size %d.",
Mark Youngb6399312017-01-10 14:22:15 -07002164 src->device_extension_list.count);
Mark Young0ad83132016-06-30 13:02:42 -06002165 return VK_ERROR_OUT_OF_HOST_MEMORY;
2166 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002167 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 -07002168
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002169 dst->device_extension_list.capacity = sizeof(struct loader_dev_ext_props) * src->device_extension_list.count;
2170 memcpy(dst->device_extension_list.list, src->device_extension_list.list, dst->device_extension_list.capacity);
2171 if (src->device_extension_list.count > 0 && src->device_extension_list.list->entrypoint_count > 0) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07002172 cnt = src->device_extension_list.list->entrypoint_count;
Mark Young0ad83132016-06-30 13:02:42 -06002173 dst->device_extension_list.list->entrypoints =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002174 loader_instance_heap_alloc(inst, sizeof(char *) * cnt, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0ad83132016-06-30 13:02:42 -06002175 if (NULL == dst->device_extension_list.list->entrypoints) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002176 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2177 "loader_copy_layer_properties: Failed to allocate space "
2178 "for device extension entrypoint list of size %d.",
Mark Youngb6399312017-01-10 14:22:15 -07002179 cnt);
Mark Young0ad83132016-06-30 13:02:42 -06002180 return VK_ERROR_OUT_OF_HOST_MEMORY;
2181 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002182 memset(dst->device_extension_list.list->entrypoints, 0, sizeof(char *) * cnt);
Mark Young0ad83132016-06-30 13:02:42 -06002183
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07002184 for (i = 0; i < cnt; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002185 dst->device_extension_list.list->entrypoints[i] = loader_instance_heap_alloc(
2186 inst, strlen(src->device_extension_list.list->entrypoints[i]) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0ad83132016-06-30 13:02:42 -06002187 if (NULL == dst->device_extension_list.list->entrypoints[i]) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002188 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2189 "loader_copy_layer_properties: Failed to "
2190 "allocate space for device extension entrypoint "
2191 "%d name of length",
Mark Youngb6399312017-01-10 14:22:15 -07002192 i);
Mark Young0ad83132016-06-30 13:02:42 -06002193 return VK_ERROR_OUT_OF_HOST_MEMORY;
2194 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002195 strcpy(dst->device_extension_list.list->entrypoints[i], src->device_extension_list.list->entrypoints[i]);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07002196 }
2197 }
Mark Young0ad83132016-06-30 13:02:42 -06002198
2199 return VK_SUCCESS;
Jon Ashburn3d002332015-08-20 16:35:30 -06002200}
2201
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002202static bool loader_find_layer_name_list(const char *name, const struct loader_layer_list *layer_list) {
Mark Youngf2079b92017-05-02 10:49:46 -06002203 if (NULL == layer_list) {
2204 return false;
2205 }
2206 for (uint32_t j = 0; j < layer_list->count; j++) {
2207 if (!strcmp(name, layer_list->list[j].info.layerName)) {
2208 return true;
2209 }
2210 }
Jon Ashburn86a527a2016-02-10 20:59:26 -07002211 return false;
2212}
2213
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002214bool 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 -07002215 if (!layer_list) return false;
Jon Ashburn86a527a2016-02-10 20:59:26 -07002216 for (uint32_t j = 0; j < layer_count; j++)
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002217 if (!strcmp(name, layer_list[j])) return true;
Jon Ashburn86a527a2016-02-10 20:59:26 -07002218 return false;
2219}
2220
Mark Youngf2079b92017-05-02 10:49:46 -06002221const char *std_validation_str = "VK_LAYER_LUNARG_standard_validation";
Jon Ashburn86a527a2016-02-10 20:59:26 -07002222
Mark Youngf2079b92017-05-02 10:49:46 -06002223// Adds the legacy VK_LAYER_LUNARG_standard_validation as a meta-layer if it
2224// fails to find it in the list already. This is usually an indication that a
2225// newer loader is being used with an older layer set.
2226static bool loader_add_legacy_std_val_layer(const struct loader_instance *inst, struct loader_layer_list *layer_instance_list) {
2227 uint32_t i;
2228 bool success = true;
2229 struct loader_layer_properties *props = loader_get_next_layer_property(inst, layer_instance_list);
2230 const char std_validation_names[6][VK_MAX_EXTENSION_NAME_SIZE] = {
Mark Youngc8b807a2017-07-14 17:11:31 -06002231 "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", "VK_LAYER_LUNARG_object_tracker",
2232 "VK_LAYER_LUNARG_core_validation", "VK_LAYER_GOOGLE_unique_objects"};
Mark Youngf2079b92017-05-02 10:49:46 -06002233 uint32_t layer_count = sizeof(std_validation_names) / sizeof(std_validation_names[0]);
2234
2235 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
2236 "Adding VK_LAYER_LUNARG_standard_validation using the loader legacy path. This is"
2237 " not an error.");
2238
2239 if (NULL == props) {
2240 goto out;
Jon Ashburn491cd042016-05-16 14:01:18 -06002241 }
Jon Ashburn71483442016-02-11 18:59:43 -07002242
Jon Ashburn491cd042016-05-16 14:01:18 -06002243 memset(props, 0, sizeof(struct loader_layer_properties));
Mark Youngf2079b92017-05-02 10:49:46 -06002244 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 -07002245 strncpy(props->info.description, "LunarG Standard Validation Layer", sizeof(props->info.description));
Jon Ashburn491cd042016-05-16 14:01:18 -06002246 props->info.implementationVersion = 1;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002247 strncpy(props->info.layerName, std_validation_str, sizeof(props->info.layerName));
Jon Ashburn491cd042016-05-16 14:01:18 -06002248 props->info.specVersion = VK_MAKE_VERSION(1, 0, VK_HEADER_VERSION);
Jon Ashburn491cd042016-05-16 14:01:18 -06002249
Mark Youngf2079b92017-05-02 10:49:46 -06002250 props->component_layer_names =
2251 loader_instance_heap_alloc(inst, sizeof(char[MAX_STRING_SIZE]) * layer_count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2252 if (NULL == props->component_layer_names) {
2253 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2254 "Failed to allocate space for legacy VK_LAYER_LUNARG_standard_validation"
2255 " meta-layer component_layers information.");
2256 success = false;
2257 goto out;
2258 }
Jon Ashburn491cd042016-05-16 14:01:18 -06002259 for (i = 0; i < layer_count; i++) {
Mark Youngf2079b92017-05-02 10:49:46 -06002260 strncpy(props->component_layer_names[i], std_validation_names[i], MAX_STRING_SIZE - 1);
2261 props->component_layer_names[i][MAX_STRING_SIZE - 1] = '\0';
Jon Ashburn86a527a2016-02-10 20:59:26 -07002262 }
Jon Ashburn491cd042016-05-16 14:01:18 -06002263
Mark Youngf2079b92017-05-02 10:49:46 -06002264out:
2265
2266 if (!success && NULL != props && NULL != props->component_layer_names) {
2267 loader_instance_heap_free(inst, props->component_layer_names);
2268 props->component_layer_names = NULL;
2269 }
2270
2271 return success;
2272}
2273
2274// Verify that all component layers in a meta-layer are valid.
2275static bool verify_meta_layer_comp_layers(const struct loader_instance *inst, struct loader_layer_properties *prop,
2276 struct loader_layer_list *instance_layers) {
2277 bool success = true;
Mark Youngc82a0622017-05-05 11:17:17 -06002278 const uint32_t expected_major = VK_VERSION_MAJOR(prop->info.specVersion);
2279 const uint32_t expected_minor = VK_VERSION_MINOR(prop->info.specVersion);
Mark Youngf2079b92017-05-02 10:49:46 -06002280
2281 for (uint32_t comp_layer = 0; comp_layer < prop->num_component_layers; comp_layer++) {
2282 if (!loader_find_layer_name_list(prop->component_layer_names[comp_layer], instance_layers)) {
2283 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2284 "Meta-layer %s can't find component layer %s at index %d."
2285 " Skipping this layer.",
2286 prop->info.layerName, prop->component_layer_names[comp_layer], comp_layer);
2287 success = false;
2288 break;
2289 } else {
2290 struct loader_layer_properties *comp_prop =
2291 loader_get_layer_property(prop->component_layer_names[comp_layer], instance_layers);
2292 if (comp_prop == NULL) {
2293 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2294 "Meta-layer %s can't find property for component layer %s at index %d."
2295 " Skipping this layer.",
2296 prop->info.layerName, prop->component_layer_names[comp_layer], comp_layer);
2297 success = false;
2298 break;
2299 }
2300
2301 // Check the version of each layer, they need to at least match MAJOR and MINOR
Mark Youngc82a0622017-05-05 11:17:17 -06002302 uint32_t cur_major = VK_VERSION_MAJOR(comp_prop->info.specVersion);
2303 uint32_t cur_minor = VK_VERSION_MINOR(comp_prop->info.specVersion);
2304 if (cur_major != expected_major || cur_minor != expected_minor) {
2305 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2306 "Meta-layer uses API version %d.%d, but component layer %d uses API "
2307 "version %d.%d. Skipping this layer.",
2308 expected_major, expected_minor, comp_layer, cur_major, cur_minor);
2309 success = false;
2310 break;
Mark Youngf2079b92017-05-02 10:49:46 -06002311 }
2312
2313 // Make sure the layer isn't using it's own name
2314 if (!strcmp(prop->info.layerName, prop->component_layer_names[comp_layer])) {
2315 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2316 "Meta-layer %s lists itself in its component layer list at index %d."
2317 " Skipping this layer.",
2318 prop->info.layerName, comp_layer);
2319 success = false;
2320 break;
2321 }
2322 if (comp_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) {
2323 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
2324 "verify_meta_layer_comp_layers: Adding meta-layer %s which also contains meta-layer %s",
2325 prop->info.layerName, comp_prop->info.layerName);
2326
2327 // Make sure if the layer is using a meta-layer in its component list that we also verify that.
2328 if (!verify_meta_layer_comp_layers(inst, comp_prop, instance_layers)) {
2329 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2330 "Meta-layer %s component layer %s can not find all component layers."
2331 " Skipping this layer.",
2332 prop->info.layerName, prop->component_layer_names[comp_layer]);
2333 success = false;
2334 break;
2335 }
2336 }
2337
2338 // Add any instance and device extensions from component layers to this layer
2339 // list, so that anyone querying extensions will only need to look at the meta-layer
2340 for (uint32_t ext = 0; ext < comp_prop->instance_extension_list.count; ext++) {
2341 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Meta-layer %s component layer %s adding instance extension %s",
2342 prop->info.layerName, prop->component_layer_names[comp_layer],
2343 comp_prop->instance_extension_list.list[ext].extensionName);
2344 if (!has_vk_extension_property(&comp_prop->instance_extension_list.list[ext], &prop->instance_extension_list)) {
2345 loader_add_to_ext_list(inst, &prop->instance_extension_list, 1, &comp_prop->instance_extension_list.list[ext]);
2346 }
2347 }
2348
2349 for (uint32_t ext = 0; ext < comp_prop->device_extension_list.count; ext++) {
2350 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Meta-layer %s component layer %s adding device extension %s",
2351 prop->info.layerName, prop->component_layer_names[comp_layer],
2352 comp_prop->device_extension_list.list[ext].props.extensionName);
2353 if (!has_vk_dev_ext_property(&comp_prop->device_extension_list.list[ext].props, &prop->device_extension_list)) {
2354 loader_add_to_dev_ext_list(inst, &prop->device_extension_list,
2355 &comp_prop->device_extension_list.list[ext].props, 0, NULL);
2356 }
2357 }
Mark Young0ad83132016-06-30 13:02:42 -06002358 }
Mark Youngf2079b92017-05-02 10:49:46 -06002359 }
2360 if (success) {
2361 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Meta-layer %s all %d component layers appear to be valid.",
2362 prop->info.layerName, prop->num_component_layers);
2363 }
2364 return success;
2365}
2366
2367// Verify that all meta-layers in a layer list are valid.
2368static void verify_all_meta_layers(const struct loader_instance *inst, struct loader_layer_list *instance_layers) {
Mark Young697317f2017-05-09 10:31:12 -06002369 for (int32_t i = 0; i < (int32_t)instance_layers->count; i++) {
Mark Youngf2079b92017-05-02 10:49:46 -06002370 struct loader_layer_properties *prop = &instance_layers->list[i];
2371
2372 // If this is a meta-layer, make sure it is valid
2373 if ((prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) && !verify_meta_layer_comp_layers(inst, prop, instance_layers)) {
2374 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
2375 "Removing meta-layer %s from instance layer list since it appears invalid.", prop->info.layerName);
2376
2377 // Delete the component layers
Mark Youngf2079b92017-05-02 10:49:46 -06002378 loader_instance_heap_free(inst, prop->component_layer_names);
Mark Youngf2079b92017-05-02 10:49:46 -06002379
Mark Young70ede4c2017-05-09 15:23:33 -06002380 // Remove the current invalid meta-layer from the layer list. Use memmove since we are
2381 // overlapping the source and destination addresses.
2382 memmove(&instance_layers->list[i], &instance_layers->list[i + 1],
2383 sizeof(struct loader_layer_properties) * (instance_layers->count - 1 - i));
Mark Youngf2079b92017-05-02 10:49:46 -06002384
Mark Young70ede4c2017-05-09 15:23:33 -06002385 // Decrement the count (because we now have one less) and decrement the loop index since we need to
2386 // re-check this index.
2387 instance_layers->count--;
Mark Young697317f2017-05-09 10:31:12 -06002388 i--;
Mark Youngf2079b92017-05-02 10:49:46 -06002389 }
Jon Ashburn491cd042016-05-16 14:01:18 -06002390 }
Jon Ashburn86a527a2016-02-10 20:59:26 -07002391}
2392
Mark Young39389872017-01-19 21:10:49 -07002393// This structure is used to store the json file version
Mark Youngdee312c2017-03-08 13:38:35 -07002394// in a more manageable way.
Mark Young39389872017-01-19 21:10:49 -07002395typedef struct {
2396 uint16_t major;
2397 uint16_t minor;
2398 uint16_t patch;
2399} layer_json_version;
2400
Lenny Komow3cf3ac72017-12-19 16:38:37 -07002401static inline bool is_valid_layer_json_version(const layer_json_version *layer_json) {
2402 // Supported versions are: 1.0.0, 1.0.1, 1.1.0, 1.1.1, and 1.1.2.
2403 if ((layer_json->major == 1 && layer_json->minor == 1 && layer_json->patch < 3) ||
2404 (layer_json->major == 1 && layer_json->minor == 0 && layer_json->patch < 2)) {
2405 return true;
2406 }
2407 return false;
2408}
2409
2410static inline bool layer_json_supports_layers_tag(const layer_json_version *layer_json) {
2411 // Supported versions started in 1.0.1, so anything newer
2412 if ((layer_json->major > 1 || layer_json->minor > 0 || layer_json->patch > 1)) {
2413 return true;
2414 }
2415 return false;
2416}
2417
2418static inline bool layer_json_supports_pre_instance_tag(const layer_json_version *layer_json) {
2419 // Supported versions started in 1.1.2, so anything newer
2420 return layer_json->major > 1 || layer_json->minor > 1 || (layer_json->minor == 1 && layer_json->patch > 1);
2421}
2422
Mark Youngf2079b92017-05-02 10:49:46 -06002423static VkResult loader_read_json_layer(const struct loader_instance *inst, struct loader_layer_list *layer_instance_list,
2424 cJSON *layer_node, layer_json_version version, cJSON *item, cJSON *disable_environment,
2425 bool is_implicit, char *filename) {
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002426 char *temp;
Mark Youngf2079b92017-05-02 10:49:46 -06002427 char *name, *type, *library_path_str, *api_version;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002428 char *implementation_version, *description;
Mark Youngf2079b92017-05-02 10:49:46 -06002429 cJSON *ext_item, *library_path, *component_layers;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002430 VkExtensionProperties ext_prop;
Mark Youngf2079b92017-05-02 10:49:46 -06002431 VkResult result = VK_ERROR_INITIALIZATION_FAILED;
2432 struct loader_layer_properties *props = NULL;
2433 int i, j;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002434
Mark Young0f183a82017-02-28 09:58:04 -07002435// The following are required in the "layer" object:
2436// (required) "name"
2437// (required) "type"
Nekotekinad431e132017-06-11 13:13:07 +03002438// (required) "library_path"
2439// (required) "api_version"
2440// (required) "implementation_version"
2441// (required) "description"
2442// (required for implicit layers) "disable_environment"
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002443#define GET_JSON_OBJECT(node, var) \
2444 { \
2445 var = cJSON_GetObjectItem(node, #var); \
2446 if (var == NULL) { \
2447 layer_node = layer_node->next; \
2448 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, \
2449 "Didn't find required layer object %s in manifest " \
2450 "JSON file, skipping this layer", \
2451 #var); \
Mark Youngf2079b92017-05-02 10:49:46 -06002452 goto out; \
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002453 } \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002454 }
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002455#define GET_JSON_ITEM(node, var) \
2456 { \
2457 item = cJSON_GetObjectItem(node, #var); \
2458 if (item == NULL) { \
2459 layer_node = layer_node->next; \
2460 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, \
2461 "Didn't find required layer value %s in manifest JSON " \
2462 "file, skipping this layer", \
2463 #var); \
Mark Youngf2079b92017-05-02 10:49:46 -06002464 goto out; \
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002465 } \
2466 temp = cJSON_Print(item); \
2467 if (temp == NULL) { \
2468 layer_node = layer_node->next; \
2469 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, \
2470 "Problem accessing layer value %s in manifest JSON " \
2471 "file, skipping this layer", \
2472 #var); \
Mark Youngf2079b92017-05-02 10:49:46 -06002473 result = VK_ERROR_OUT_OF_HOST_MEMORY; \
2474 goto out; \
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002475 } \
2476 temp[strlen(temp) - 1] = '\0'; \
2477 var = loader_stack_alloc(strlen(temp) + 1); \
2478 strcpy(var, &temp[1]); \
2479 cJSON_Free(temp); \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002480 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002481 GET_JSON_ITEM(layer_node, name)
2482 GET_JSON_ITEM(layer_node, type)
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002483 GET_JSON_ITEM(layer_node, api_version)
2484 GET_JSON_ITEM(layer_node, implementation_version)
2485 GET_JSON_ITEM(layer_node, description)
Mark Youngf2079b92017-05-02 10:49:46 -06002486
2487 // Add list entry
2488 if (!strcmp(type, "DEVICE")) {
2489 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, "Device layers are deprecated skipping this layer");
2490 layer_node = layer_node->next;
2491 goto out;
2492 }
2493
2494 // Allow either GLOBAL or INSTANCE type interchangeably to handle
2495 // layers that must work with older loaders
2496 if (!strcmp(type, "INSTANCE") || !strcmp(type, "GLOBAL")) {
2497 if (layer_instance_list == NULL) {
2498 layer_node = layer_node->next;
2499 goto out;
2500 }
2501 props = loader_get_next_layer_property(inst, layer_instance_list);
2502 if (NULL == props) {
2503 // Error already triggered in loader_get_next_layer_property.
2504 result = VK_ERROR_OUT_OF_HOST_MEMORY;
2505 goto out;
2506 }
2507 props->type_flags = VK_LAYER_TYPE_FLAG_INSTANCE_LAYER;
2508 if (!is_implicit) {
2509 props->type_flags |= VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER;
2510 }
2511 } else {
2512 layer_node = layer_node->next;
2513 goto out;
2514 }
2515
2516 // Library path no longer required unless component_layers is also not defined
2517 library_path = cJSON_GetObjectItem(layer_node, "library_path");
2518 component_layers = cJSON_GetObjectItem(layer_node, "component_layers");
2519 if (NULL != library_path) {
2520 if (NULL != component_layers) {
2521 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2522 "Indicating meta-layer-specific component_layers, but also "
2523 "defining layer library path. Both are not compatible, so "
2524 "skipping this layer");
2525 goto out;
2526 }
2527 props->num_component_layers = 0;
2528 props->component_layer_names = NULL;
2529
2530 temp = cJSON_Print(library_path);
2531 if (NULL == temp) {
2532 layer_node = layer_node->next;
2533 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2534 "Problem accessing layer value library_path in manifest JSON "
2535 "file, skipping this layer");
2536 result = VK_ERROR_OUT_OF_HOST_MEMORY;
2537 goto out;
2538 }
2539 temp[strlen(temp) - 1] = '\0';
2540 library_path_str = loader_stack_alloc(strlen(temp) + 1);
2541 strcpy(library_path_str, &temp[1]);
2542 cJSON_Free(temp);
2543
2544 char *fullpath = props->lib_name;
2545 char *rel_base;
2546 if (NULL != library_path_str) {
2547 if (loader_platform_is_path(library_path_str)) {
2548 // A relative or absolute path
2549 char *name_copy = loader_stack_alloc(strlen(filename) + 1);
2550 strcpy(name_copy, filename);
2551 rel_base = loader_platform_dirname(name_copy);
2552 loader_expand_path(library_path_str, rel_base, MAX_STRING_SIZE, fullpath);
2553 } else {
2554 // A filename which is assumed in a system directory
2555 loader_get_fullpath(library_path_str, DEFAULT_VK_LAYERS_PATH, MAX_STRING_SIZE, fullpath);
2556 }
2557 }
2558 } else if (NULL != component_layers) {
2559 if (version.major == 1 && (version.minor < 1 || version.patch < 1)) {
2560 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2561 "Indicating meta-layer-specific component_layers, but using older "
2562 "JSON file version.");
2563 }
2564 int count = cJSON_GetArraySize(component_layers);
2565 props->num_component_layers = count;
2566
2567 // Allocate buffer for layer names
2568 props->component_layer_names =
2569 loader_instance_heap_alloc(inst, sizeof(char[MAX_STRING_SIZE]) * count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2570 if (NULL == props->component_layer_names) {
2571 result = VK_ERROR_OUT_OF_HOST_MEMORY;
2572 goto out;
2573 }
2574
2575 // Copy the component layers into the array
2576 for (i = 0; i < count; i++) {
2577 cJSON *comp_layer = cJSON_GetArrayItem(component_layers, i);
2578 if (NULL != comp_layer) {
2579 temp = cJSON_Print(comp_layer);
2580 if (NULL == temp) {
2581 result = VK_ERROR_OUT_OF_HOST_MEMORY;
2582 goto out;
2583 }
2584 temp[strlen(temp) - 1] = '\0';
2585 strncpy(props->component_layer_names[i], temp + 1, MAX_STRING_SIZE - 1);
2586 props->component_layer_names[i][MAX_STRING_SIZE - 1] = '\0';
2587 cJSON_Free(temp);
2588 }
2589 }
2590
2591 // This is now, officially, a meta-layer
2592 props->type_flags |= VK_LAYER_TYPE_FLAG_META_LAYER;
2593 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Encountered meta-layer %s", name);
2594
2595 // Make sure we set up other things so we head down the correct branches below
2596 library_path_str = NULL;
2597 } else {
2598 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2599 "Layer missing both library_path and component_layers fields. One or the "
2600 "other MUST be defined. Skipping this layer");
2601 goto out;
2602 }
2603
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002604 if (is_implicit) {
2605 GET_JSON_OBJECT(layer_node, disable_environment)
2606 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002607#undef GET_JSON_ITEM
2608#undef GET_JSON_OBJECT
2609
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002610 strncpy(props->info.layerName, name, sizeof(props->info.layerName));
2611 props->info.layerName[sizeof(props->info.layerName) - 1] = '\0';
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002612 props->info.specVersion = loader_make_version(api_version);
2613 props->info.implementationVersion = atoi(implementation_version);
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002614 strncpy((char *)props->info.description, description, sizeof(props->info.description));
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002615 props->info.description[sizeof(props->info.description) - 1] = '\0';
2616 if (is_implicit) {
2617 if (!disable_environment || !disable_environment->child) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002618 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2619 "Didn't find required layer child value disable_environment"
2620 "in manifest JSON file, skipping this layer");
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002621 layer_node = layer_node->next;
Mark Youngf2079b92017-05-02 10:49:46 -06002622 goto out;
Jon Ashburnfb8ac012015-08-12 16:39:32 -06002623 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002624 strncpy(props->disable_env_var.name, disable_environment->child->string, sizeof(props->disable_env_var.name));
2625 props->disable_env_var.name[sizeof(props->disable_env_var.name) - 1] = '\0';
2626 strncpy(props->disable_env_var.value, disable_environment->child->valuestring, sizeof(props->disable_env_var.value));
2627 props->disable_env_var.value[sizeof(props->disable_env_var.value) - 1] = '\0';
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002628 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002629
Mark Young0f183a82017-02-28 09:58:04 -07002630// Now get all optional items and objects and put in list:
2631// functions
2632// instance_extensions
2633// device_extensions
2634// enable_environment (implicit layers only)
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002635#define GET_JSON_OBJECT(node, var) \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002636 { var = cJSON_GetObjectItem(node, #var); }
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002637#define GET_JSON_ITEM(node, var) \
2638 { \
2639 item = cJSON_GetObjectItem(node, #var); \
2640 if (item != NULL) { \
2641 temp = cJSON_Print(item); \
2642 if (temp != NULL) { \
2643 temp[strlen(temp) - 1] = '\0'; \
2644 var = loader_stack_alloc(strlen(temp) + 1); \
2645 strcpy(var, &temp[1]); \
2646 cJSON_Free(temp); \
Mark Youngf2079b92017-05-02 10:49:46 -06002647 } else { \
2648 result = VK_ERROR_OUT_OF_HOST_MEMORY; \
2649 goto out; \
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002650 } \
2651 } \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002652 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002653
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002654 cJSON *instance_extensions, *device_extensions, *functions, *enable_environment;
Mark Young39389872017-01-19 21:10:49 -07002655 cJSON *entrypoints = NULL;
2656 char *vkGetInstanceProcAddr = NULL;
2657 char *vkGetDeviceProcAddr = NULL;
2658 char *vkNegotiateLoaderLayerInterfaceVersion = NULL;
2659 char *spec_version = NULL;
2660 char **entry_array = NULL;
Jon Ashburn075ce432015-12-17 17:38:24 -07002661
Mark Young39389872017-01-19 21:10:49 -07002662 // Layer interface functions
2663 // vkGetInstanceProcAddr
2664 // vkGetDeviceProcAddr
2665 // vkNegotiateLoaderLayerInterfaceVersion (starting with JSON file 1.1.0)
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002666 GET_JSON_OBJECT(layer_node, functions)
2667 if (functions != NULL) {
Mark Young39389872017-01-19 21:10:49 -07002668 if (version.major > 1 || version.minor >= 1) {
2669 GET_JSON_ITEM(functions, vkNegotiateLoaderLayerInterfaceVersion)
2670 if (vkNegotiateLoaderLayerInterfaceVersion != NULL)
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002671 strncpy(props->functions.str_negotiate_interface, vkNegotiateLoaderLayerInterfaceVersion,
Mark Young39389872017-01-19 21:10:49 -07002672 sizeof(props->functions.str_negotiate_interface));
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002673 props->functions.str_negotiate_interface[sizeof(props->functions.str_negotiate_interface) - 1] = '\0';
Mark Young39389872017-01-19 21:10:49 -07002674 } else {
2675 props->functions.str_negotiate_interface[0] = '\0';
2676 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002677 GET_JSON_ITEM(functions, vkGetInstanceProcAddr)
2678 GET_JSON_ITEM(functions, vkGetDeviceProcAddr)
Mark Young39389872017-01-19 21:10:49 -07002679 if (vkGetInstanceProcAddr != NULL) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002680 strncpy(props->functions.str_gipa, vkGetInstanceProcAddr, sizeof(props->functions.str_gipa));
Mark Young39389872017-01-19 21:10:49 -07002681 if (version.major > 1 || version.minor >= 1) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002682 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2683 "Indicating layer-specific vkGetInstanceProcAddr "
2684 "function is deprecated starting with JSON file "
2685 "version 1.1.0. Instead, use the new "
2686 "vkNegotiateLayerInterfaceVersion function to "
2687 "return the GetInstanceProcAddr function for this"
2688 "layer");
Mark Young39389872017-01-19 21:10:49 -07002689 }
2690 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002691 props->functions.str_gipa[sizeof(props->functions.str_gipa) - 1] = '\0';
Mark Young39389872017-01-19 21:10:49 -07002692 if (vkGetDeviceProcAddr != NULL) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002693 strncpy(props->functions.str_gdpa, vkGetDeviceProcAddr, sizeof(props->functions.str_gdpa));
Mark Young39389872017-01-19 21:10:49 -07002694 if (version.major > 1 || version.minor >= 1) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002695 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2696 "Indicating layer-specific vkGetDeviceProcAddr "
2697 "function is deprecated starting with JSON file "
2698 "version 1.1.0. Instead, use the new "
2699 "vkNegotiateLayerInterfaceVersion function to "
2700 "return the GetDeviceProcAddr function for this"
2701 "layer");
Mark Young39389872017-01-19 21:10:49 -07002702 }
2703 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002704 props->functions.str_gdpa[sizeof(props->functions.str_gdpa) - 1] = '\0';
2705 }
Mark Young39389872017-01-19 21:10:49 -07002706
2707 // instance_extensions
2708 // array of {
2709 // name
2710 // spec_version
2711 // }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002712 GET_JSON_OBJECT(layer_node, instance_extensions)
2713 if (instance_extensions != NULL) {
2714 int count = cJSON_GetArraySize(instance_extensions);
2715 for (i = 0; i < count; i++) {
2716 ext_item = cJSON_GetArrayItem(instance_extensions, i);
2717 GET_JSON_ITEM(ext_item, name)
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002718 if (name != NULL) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002719 strncpy(ext_prop.extensionName, name, sizeof(ext_prop.extensionName));
2720 ext_prop.extensionName[sizeof(ext_prop.extensionName) - 1] = '\0';
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002721 }
Mark Young0ad83132016-06-30 13:02:42 -06002722 GET_JSON_ITEM(ext_item, spec_version)
2723 if (NULL != spec_version) {
2724 ext_prop.specVersion = atoi(spec_version);
2725 } else {
2726 ext_prop.specVersion = 0;
2727 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002728 bool ext_unsupported = wsi_unsupported_instance_extension(&ext_prop);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002729 if (!ext_unsupported) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002730 loader_add_to_ext_list(inst, &props->instance_extension_list, 1, &ext_prop);
Jon Ashburn075ce432015-12-17 17:38:24 -07002731 }
Jon Ashburnfb8ac012015-08-12 16:39:32 -06002732 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002733 }
Mark Young39389872017-01-19 21:10:49 -07002734
2735 // device_extensions
2736 // array of {
2737 // name
2738 // spec_version
2739 // entrypoints
2740 // }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002741 GET_JSON_OBJECT(layer_node, device_extensions)
2742 if (device_extensions != NULL) {
2743 int count = cJSON_GetArraySize(device_extensions);
2744 for (i = 0; i < count; i++) {
2745 ext_item = cJSON_GetArrayItem(device_extensions, i);
2746 GET_JSON_ITEM(ext_item, name)
2747 GET_JSON_ITEM(ext_item, spec_version)
2748 if (name != NULL) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002749 strncpy(ext_prop.extensionName, name, sizeof(ext_prop.extensionName));
2750 ext_prop.extensionName[sizeof(ext_prop.extensionName) - 1] = '\0';
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002751 }
Mark Young0ad83132016-06-30 13:02:42 -06002752 if (NULL != spec_version) {
2753 ext_prop.specVersion = atoi(spec_version);
2754 } else {
2755 ext_prop.specVersion = 0;
2756 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002757 // entrypoints = cJSON_GetObjectItem(ext_item, "entrypoints");
2758 GET_JSON_OBJECT(ext_item, entrypoints)
2759 int entry_count;
2760 if (entrypoints == NULL) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002761 loader_add_to_dev_ext_list(inst, &props->device_extension_list, &ext_prop, 0, NULL);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002762 continue;
2763 }
2764 entry_count = cJSON_GetArraySize(entrypoints);
Mark Young0ad83132016-06-30 13:02:42 -06002765 if (entry_count) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002766 entry_array = (char **)loader_stack_alloc(sizeof(char *) * entry_count);
Mark Young0ad83132016-06-30 13:02:42 -06002767 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002768 for (j = 0; j < entry_count; j++) {
2769 ext_item = cJSON_GetArrayItem(entrypoints, j);
2770 if (ext_item != NULL) {
2771 temp = cJSON_Print(ext_item);
Mark Young0ad83132016-06-30 13:02:42 -06002772 if (NULL == temp) {
2773 entry_array[j] = NULL;
Mark Youngf2079b92017-05-02 10:49:46 -06002774 result = VK_ERROR_OUT_OF_HOST_MEMORY;
2775 goto out;
Mark Young0ad83132016-06-30 13:02:42 -06002776 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002777 temp[strlen(temp) - 1] = '\0';
2778 entry_array[j] = loader_stack_alloc(strlen(temp) + 1);
2779 strcpy(entry_array[j], &temp[1]);
Mark Young0ad83132016-06-30 13:02:42 -06002780 cJSON_Free(temp);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002781 }
2782 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002783 loader_add_to_dev_ext_list(inst, &props->device_extension_list, &ext_prop, entry_count, entry_array);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002784 }
2785 }
2786 if (is_implicit) {
2787 GET_JSON_OBJECT(layer_node, enable_environment)
2788
2789 // enable_environment is optional
2790 if (enable_environment) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002791 strncpy(props->enable_env_var.name, enable_environment->child->string, sizeof(props->enable_env_var.name));
2792 props->enable_env_var.name[sizeof(props->enable_env_var.name) - 1] = '\0';
2793 strncpy(props->enable_env_var.value, enable_environment->child->valuestring, sizeof(props->enable_env_var.value));
2794 props->enable_env_var.value[sizeof(props->enable_env_var.value) - 1] = '\0';
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002795 }
2796 }
Mark Youngf2079b92017-05-02 10:49:46 -06002797
Lenny Komow3cf3ac72017-12-19 16:38:37 -07002798 // Read in the pre-instance stuff
2799 cJSON *pre_instance = cJSON_GetObjectItem(layer_node, "pre_instance_functions");
2800 if (pre_instance) {
2801 if (!layer_json_supports_pre_instance_tag(&version)) {
2802 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2803 "Found pre_instance_functions section in layer from \"%s\". "
2804 "This section is only valid in manifest version 1.1.2 or later. The section will be ignored",
2805 filename);
2806 } else if (!is_implicit) {
2807 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2808 "Found pre_instance_functions section in explicit layer from "
2809 "\"%s\". This section is only valid in implicit layers. The section will be ignored",
2810 filename);
2811 } else {
2812 cJSON *inst_ext_json = cJSON_GetObjectItem(pre_instance, "vkEnumerateInstanceExtensionProperties");
2813 if (inst_ext_json) {
2814 char *inst_ext_name = cJSON_Print(inst_ext_json);
2815 size_t len = strlen(inst_ext_name) >= MAX_STRING_SIZE ? MAX_STRING_SIZE - 3 : strlen(inst_ext_name) - 2;
2816 strncpy(props->pre_instance_functions.enumerate_instance_extension_properties, inst_ext_name + 1, len);
2817 props->pre_instance_functions.enumerate_instance_extension_properties[len] = '\0';
2818 cJSON_Free(inst_ext_name);
2819 }
2820
2821 cJSON *inst_layer_json = cJSON_GetObjectItem(pre_instance, "vkEnumerateInstanceLayerProperties");
2822 if (inst_layer_json) {
2823 char *inst_layer_name = cJSON_Print(inst_layer_json);
2824 size_t len = strlen(inst_layer_name) >= MAX_STRING_SIZE ? MAX_STRING_SIZE - 3 : strlen(inst_layer_name) - 2;
2825 strncpy(props->pre_instance_functions.enumerate_instance_layer_properties, inst_layer_name + 1, len);
2826 props->pre_instance_functions.enumerate_instance_layer_properties[len] = '\0';
2827 cJSON_Free(inst_layer_name);
2828 }
2829 }
2830 }
2831
Mark Youngf2079b92017-05-02 10:49:46 -06002832 result = VK_SUCCESS;
2833
2834out:
2835
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002836#undef GET_JSON_ITEM
2837#undef GET_JSON_OBJECT
Mark Youngf2079b92017-05-02 10:49:46 -06002838
2839 if (VK_SUCCESS != result && NULL != props) {
2840 props->num_component_layers = 0;
2841 if (NULL != props->component_layer_names) {
2842 loader_instance_heap_free(inst, props->component_layer_names);
2843 }
2844 props->component_layer_names = NULL;
2845 }
2846
2847 return result;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002848}
2849
Mark Young0f183a82017-02-28 09:58:04 -07002850// Given a cJSON struct (json) of the top level JSON object from layer manifest
2851// file, add entry to the layer_list. Fill out the layer_properties in this list
2852// entry from the input cJSON object.
2853//
2854// \returns
2855// void
2856// layer_list has a new entry and initialized accordingly.
2857// If the json input object does not have all the required fields no entry
2858// is added to the list.
Mark Youngf2079b92017-05-02 10:49:46 -06002859static VkResult loader_add_layer_properties(const struct loader_instance *inst, struct loader_layer_list *layer_instance_list,
2860 cJSON *json, bool is_implicit, char *filename) {
Mark Young39389872017-01-19 21:10:49 -07002861 // The following Fields in layer manifest file that are required:
Nekotekinad431e132017-06-11 13:13:07 +03002862 // - "file_format_version"
Mark Young39389872017-01-19 21:10:49 -07002863 // - If more than one "layer" object are used, then the "layers" array is
Mark Youngdee312c2017-03-08 13:38:35 -07002864 // required
Mark Youngf2079b92017-05-02 10:49:46 -06002865 VkResult result = VK_ERROR_INITIALIZATION_FAILED;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002866 cJSON *item, *layers_node, *layer_node;
Mike Stroyan81908212017-03-14 13:09:12 -06002867 layer_json_version json_version = {0, 0, 0};
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002868 char *vers_tok;
2869 cJSON *disable_environment = NULL;
2870 item = cJSON_GetObjectItem(json, "file_format_version");
2871 if (item == NULL) {
Mark Youngf2079b92017-05-02 10:49:46 -06002872 goto out;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002873 }
2874 char *file_vers = cJSON_PrintUnformatted(item);
Mark Young0ad83132016-06-30 13:02:42 -06002875 if (NULL == file_vers) {
Mark Youngf2079b92017-05-02 10:49:46 -06002876 goto out;
Mark Young0ad83132016-06-30 13:02:42 -06002877 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002878 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 -06002879 // Get the major/minor/and patch as integers for easier comparison
2880 vers_tok = strtok(file_vers, ".\"\n\r");
2881 if (NULL != vers_tok) {
Mark Young39389872017-01-19 21:10:49 -07002882 json_version.major = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002883 vers_tok = strtok(NULL, ".\"\n\r");
2884 if (NULL != vers_tok) {
Mark Young39389872017-01-19 21:10:49 -07002885 json_version.minor = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002886 vers_tok = strtok(NULL, ".\"\n\r");
2887 if (NULL != vers_tok) {
Mark Young39389872017-01-19 21:10:49 -07002888 json_version.patch = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002889 }
2890 }
2891 }
Mark Young39389872017-01-19 21:10:49 -07002892
2893 if (!is_valid_layer_json_version(&json_version)) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002894 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2895 "loader_add_layer_properties: %s invalid layer "
Mark Youngf2079b92017-05-02 10:49:46 -06002896 "manifest file version %d.%d.%d. May cause errors.",
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002897 filename, json_version.major, json_version.minor, json_version.patch);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002898 }
Mark Young0ad83132016-06-30 13:02:42 -06002899 cJSON_Free(file_vers);
Mark Young39389872017-01-19 21:10:49 -07002900
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002901 // If "layers" is present, read in the array of layer objects
2902 layers_node = cJSON_GetObjectItem(json, "layers");
2903 if (layers_node != NULL) {
2904 int numItems = cJSON_GetArraySize(layers_node);
Mark Young39389872017-01-19 21:10:49 -07002905 if (!layer_json_supports_layers_tag(&json_version)) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002906 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2907 "loader_add_layer_properties: \'layers\' tag not "
2908 "supported until file version 1.0.1, but %s is "
2909 "reporting version %s",
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002910 filename, file_vers);
2911 }
2912 for (int curLayer = 0; curLayer < numItems; curLayer++) {
2913 layer_node = cJSON_GetArrayItem(layers_node, curLayer);
2914 if (layer_node == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002915 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2916 "loader_add_layer_properties: Can not find "
2917 "\'layers\' array element %d object in manifest "
2918 "JSON file %s. Skipping this file",
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002919 curLayer, filename);
Mark Youngf2079b92017-05-02 10:49:46 -06002920 goto out;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002921 }
Mark Youngf2079b92017-05-02 10:49:46 -06002922 result = loader_read_json_layer(inst, layer_instance_list, layer_node, json_version, item, disable_environment,
2923 is_implicit, filename);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002924 }
2925 } else {
2926 // Otherwise, try to read in individual layers
2927 layer_node = cJSON_GetObjectItem(json, "layer");
2928 if (layer_node == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002929 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2930 "loader_add_layer_properties: Can not find \'layer\' "
2931 "object in manifest JSON file %s. Skipping this file.",
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002932 filename);
Mark Youngf2079b92017-05-02 10:49:46 -06002933 goto out;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002934 }
2935 // Loop through all "layer" objects in the file to get a count of them
2936 // first.
2937 uint16_t layer_count = 0;
2938 cJSON *tempNode = layer_node;
2939 do {
2940 tempNode = tempNode->next;
2941 layer_count++;
2942 } while (tempNode != NULL);
Mark Young39389872017-01-19 21:10:49 -07002943
2944 // Throw a warning if we encounter multiple "layer" objects in file
2945 // versions newer than 1.0.0. Having multiple objects with the same
2946 // name at the same level is actually a JSON standard violation.
2947 if (layer_count > 1 && layer_json_supports_layers_tag(&json_version)) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002948 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2949 "loader_add_layer_properties: Multiple \'layer\' nodes"
2950 " are deprecated starting in file version \"1.0.1\". "
2951 "Please use \'layers\' : [] array instead in %s.",
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002952 filename);
2953 } else {
2954 do {
Mark Youngf2079b92017-05-02 10:49:46 -06002955 result = loader_read_json_layer(inst, layer_instance_list, layer_node, json_version, item, disable_environment,
2956 is_implicit, filename);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002957 layer_node = layer_node->next;
2958 } while (layer_node != NULL);
2959 }
2960 }
Mark Youngf2079b92017-05-02 10:49:46 -06002961
2962out:
2963
2964 return result;
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002965}
2966
Mark Young0f183a82017-02-28 09:58:04 -07002967// Find the Vulkan library manifest files.
2968//
2969// This function scans the "location" or "env_override" directories/files
2970// for a list of JSON manifest files. If env_override is non-NULL
2971// and has a valid value. Then the location is ignored. Otherwise
2972// location is used to look for manifest files. The location
2973// is interpreted as Registry path on Windows and a directory path(s)
2974// on Linux. "home_location" is an additional directory in the users home
2975// directory to look at. It is expanded into the dir path
2976// $XDG_DATA_HOME/home_location or $HOME/.local/share/home_location depending
2977// on environment variables. This "home_location" is only used on Linux.
2978//
2979// \returns
2980// VKResult
2981// A string list of manifest files to be opened in out_files param.
2982// List has a pointer to string for each manifest filename.
2983// When done using the list in out_files, pointers should be freed.
2984// Location or override string lists can be either files or directories as
Mark Youngf2079b92017-05-02 10:49:46 -06002985// follows:
Mark Young0f183a82017-02-28 09:58:04 -07002986// | location | override
2987// --------------------------------
2988// Win ICD | files | files
2989// Win Layer | files | dirs
2990// Linux ICD | dirs | files
2991// Linux Layer| dirs | dirs
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002992static 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 -06002993 bool is_layer, bool warn_if_not_present, const char *location,
2994 const char *relative_location, struct loader_manifest_files *out_files) {
Mark Youngbb3a29c2017-05-19 12:29:43 -06002995 const char *override = NULL;
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05002996 char *override_getenv = NULL;
Mark Young0ad83132016-06-30 13:02:42 -06002997 char *loc, *orig_loc = NULL;
2998 char *reg = NULL;
Jon Ashburn2077e382015-06-29 11:25:34 -06002999 char *file, *next_file, *name;
3000 size_t alloced_count = 64;
3001 char full_path[2048];
3002 DIR *sysdir = NULL;
Jon Ashburnffad94d2015-06-30 14:46:22 -07003003 bool list_is_dirs = false;
Jon Ashburn2077e382015-06-29 11:25:34 -06003004 struct dirent *dent;
Mark Young0ad83132016-06-30 13:02:42 -06003005 VkResult res = VK_SUCCESS;
Jon Ashburn2077e382015-06-29 11:25:34 -06003006
3007 out_files->count = 0;
3008 out_files->filename_list = NULL;
3009
Jamie Madill00c3c912016-04-06 18:26:46 -04003010 if (source_override != NULL) {
3011 override = source_override;
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05003012 } else if (env_override != NULL) {
Johannes van Waveren9bd805012015-10-28 11:45:00 -05003013#if !defined(_WIN32)
Jon Ashburncc407a22016-04-15 09:25:03 -06003014 if (geteuid() != getuid() || getegid() != getgid()) {
Mark Young0f183a82017-02-28 09:58:04 -07003015 // Don't allow setuid apps to use the env var:
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05003016 env_override = NULL;
Jon Ashburn2077e382015-06-29 11:25:34 -06003017 }
3018#endif
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05003019 if (env_override != NULL) {
Mark Youngd8c6b692017-03-09 11:39:41 -07003020 override = override_getenv = loader_secure_getenv(env_override, inst);
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05003021 }
Jon Ashburn2077e382015-06-29 11:25:34 -06003022 }
Jon Ashburnb6822212016-02-16 15:34:16 -07003023#if !defined(_WIN32)
Benjamin Saunders31a48012017-01-29 14:49:54 -08003024 if (relative_location == NULL) {
Jon Ashburnb6822212016-02-16 15:34:16 -07003025#else
Benjamin Saunders31a48012017-01-29 14:49:54 -08003026 relative_location = NULL;
Jon Ashburn2077e382015-06-29 11:25:34 -06003027 if (location == NULL) {
Jon Ashburnb6822212016-02-16 15:34:16 -07003028#endif
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003029 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3030 "loader_get_manifest_files: Can not get manifest files with "
3031 "NULL location, env_override=%s",
Mark Youngb6399312017-01-10 14:22:15 -07003032 (env_override != NULL) ? env_override : "");
Mark Young0ad83132016-06-30 13:02:42 -06003033 res = VK_ERROR_INITIALIZATION_FAILED;
3034 goto out;
Jon Ashburn2077e382015-06-29 11:25:34 -06003035 }
3036
Johannes van Waveren9bd805012015-10-28 11:45:00 -05003037#if defined(_WIN32)
Jon Ashburnffad94d2015-06-30 14:46:22 -07003038 list_is_dirs = (is_layer && override != NULL) ? true : false;
Johannes van Waveren9bd805012015-10-28 11:45:00 -05003039#else
3040 list_is_dirs = (override == NULL || is_layer) ? true : false;
Jon Ashburnffad94d2015-06-30 14:46:22 -07003041#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06003042 // Make a copy of the input we are using so it is not modified
Jon Ashburnffad94d2015-06-30 14:46:22 -07003043 // Also handle getting the location(s) from registry on Windows
3044 if (override == NULL) {
Benjamin Saunders31a48012017-01-29 14:49:54 -08003045 size_t loc_size = 0;
3046#if !defined(_WIN32)
Mark Youngd8c6b692017-03-09 11:39:41 -07003047 const char *xdgconfdirs = loader_secure_getenv("XDG_CONFIG_DIRS", inst);
3048 const char *xdgdatadirs = loader_secure_getenv("XDG_DATA_DIRS", inst);
Mark Youngf2079b92017-05-02 10:49:46 -06003049 if (xdgconfdirs == NULL || xdgconfdirs[0] == '\0') xdgconfdirs = FALLBACK_CONFIG_DIRS;
3050 if (xdgdatadirs == NULL || xdgdatadirs[0] == '\0') xdgdatadirs = FALLBACK_DATA_DIRS;
Benjamin Saunders31a48012017-01-29 14:49:54 -08003051 const size_t rel_size = strlen(relative_location);
3052 // Leave space for trailing separators
Mark Youngf2079b92017-05-02 10:49:46 -06003053 loc_size += strlen(xdgconfdirs) + strlen(xdgdatadirs) + 2 * rel_size + 2;
Benjamin Saunders31a48012017-01-29 14:49:54 -08003054 for (const char *x = xdgconfdirs; *x; ++x)
3055 if (*x == PATH_SEPARATOR) loc_size += rel_size;
3056 for (const char *x = xdgdatadirs; *x; ++x)
3057 if (*x == PATH_SEPARATOR) loc_size += rel_size;
3058 loc_size += strlen(SYSCONFDIR) + rel_size + 1;
3059#if defined(EXTRASYSCONFDIR)
3060 loc_size += strlen(EXTRASYSCONFDIR) + rel_size + 1;
3061#endif
Karl Schultz2e5ed332017-12-12 10:33:01 -05003062#if defined(__APPLE__)
3063 // For bundle path
3064 loc_size += MAXPATHLEN;
3065#endif
Benjamin Saunders31a48012017-01-29 14:49:54 -08003066#else
3067 loc_size += strlen(location) + 1;
3068#endif
3069 loc = loader_stack_alloc(loc_size);
Jon Ashburnffad94d2015-06-30 14:46:22 -07003070 if (loc == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003071 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3072 "loader_get_manifest_files: Failed to allocate "
3073 "%d bytes for manifest file location.",
Benjamin Saunders31a48012017-01-29 14:49:54 -08003074 loc_size);
Mark Young0ad83132016-06-30 13:02:42 -06003075 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3076 goto out;
Jon Ashburnffad94d2015-06-30 14:46:22 -07003077 }
Benjamin Saunders31a48012017-01-29 14:49:54 -08003078 char *loc_write = loc;
3079#if !defined(_WIN32)
3080 const char *loc_read;
Karl Schultz52f5daa2017-02-12 12:34:03 -07003081 size_t start, stop;
Benjamin Saunders31a48012017-01-29 14:49:54 -08003082
Karl Schultz2e5ed332017-12-12 10:33:01 -05003083#if defined(__APPLE__)
3084 // Add the bundle's Resources dir to the beginning of the search path.
3085 // Looks for manifests in the bundle first, before any system directories.
3086 CFBundleRef main_bundle = CFBundleGetMainBundle();
3087 if (NULL != main_bundle) {
3088 CFURLRef ref = CFBundleCopyResourcesDirectoryURL(main_bundle);
3089 if (NULL != ref) {
3090 if (CFURLGetFileSystemRepresentation(ref, TRUE, (UInt8 *)loc_write, loc_size)) {
3091 loc_write += strlen(loc_write);
3092 memcpy(loc_write, relative_location, rel_size);
3093 loc_write += rel_size;
3094 *loc_write++ = PATH_SEPARATOR;
3095 }
3096 CFRelease(ref);
3097 }
3098 }
3099#endif
Benjamin Saunders31a48012017-01-29 14:49:54 -08003100 loc_read = &xdgconfdirs[0];
Karl Schultz52f5daa2017-02-12 12:34:03 -07003101 start = 0;
3102 while (loc_read[start] != '\0') {
3103 while (loc_read[start] == PATH_SEPARATOR) {
3104 start++;
3105 }
3106 stop = start;
3107 while (loc_read[stop] != PATH_SEPARATOR && loc_read[stop] != '\0') {
3108 stop++;
3109 }
3110 const size_t s = stop - start;
3111 if (s) {
3112 memcpy(loc_write, &loc_read[start], s);
Benjamin Saunders31a48012017-01-29 14:49:54 -08003113 loc_write += s;
3114 memcpy(loc_write, relative_location, rel_size);
3115 loc_write += rel_size;
3116 *loc_write++ = PATH_SEPARATOR;
Karl Schultz52f5daa2017-02-12 12:34:03 -07003117 start = stop;
Benjamin Saunders31a48012017-01-29 14:49:54 -08003118 }
3119 }
3120
3121 memcpy(loc_write, SYSCONFDIR, strlen(SYSCONFDIR));
3122 loc_write += strlen(SYSCONFDIR);
3123 memcpy(loc_write, relative_location, rel_size);
3124 loc_write += rel_size;
3125 *loc_write++ = PATH_SEPARATOR;
3126
3127#if defined(EXTRASYSCONFDIR)
3128 memcpy(loc_write, EXTRASYSCONFDIR, strlen(EXTRASYSCONFDIR));
3129 loc_write += strlen(EXTRASYSCONFDIR);
3130 memcpy(loc_write, relative_location, rel_size);
3131 loc_write += rel_size;
3132 *loc_write++ = PATH_SEPARATOR;
3133#endif
3134
3135 loc_read = &xdgdatadirs[0];
Karl Schultz52f5daa2017-02-12 12:34:03 -07003136 start = 0;
3137 while (loc_read[start] != '\0') {
3138 while (loc_read[start] == PATH_SEPARATOR) {
3139 start++;
3140 }
3141 stop = start;
3142 while (loc_read[stop] != PATH_SEPARATOR && loc_read[stop] != '\0') {
3143 stop++;
3144 }
3145 const size_t s = stop - start;
3146 if (s) {
3147 memcpy(loc_write, &loc_read[start], s);
Benjamin Saunders31a48012017-01-29 14:49:54 -08003148 loc_write += s;
3149 memcpy(loc_write, relative_location, rel_size);
3150 loc_write += rel_size;
3151 *loc_write++ = PATH_SEPARATOR;
Karl Schultz52f5daa2017-02-12 12:34:03 -07003152 start = stop;
Benjamin Saunders31a48012017-01-29 14:49:54 -08003153 }
3154 }
Karl Schultz52f5daa2017-02-12 12:34:03 -07003155
Benjamin Saunders31a48012017-01-29 14:49:54 -08003156 --loc_write;
3157#else
3158 memcpy(loc_write, location, strlen(location));
3159 loc_write += strlen(location);
3160#endif
3161 assert(loc_write - loc < (ptrdiff_t)loc_size);
3162 *loc_write = '\0';
3163
Johannes van Waveren9bd805012015-10-28 11:45:00 -05003164#if defined(_WIN32)
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +02003165 VkResult regHKR_result = VK_SUCCESS;
3166
Slawomir Cygan8f9f2552017-08-09 11:36:52 +02003167 DWORD reg_size = 4096;
3168
Norbert Garnys7dc9a592018-02-13 16:32:03 +01003169 // These calls look at the PNP/Device section of the registry.
Lenny Komowf7c09382017-08-31 16:35:08 -06003170 if (!strncmp(loc, DEFAULT_VK_DRIVERS_INFO, sizeof(DEFAULT_VK_DRIVERS_INFO))) {
3171 regHKR_result = loaderGetDeviceRegistryFiles(inst, &reg, &reg_size, LoaderPnpDriverRegistry());
3172 } else if (!strncmp(loc, DEFAULT_VK_ELAYERS_INFO, sizeof(DEFAULT_VK_ELAYERS_INFO))) {
3173 regHKR_result = loaderGetDeviceRegistryFiles(inst, &reg, &reg_size, LoaderPnpELayerRegistry());
3174 } else if (!strncmp(loc, DEFAULT_VK_ILAYERS_INFO, sizeof(DEFAULT_VK_ILAYERS_INFO))) {
3175 regHKR_result = loaderGetDeviceRegistryFiles(inst, &reg, &reg_size, LoaderPnpILayerRegistry());
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +02003176 }
3177
Norbert Garnys7dc9a592018-02-13 16:32:03 +01003178 // This call looks into the Khronos non-device specific section of the registry.
Slawomir Cygan8f9f2552017-08-09 11:36:52 +02003179 VkResult reg_result = loaderGetRegistryFiles(inst, loc, is_layer, &reg, &reg_size);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +02003180
3181 if ((VK_SUCCESS != reg_result && VK_SUCCESS != regHKR_result) || NULL == reg) {
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07003182 if (!is_layer) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003183 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3184 "loader_get_manifest_files: Registry lookup failed "
3185 "to get ICD manifest files. Possibly missing Vulkan"
3186 " driver?");
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +02003187 if (VK_SUCCESS == regHKR_result || VK_ERROR_OUT_OF_HOST_MEMORY == regHKR_result) {
3188 res = regHKR_result;
3189 } else if (VK_SUCCESS == reg_result || VK_ERROR_OUT_OF_HOST_MEMORY == reg_result) {
Mark Young2c84c0c2017-01-13 10:27:03 -07003190 res = reg_result;
3191 } else {
3192 res = VK_ERROR_INCOMPATIBLE_DRIVER;
3193 }
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07003194 } else {
Mark Youngf8c20102016-11-07 16:26:17 -07003195 if (warn_if_not_present) {
Mark Young2c84c0c2017-01-13 10:27:03 -07003196 // This is only a warning for layers
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003197 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3198 "loader_get_manifest_files: Registry lookup failed "
3199 "to get layer manifest files.");
Mark Youngf8c20102016-11-07 16:26:17 -07003200 }
Mark Young2c84c0c2017-01-13 10:27:03 -07003201 if (reg_result == VK_ERROR_OUT_OF_HOST_MEMORY) {
3202 res = reg_result;
3203 } else {
3204 // Return success for now since it's not critical for layers
3205 res = VK_SUCCESS;
3206 }
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07003207 }
Mark Young0ad83132016-06-30 13:02:42 -06003208 goto out;
Jon Ashburn24265ac2015-07-31 09:33:21 -06003209 }
Mark Young0ad83132016-06-30 13:02:42 -06003210 orig_loc = loc;
3211 loc = reg;
Jon Ashburnffad94d2015-06-30 14:46:22 -07003212#endif
Jon Ashburn23d36b12016-02-02 17:47:28 -07003213 } else {
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -06003214 loc = loader_stack_alloc(strlen(override) + 1);
Jon Ashburnffad94d2015-06-30 14:46:22 -07003215 if (loc == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003216 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3217 "loader_get_manifest_files: Failed to allocate space for "
3218 "override environment variable of length %d",
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003219 strlen(override) + 1);
Mark Young0ad83132016-06-30 13:02:42 -06003220 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3221 goto out;
Jon Ashburnffad94d2015-06-30 14:46:22 -07003222 }
3223 strcpy(loc, override);
3224 }
Jon Ashburn2077e382015-06-29 11:25:34 -06003225
Liam Middlebrook9b14e892015-07-23 18:32:20 -07003226 // Print out the paths being searched if debugging is enabled
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003227 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 -07003228
Jon Ashburn2077e382015-06-29 11:25:34 -06003229 file = loc;
3230 while (*file) {
3231 next_file = loader_get_next_path(file);
Jon Ashburnffad94d2015-06-30 14:46:22 -07003232 if (list_is_dirs) {
Jon Ashburn2077e382015-06-29 11:25:34 -06003233 sysdir = opendir(file);
3234 name = NULL;
3235 if (sysdir) {
3236 dent = readdir(sysdir);
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003237 if (dent == NULL) break;
Jon Ashburn2077e382015-06-29 11:25:34 -06003238 name = &(dent->d_name[0]);
3239 loader_get_fullpath(name, file, sizeof(full_path), full_path);
3240 name = full_path;
3241 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07003242 } else {
Johannes van Waveren9bd805012015-10-28 11:45:00 -05003243#if defined(_WIN32)
3244 name = file;
3245#else
Jon Ashburnffad94d2015-06-30 14:46:22 -07003246 // only Linux has relative paths
Jon Ashburn2077e382015-06-29 11:25:34 -06003247 char *dir;
3248 // make a copy of location so it isn't modified
Jason Ekstrandcc7550e2015-10-10 08:33:37 -07003249 dir = loader_stack_alloc(strlen(loc) + 1);
Jon Ashburn2077e382015-06-29 11:25:34 -06003250 if (dir == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003251 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3252 "loader_get_manifest_files: Failed to allocate "
3253 "space for relative location path length %d",
Mark Youngb6399312017-01-10 14:22:15 -07003254 strlen(loc) + 1);
Mark Young0ad83132016-06-30 13:02:42 -06003255 goto out;
Jon Ashburn2077e382015-06-29 11:25:34 -06003256 }
Jason Ekstrandcc7550e2015-10-10 08:33:37 -07003257 strcpy(dir, loc);
Jon Ashburn2077e382015-06-29 11:25:34 -06003258
3259 loader_get_fullpath(file, dir, sizeof(full_path), full_path);
3260
3261 name = full_path;
Jon Ashburnffad94d2015-06-30 14:46:22 -07003262#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06003263 }
3264 while (name) {
Mark Young0f183a82017-02-28 09:58:04 -07003265 // Look for files ending with ".json" suffix
Jon Ashburn23d36b12016-02-02 17:47:28 -07003266 uint32_t nlen = (uint32_t)strlen(name);
3267 const char *suf = name + nlen - 5;
Lenny Komow408e0bd2017-08-09 16:01:59 -06003268
3269 // Check if the file is already present
3270 bool file_already_loaded = false;
3271 for (uint32_t i = 0; i < out_files->count; ++i) {
3272 if (!strcmp(out_files->filename_list[i], name)) {
3273 file_already_loaded = true;
3274 }
3275 }
3276
3277 if (!file_already_loaded && (nlen > 5) && !strncmp(suf, ".json", 5)) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003278 if (out_files->count == 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003279 out_files->filename_list =
3280 loader_instance_heap_alloc(inst, alloced_count * sizeof(char *), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Mark Youngbb3a29c2017-05-19 12:29:43 -06003281 if (NULL == out_files->filename_list) {
3282 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3283 "loader_get_manifest_files: Failed to allocate space for manifest file name list");
3284 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3285 goto out;
3286 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07003287 } else if (out_files->count == alloced_count) {
Mark Youngbb3a29c2017-05-19 12:29:43 -06003288 void *new_ptr =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003289 loader_instance_heap_realloc(inst, out_files->filename_list, alloced_count * sizeof(char *),
3290 alloced_count * sizeof(char *) * 2, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Mark Youngbb3a29c2017-05-19 12:29:43 -06003291 if (NULL == new_ptr) {
3292 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3293 "loader_get_manifest_files: Failed to reallocate space for manifest file name list");
3294 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3295 goto out;
3296 }
3297 out_files->filename_list = new_ptr;
Jon Ashburn23d36b12016-02-02 17:47:28 -07003298 alloced_count *= 2;
Jon Ashburn2077e382015-06-29 11:25:34 -06003299 }
Mark Young0ad83132016-06-30 13:02:42 -06003300 out_files->filename_list[out_files->count] =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003301 loader_instance_heap_alloc(inst, strlen(name) + 1, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Jon Ashburn23d36b12016-02-02 17:47:28 -07003302 if (out_files->filename_list[out_files->count] == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003303 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3304 "loader_get_manifest_files: Failed to allocate "
3305 "space for manifest file %d list",
Mark Youngb6399312017-01-10 14:22:15 -07003306 out_files->count);
Mark Young0ad83132016-06-30 13:02:42 -06003307 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3308 goto out;
Jon Ashburn23d36b12016-02-02 17:47:28 -07003309 }
3310 strcpy(out_files->filename_list[out_files->count], name);
3311 out_files->count++;
Lenny Komow408e0bd2017-08-09 16:01:59 -06003312 } else if(file_already_loaded) {
3313 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3314 "Skipping manifest file %s - The file has already been read once", name);
Jon Ashburn23d36b12016-02-02 17:47:28 -07003315 } else if (!list_is_dirs) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003316 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, "Skipping manifest file %s, file name must end in .json",
3317 name);
Jon Ashburn23d36b12016-02-02 17:47:28 -07003318 }
3319 if (list_is_dirs) {
3320 dent = readdir(sysdir);
Mark Young0ad83132016-06-30 13:02:42 -06003321 if (dent == NULL) {
Jon Ashburn2077e382015-06-29 11:25:34 -06003322 break;
Mark Young0ad83132016-06-30 13:02:42 -06003323 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07003324 name = &(dent->d_name[0]);
3325 loader_get_fullpath(name, file, sizeof(full_path), full_path);
3326 name = full_path;
3327 } else {
3328 break;
3329 }
Jon Ashburn2077e382015-06-29 11:25:34 -06003330 }
Mark Young0ad83132016-06-30 13:02:42 -06003331 if (sysdir) {
Jon Ashburn2077e382015-06-29 11:25:34 -06003332 closedir(sysdir);
Mark Young0ad83132016-06-30 13:02:42 -06003333 sysdir = NULL;
3334 }
Jon Ashburn2077e382015-06-29 11:25:34 -06003335 file = next_file;
Jon Ashburn67e262e2016-02-18 12:45:39 -07003336#if !defined(_WIN32)
Benjamin Saunders31a48012017-01-29 14:49:54 -08003337 if (relative_location != NULL && (next_file == NULL || *next_file == '\0') && override == NULL) {
Mark Youngd8c6b692017-03-09 11:39:41 -07003338 char *xdgdatahome = loader_secure_getenv("XDG_DATA_HOME", inst);
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003339 size_t len;
3340 if (xdgdatahome != NULL) {
Mark Young6ef95f42017-02-17 09:02:23 -07003341 size_t alloc_len = strlen(xdgdatahome) + 2 + strlen(relative_location);
3342 char *home_loc = loader_stack_alloc(alloc_len);
Jon Ashburn67e262e2016-02-18 12:45:39 -07003343 if (home_loc == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003344 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3345 "loader_get_manifest_files: Failed to allocate "
3346 "space for manifest file XDG Home location");
Mark Young0ad83132016-06-30 13:02:42 -06003347 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3348 goto out;
Jon Ashburn67e262e2016-02-18 12:45:39 -07003349 }
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003350 strcpy(home_loc, xdgdatahome);
Jon Ashburn67e262e2016-02-18 12:45:39 -07003351 // Add directory separator if needed
Benjamin Saunders31a48012017-01-29 14:49:54 -08003352 if (relative_location[0] != DIRECTORY_SYMBOL) {
Jon Ashburn67e262e2016-02-18 12:45:39 -07003353 len = strlen(home_loc);
3354 home_loc[len] = DIRECTORY_SYMBOL;
Jon Ashburn1530c342016-02-26 13:14:27 -07003355 home_loc[len + 1] = '\0';
Jon Ashburn67e262e2016-02-18 12:45:39 -07003356 }
Mark Young6ef95f42017-02-17 09:02:23 -07003357 strncat(home_loc, relative_location, alloc_len);
Jon Ashburn67e262e2016-02-18 12:45:39 -07003358 file = home_loc;
3359 next_file = loader_get_next_path(file);
Benjamin Saunders31a48012017-01-29 14:49:54 -08003360 relative_location = NULL;
Jon Ashburn67e262e2016-02-18 12:45:39 -07003361
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003362 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Searching the following path for manifest files: %s\n",
3363 home_loc);
Jon Ashburn67e262e2016-02-18 12:45:39 -07003364 list_is_dirs = true;
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003365
3366 } else {
Mark Youngd8c6b692017-03-09 11:39:41 -07003367 char *home = loader_secure_getenv("HOME", inst);
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003368 if (home != NULL) {
Mark Young6ef95f42017-02-17 09:02:23 -07003369 size_t alloc_len = strlen(home) + 16 + strlen(relative_location);
3370 char *home_loc = loader_stack_alloc(alloc_len);
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003371 if (home_loc == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003372 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3373 "loader_get_manifest_files: Failed to allocate "
3374 "space for manifest file Home location");
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003375 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3376 goto out;
3377 }
Mark Young6ef95f42017-02-17 09:02:23 -07003378 strncpy(home_loc, home, alloc_len);
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003379
3380 len = strlen(home);
3381 if (home[len] != DIRECTORY_SYMBOL) {
3382 home_loc[len] = DIRECTORY_SYMBOL;
3383 home_loc[len + 1] = '\0';
3384 }
Mark Young6ef95f42017-02-17 09:02:23 -07003385 strncat(home_loc, ".local/share", alloc_len);
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003386
Benjamin Saunders31a48012017-01-29 14:49:54 -08003387 if (relative_location[0] != DIRECTORY_SYMBOL) {
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003388 len = strlen(home_loc);
3389 home_loc[len] = DIRECTORY_SYMBOL;
3390 home_loc[len + 1] = '\0';
3391 }
Mark Young6ef95f42017-02-17 09:02:23 -07003392 strncat(home_loc, relative_location, alloc_len);
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003393 file = home_loc;
3394 next_file = loader_get_next_path(file);
Benjamin Saunders31a48012017-01-29 14:49:54 -08003395 relative_location = NULL;
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003396
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003397 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Searching the following path for manifest files: %s\n",
3398 home_loc);
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003399 list_is_dirs = true;
3400 } else {
3401 // without knowing HOME, we just.. give up
3402 }
Jon Ashburn67e262e2016-02-18 12:45:39 -07003403 }
3404 }
3405#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06003406 }
Mark Young0ad83132016-06-30 13:02:42 -06003407
3408out:
3409 if (VK_SUCCESS != res && NULL != out_files->filename_list) {
3410 for (uint32_t remove = 0; remove < out_files->count; remove++) {
3411 loader_instance_heap_free(inst, out_files->filename_list[remove]);
3412 }
3413 loader_instance_heap_free(inst, out_files->filename_list);
3414 out_files->count = 0;
3415 out_files->filename_list = NULL;
3416 }
3417
3418 if (NULL != sysdir) {
3419 closedir(sysdir);
3420 }
3421
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05003422 if (override_getenv != NULL) {
3423 loader_free_getenv(override_getenv, inst);
3424 }
3425
Mark Young0ad83132016-06-30 13:02:42 -06003426 if (NULL != reg && reg != orig_loc) {
3427 loader_instance_heap_free(inst, reg);
3428 }
3429 return res;
Jon Ashburn2077e382015-06-29 11:25:34 -06003430}
3431
Jon Ashburn23d36b12016-02-02 17:47:28 -07003432void loader_init_icd_lib_list() {}
Jon Ashburn8810c5f2015-08-18 18:04:47 -06003433
Jon Ashburn23d36b12016-02-02 17:47:28 -07003434void loader_destroy_icd_lib_list() {}
Mark Young0f183a82017-02-28 09:58:04 -07003435
3436// Try to find the Vulkan ICD driver(s).
3437//
3438// This function scans the default system loader path(s) or path
3439// specified by the \c VK_ICD_FILENAMES environment variable in
3440// order to find loadable VK ICDs manifest files. From these
3441// manifest files it finds the ICD libraries.
3442//
3443// \returns
3444// Vulkan result
3445// (on result == VK_SUCCESS) a list of icds that were discovered
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003446VkResult loader_icd_scan(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list) {
Jon Ashburn2077e382015-06-29 11:25:34 -06003447 char *file_str;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003448 uint16_t file_major_vers = 0;
3449 uint16_t file_minor_vers = 0;
3450 uint16_t file_patch_vers = 0;
3451 char *vers_tok;
Jon Ashburn2077e382015-06-29 11:25:34 -06003452 struct loader_manifest_files manifest_files;
Mark Young0ad83132016-06-30 13:02:42 -06003453 VkResult res = VK_SUCCESS;
3454 bool lockedMutex = false;
3455 cJSON *json = NULL;
Mark Young3a587792016-08-19 15:25:08 -06003456 uint32_t num_good_icds = 0;
Jon Ashburn2077e382015-06-29 11:25:34 -06003457
Mark Young0ad83132016-06-30 13:02:42 -06003458 memset(&manifest_files, 0, sizeof(struct loader_manifest_files));
3459
Mark Young0153e0b2016-11-03 14:27:13 -06003460 res = loader_scanned_icd_init(inst, icd_tramp_list);
Mark Young0ad83132016-06-30 13:02:42 -06003461 if (VK_SUCCESS != res) {
3462 goto out;
3463 }
3464
Jon Ashburn2077e382015-06-29 11:25:34 -06003465 // Get a list of manifest files for ICDs
Benjamin Saunders31a48012017-01-29 14:49:54 -08003466 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 -07003467 &manifest_files);
Mark Young0ad83132016-06-30 13:02:42 -06003468 if (VK_SUCCESS != res || manifest_files.count == 0) {
3469 goto out;
3470 }
Mark Youngf2079b92017-05-02 10:49:46 -06003471
Jon Ashburn6461ef22015-09-22 13:11:00 -06003472 loader_platform_thread_lock_mutex(&loader_json_lock);
Mark Young0ad83132016-06-30 13:02:42 -06003473 lockedMutex = true;
Jon Ashburn2077e382015-06-29 11:25:34 -06003474 for (uint32_t i = 0; i < manifest_files.count; i++) {
3475 file_str = manifest_files.filename_list[i];
Mark Young0ad83132016-06-30 13:02:42 -06003476 if (file_str == NULL) {
Jon Ashburn2077e382015-06-29 11:25:34 -06003477 continue;
Mark Young0ad83132016-06-30 13:02:42 -06003478 }
Jon Ashburn2077e382015-06-29 11:25:34 -06003479
Mark Youngdcd5f7e2017-04-25 10:35:54 -06003480 VkResult temp_res = loader_get_json(inst, file_str, &json);
3481 if (NULL == json || temp_res != VK_SUCCESS) {
Mark Youngd66edd52017-03-10 17:31:18 -07003482 if (NULL != json) {
3483 cJSON_Delete(json);
3484 json = NULL;
3485 }
Mark Youngdcd5f7e2017-04-25 10:35:54 -06003486 // If we haven't already found an ICD, copy this result to
3487 // the returned result.
3488 if (num_good_icds == 0) {
3489 res = temp_res;
3490 }
3491 if (temp_res == VK_ERROR_OUT_OF_HOST_MEMORY) {
Mark Youngd66edd52017-03-10 17:31:18 -07003492 break;
3493 } else {
3494 continue;
3495 }
Mark Young0ad83132016-06-30 13:02:42 -06003496 }
Mark Youngdcd5f7e2017-04-25 10:35:54 -06003497 res = temp_res;
Mark Young3a587792016-08-19 15:25:08 -06003498
Jon Ashburn005617f2015-11-17 17:35:40 -07003499 cJSON *item, *itemICD;
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003500 item = cJSON_GetObjectItem(json, "file_format_version");
Jon Ashburn6461ef22015-09-22 13:11:00 -06003501 if (item == NULL) {
Mark Young3a587792016-08-19 15:25:08 -06003502 if (num_good_icds == 0) {
3503 res = VK_ERROR_INITIALIZATION_FAILED;
3504 }
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003505 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3506 "loader_icd_scan: ICD JSON %s does not have a"
3507 " \'file_format_version\' field. Skipping ICD JSON.",
Mark Youngb6399312017-01-10 14:22:15 -07003508 file_str);
Derrick Owens62e16ef2016-09-09 15:49:07 -04003509 cJSON_Delete(json);
3510 json = NULL;
Mark Young3a587792016-08-19 15:25:08 -06003511 continue;
Jon Ashburn6461ef22015-09-22 13:11:00 -06003512 }
Mark Youngd66edd52017-03-10 17:31:18 -07003513
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003514 char *file_vers = cJSON_Print(item);
Mark Young0ad83132016-06-30 13:02:42 -06003515 if (NULL == file_vers) {
Mark Youngd66edd52017-03-10 17:31:18 -07003516 // Only reason the print can fail is if there was an allocation issue
Mark Young3a587792016-08-19 15:25:08 -06003517 if (num_good_icds == 0) {
3518 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3519 }
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003520 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3521 "loader_icd_scan: Failed retrieving ICD JSON %s"
3522 " \'file_format_version\' field. Skipping ICD JSON",
Mark Youngb6399312017-01-10 14:22:15 -07003523 file_str);
Derrick Owenscd92b8b2016-09-09 15:45:13 -04003524 cJSON_Delete(json);
3525 json = NULL;
Mark Young3a587792016-08-19 15:25:08 -06003526 continue;
Mark Young0ad83132016-06-30 13:02:42 -06003527 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003528 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 -07003529
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003530 // Get the major/minor/and patch as integers for easier comparison
3531 vers_tok = strtok(file_vers, ".\"\n\r");
3532 if (NULL != vers_tok) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04003533 file_major_vers = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003534 vers_tok = strtok(NULL, ".\"\n\r");
3535 if (NULL != vers_tok) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04003536 file_minor_vers = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003537 vers_tok = strtok(NULL, ".\"\n\r");
3538 if (NULL != vers_tok) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04003539 file_patch_vers = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003540 }
3541 }
3542 }
Mark Youngd66edd52017-03-10 17:31:18 -07003543
3544 if (file_major_vers != 1 || file_minor_vers != 0 || file_patch_vers > 1) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003545 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3546 "loader_icd_scan: Unexpected manifest file version "
3547 "(expected 1.0.0 or 1.0.1), may cause errors");
Mark Youngd66edd52017-03-10 17:31:18 -07003548 }
Mark Young0ad83132016-06-30 13:02:42 -06003549 cJSON_Free(file_vers);
Mark Youngd66edd52017-03-10 17:31:18 -07003550
Jon Ashburn005617f2015-11-17 17:35:40 -07003551 itemICD = cJSON_GetObjectItem(json, "ICD");
3552 if (itemICD != NULL) {
3553 item = cJSON_GetObjectItem(itemICD, "library_path");
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003554 if (item != NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003555 char *temp = cJSON_Print(item);
Jon Ashburn86251302015-08-25 16:48:24 -06003556 if (!temp || strlen(temp) == 0) {
Mark Young3a587792016-08-19 15:25:08 -06003557 if (num_good_icds == 0) {
3558 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3559 }
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003560 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3561 "loader_icd_scan: Failed retrieving ICD JSON %s"
3562 " \'library_path\' field. Skipping ICD JSON.",
Mark Youngb6399312017-01-10 14:22:15 -07003563 file_str);
Mark Young0ad83132016-06-30 13:02:42 -06003564 cJSON_Free(temp);
Jon Ashburn86251302015-08-25 16:48:24 -06003565 cJSON_Delete(json);
Mark Young0ad83132016-06-30 13:02:42 -06003566 json = NULL;
Jon Ashburn86251302015-08-25 16:48:24 -06003567 continue;
Jon Ashburn2077e382015-06-29 11:25:34 -06003568 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07003569 // strip out extra quotes
Jon Ashburn86251302015-08-25 16:48:24 -06003570 temp[strlen(temp) - 1] = '\0';
3571 char *library_path = loader_stack_alloc(strlen(temp) + 1);
Mark Young3a587792016-08-19 15:25:08 -06003572 if (NULL == library_path) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003573 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3574 "loader_icd_scan: Failed to allocate space for "
3575 "ICD JSON %s \'library_path\' value. Skipping "
3576 "ICD JSON.",
Mark Youngb6399312017-01-10 14:22:15 -07003577 file_str);
Mark Young3a587792016-08-19 15:25:08 -06003578 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3579 cJSON_Free(temp);
3580 cJSON_Delete(json);
3581 json = NULL;
3582 goto out;
3583 }
Jon Ashburn86251302015-08-25 16:48:24 -06003584 strcpy(library_path, &temp[1]);
Mark Young0ad83132016-06-30 13:02:42 -06003585 cJSON_Free(temp);
Mark Young3a587792016-08-19 15:25:08 -06003586 if (strlen(library_path) == 0) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003587 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3588 "loader_icd_scan: ICD JSON %s \'library_path\'"
3589 " field is empty. Skipping ICD JSON.",
Jon Ashburn23d36b12016-02-02 17:47:28 -07003590 file_str);
Jon Ashburn86251302015-08-25 16:48:24 -06003591 cJSON_Delete(json);
Mark Young0ad83132016-06-30 13:02:42 -06003592 json = NULL;
Jon Ashburn86251302015-08-25 16:48:24 -06003593 continue;
3594 }
Jamie Madill2fcbd152016-04-27 16:33:23 -04003595 char fullpath[MAX_STRING_SIZE];
Jon Ashburn86251302015-08-25 16:48:24 -06003596 // Print out the paths being searched if debugging is enabled
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003597 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Searching for ICD drivers named %s, using default dir %s",
3598 library_path, DEFAULT_VK_DRIVERS_PATH);
Daniel Dadap00b4aba2015-09-30 11:50:51 -05003599 if (loader_platform_is_path(library_path)) {
Jon Ashburn86251302015-08-25 16:48:24 -06003600 // a relative or absolute path
Daniel Dadap00b4aba2015-09-30 11:50:51 -05003601 char *name_copy = loader_stack_alloc(strlen(file_str) + 1);
3602 char *rel_base;
Jon Ashburn86251302015-08-25 16:48:24 -06003603 strcpy(name_copy, file_str);
3604 rel_base = loader_platform_dirname(name_copy);
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003605 loader_expand_path(library_path, rel_base, sizeof(fullpath), fullpath);
Daniel Dadap00b4aba2015-09-30 11:50:51 -05003606 } else {
Jamie Madill2fcbd152016-04-27 16:33:23 -04003607 // a filename which is assumed in a system directory
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003608 loader_get_fullpath(library_path, DEFAULT_VK_DRIVERS_PATH, sizeof(fullpath), fullpath);
Jon Ashburn86251302015-08-25 16:48:24 -06003609 }
Jon Ashburn005617f2015-11-17 17:35:40 -07003610
3611 uint32_t vers = 0;
3612 item = cJSON_GetObjectItem(itemICD, "api_version");
3613 if (item != NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003614 temp = cJSON_Print(item);
Mark Young0ad83132016-06-30 13:02:42 -06003615 if (NULL == temp) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003616 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3617 "loader_icd_scan: Failed retrieving ICD JSON %s"
3618 " \'api_version\' field. Skipping ICD JSON.",
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003619 file_str);
Mark Youngb6399312017-01-10 14:22:15 -07003620
Mark Young0ad83132016-06-30 13:02:42 -06003621 // Only reason the print can fail is if there was an
3622 // allocation issue
Mark Youngb6399312017-01-10 14:22:15 -07003623 if (num_good_icds == 0) {
3624 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3625 }
3626
3627 cJSON_Free(temp);
3628 cJSON_Delete(json);
3629 json = NULL;
3630 continue;
Mark Young0ad83132016-06-30 13:02:42 -06003631 }
Jon Ashburn005617f2015-11-17 17:35:40 -07003632 vers = loader_make_version(temp);
Mark Young0ad83132016-06-30 13:02:42 -06003633 cJSON_Free(temp);
Mark Youngb6399312017-01-10 14:22:15 -07003634 } else {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003635 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3636 "loader_icd_scan: ICD JSON %s does not have an"
3637 " \'api_version\' field.",
Mark Youngb6399312017-01-10 14:22:15 -07003638 file_str);
Jon Ashburn005617f2015-11-17 17:35:40 -07003639 }
Mark Youngb6399312017-01-10 14:22:15 -07003640
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003641 res = loader_scanned_icd_add(inst, icd_tramp_list, fullpath, vers);
Mark Young3a587792016-08-19 15:25:08 -06003642 if (VK_SUCCESS != res) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003643 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3644 "loader_icd_scan: Failed to add ICD JSON %s. "
3645 " Skipping ICD JSON.",
Mark Youngb6399312017-01-10 14:22:15 -07003646 fullpath);
Mark Youngd66edd52017-03-10 17:31:18 -07003647 cJSON_Delete(json);
3648 json = NULL;
Mark Youngb6399312017-01-10 14:22:15 -07003649 continue;
Mark Young3a587792016-08-19 15:25:08 -06003650 }
3651 num_good_icds++;
Mark Young0ad83132016-06-30 13:02:42 -06003652 } else {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003653 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3654 "loader_icd_scan: Failed to find \'library_path\' "
3655 "object in ICD JSON file %s. Skipping ICD JSON.",
Jon Ashburn23d36b12016-02-02 17:47:28 -07003656 file_str);
Mark Young0ad83132016-06-30 13:02:42 -06003657 }
3658 } else {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003659 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3660 "loader_icd_scan: Can not find \'ICD\' object in ICD JSON "
3661 "file %s. Skipping ICD JSON",
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003662 file_str);
Mark Young0ad83132016-06-30 13:02:42 -06003663 }
Jon Ashburn2077e382015-06-29 11:25:34 -06003664
Mark Young0ad83132016-06-30 13:02:42 -06003665 cJSON_Delete(json);
3666 json = NULL;
3667 }
3668
3669out:
Mark Youngb6399312017-01-10 14:22:15 -07003670
Mark Young0ad83132016-06-30 13:02:42 -06003671 if (NULL != json) {
Jon Ashburn2077e382015-06-29 11:25:34 -06003672 cJSON_Delete(json);
3673 }
Mark Youngd66edd52017-03-10 17:31:18 -07003674
Mark Young0ad83132016-06-30 13:02:42 -06003675 if (NULL != manifest_files.filename_list) {
3676 for (uint32_t i = 0; i < manifest_files.count; i++) {
3677 if (NULL != manifest_files.filename_list[i]) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003678 loader_instance_heap_free(inst, manifest_files.filename_list[i]);
Mark Young0ad83132016-06-30 13:02:42 -06003679 }
3680 }
3681 loader_instance_heap_free(inst, manifest_files.filename_list);
3682 }
3683 if (lockedMutex) {
3684 loader_platform_thread_unlock_mutex(&loader_json_lock);
3685 }
Mark Youngd66edd52017-03-10 17:31:18 -07003686
Mark Young0ad83132016-06-30 13:02:42 -06003687 return res;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08003688}
3689
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003690void loader_layer_scan(const struct loader_instance *inst, struct loader_layer_list *instance_layers) {
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003691 char *file_str;
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003692 struct loader_manifest_files manifest_files[2]; // [0] = explicit, [1] = implicit
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003693 cJSON *json;
Jon Ashburn075ce432015-12-17 17:38:24 -07003694 uint32_t implicit;
Mark Young0ad83132016-06-30 13:02:42 -06003695 bool lockedMutex = false;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003696
Mark Young0ad83132016-06-30 13:02:42 -06003697 memset(manifest_files, 0, sizeof(struct loader_manifest_files) * 2);
3698
3699 // Get a list of manifest files for explicit layers
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003700 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 -08003701 RELATIVE_VK_ELAYERS_INFO, &manifest_files[0])) {
Mark Young0ad83132016-06-30 13:02:42 -06003702 goto out;
3703 }
3704
3705 // Get a list of manifest files for any implicit layers
Jon Ashburn23d36b12016-02-02 17:47:28 -07003706 // Pass NULL for environment variable override - implicit layers are not
3707 // overridden by LAYERS_PATH_ENV
Benjamin Saunders31a48012017-01-29 14:49:54 -08003708 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 -07003709 &manifest_files[1])) {
Mark Young0ad83132016-06-30 13:02:42 -06003710 goto out;
3711 }
Jon Ashburn90c6a0e2015-06-04 15:30:58 -06003712
Mark Young0ad83132016-06-30 13:02:42 -06003713 // Make sure we have at least one layer, if not, go ahead and return
3714 if (manifest_files[0].count == 0 && manifest_files[1].count == 0) {
3715 goto out;
3716 }
3717
3718 // cleanup any previously scanned libraries
Jon Ashburne39a4f82015-08-28 13:38:21 -06003719 loader_delete_layer_properties(inst, instance_layers);
Jon Ashburnb2ef1372015-07-16 17:19:31 -06003720
Jon Ashburn6461ef22015-09-22 13:11:00 -06003721 loader_platform_thread_lock_mutex(&loader_json_lock);
Mark Young0ad83132016-06-30 13:02:42 -06003722 lockedMutex = true;
Jon Ashburn075ce432015-12-17 17:38:24 -07003723 for (implicit = 0; implicit < 2; implicit++) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04003724 for (uint32_t i = 0; i < manifest_files[implicit].count; i++) {
Jon Ashburn075ce432015-12-17 17:38:24 -07003725 file_str = manifest_files[implicit].filename_list[i];
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003726 if (file_str == NULL) continue;
Courtney Goeltzenleuchtera9e4af42015-06-01 14:49:17 -06003727
Jon Ashburn075ce432015-12-17 17:38:24 -07003728 // parse file into JSON struct
Mark Young3a587792016-08-19 15:25:08 -06003729 VkResult res = loader_get_json(inst, file_str, &json);
3730 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
3731 break;
3732 } else if (VK_SUCCESS != res || NULL == json) {
Jon Ashburn075ce432015-12-17 17:38:24 -07003733 continue;
3734 }
3735
Mark Youngf2079b92017-05-02 10:49:46 -06003736 VkResult local_res = loader_add_layer_properties(inst, instance_layers, json, (implicit == 1), file_str);
Jon Ashburn075ce432015-12-17 17:38:24 -07003737 cJSON_Delete(json);
Mark Youngf2079b92017-05-02 10:49:46 -06003738
Lenny Komow9a73b662018-02-13 10:30:02 -07003739 // If the error is anything other than out of memory we still want to try to load the other layers
3740 if (VK_ERROR_OUT_OF_HOST_MEMORY == local_res) {
Mark Youngf2079b92017-05-02 10:49:46 -06003741 goto out;
3742 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003743 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003744 }
Jon Ashburn86a527a2016-02-10 20:59:26 -07003745
Mark Youngf2079b92017-05-02 10:49:46 -06003746 // See if "VK_LAYER_LUNARG_standard_validation" already in list.
3747 bool found_std_val = false;
3748 for (uint32_t i = 0; i < instance_layers->count; i++) {
3749 struct loader_layer_properties *props = &instance_layers->list[i];
3750 if (strcmp(props->info.layerName, std_validation_str) == 0) {
3751 found_std_val = true;
3752 break;
3753 }
3754 }
3755
3756 // If we didn't find the VK_LAYER_LUNARG_standard_validation meta-layer in
3757 // the list, then we need to add it manually. This is likely because we're
3758 // dealing with a new loader, but an old layer folder.
3759 if (!found_std_val && !loader_add_legacy_std_val_layer(inst, instance_layers)) {
3760 goto out;
3761 }
3762
3763 // Verify any meta-layers in the list are valid and all the component layers are
3764 // actually present in the available layer list
3765 verify_all_meta_layers(inst, instance_layers);
Jon Ashburn86a527a2016-02-10 20:59:26 -07003766
Mark Young0ad83132016-06-30 13:02:42 -06003767out:
3768
3769 for (uint32_t manFile = 0; manFile < 2; manFile++) {
3770 if (NULL != manifest_files[manFile].filename_list) {
3771 for (uint32_t i = 0; i < manifest_files[manFile].count; i++) {
3772 if (NULL != manifest_files[manFile].filename_list[i]) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003773 loader_instance_heap_free(inst, manifest_files[manFile].filename_list[i]);
Mark Young0ad83132016-06-30 13:02:42 -06003774 }
3775 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003776 loader_instance_heap_free(inst, manifest_files[manFile].filename_list);
Mark Young0ad83132016-06-30 13:02:42 -06003777 }
3778 }
3779 if (lockedMutex) {
3780 loader_platform_thread_unlock_mutex(&loader_json_lock);
3781 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003782}
3783
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003784void loader_implicit_layer_scan(const struct loader_instance *inst, struct loader_layer_list *instance_layers) {
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003785 char *file_str;
3786 struct loader_manifest_files manifest_files;
3787 cJSON *json;
3788 uint32_t i;
3789
3790 // Pass NULL for environment variable override - implicit layers are not
3791 // overridden by LAYERS_PATH_ENV
Mark Youngf2079b92017-05-02 10:49:46 -06003792 VkResult res = loader_get_manifest_files(inst, NULL, NULL, true, false, DEFAULT_VK_ILAYERS_INFO, RELATIVE_VK_ILAYERS_INFO,
3793 &manifest_files);
Mark Young0ad83132016-06-30 13:02:42 -06003794 if (VK_SUCCESS != res || manifest_files.count == 0) {
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003795 return;
3796 }
3797
Mark Young0f183a82017-02-28 09:58:04 -07003798 // Cleanup any previously scanned libraries
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003799 loader_delete_layer_properties(inst, instance_layers);
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003800
3801 loader_platform_thread_lock_mutex(&loader_json_lock);
3802
3803 for (i = 0; i < manifest_files.count; i++) {
3804 file_str = manifest_files.filename_list[i];
3805 if (file_str == NULL) {
3806 continue;
3807 }
3808
3809 // parse file into JSON struct
Mark Young3a587792016-08-19 15:25:08 -06003810 res = loader_get_json(inst, file_str, &json);
3811 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
3812 break;
3813 } else if (VK_SUCCESS != res || NULL == json) {
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003814 continue;
3815 }
3816
Mark Youngf2079b92017-05-02 10:49:46 -06003817 res = loader_add_layer_properties(inst, instance_layers, json, true, file_str);
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003818
Mark Young0ad83132016-06-30 13:02:42 -06003819 loader_instance_heap_free(inst, file_str);
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003820 cJSON_Delete(json);
Mark Youngf2079b92017-05-02 10:49:46 -06003821
3822 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
3823 break;
3824 }
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003825 }
Mark Young0ad83132016-06-30 13:02:42 -06003826 loader_instance_heap_free(inst, manifest_files.filename_list);
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003827 loader_platform_thread_unlock_mutex(&loader_json_lock);
3828}
3829
Jean-Francois Roybd7ceab2017-07-06 14:10:13 -07003830// Check if an implicit layer should be enabled.
3831bool loader_is_implicit_layer_enabled(const struct loader_instance *inst, const struct loader_layer_properties *prop) {
3832 bool enable = false;
3833 char *env_value = NULL;
3834
3835 // if no enable_environment variable is specified, this implicit layer
3836 // should always be enabled. Otherwise check if the variable is set
3837 if (prop->enable_env_var.name[0] == 0) {
3838 enable = true;
3839 } else {
3840 env_value = loader_secure_getenv(prop->enable_env_var.name, inst);
3841 if (env_value && !strcmp(prop->enable_env_var.value, env_value)) enable = true;
3842 loader_free_getenv(env_value, inst);
3843 }
3844
3845 // disable_environment has priority, i.e. if both enable and disable
3846 // environment variables are set, the layer is disabled. Implicit
3847 // layers are required to have a disable_environment variables
3848 env_value = loader_secure_getenv(prop->disable_env_var.name, inst);
3849 if (env_value && !strcmp(prop->disable_env_var.value, env_value)) enable = false;
3850 loader_free_getenv(env_value, inst);
3851
3852 return enable;
3853}
3854
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003855static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpdpa_instance_internal(VkInstance inst, const char *pName) {
Mark Young39389872017-01-19 21:10:49 -07003856 // inst is not wrapped
3857 if (inst == VK_NULL_HANDLE) {
3858 return NULL;
3859 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003860 VkLayerInstanceDispatchTable *disp_table = *(VkLayerInstanceDispatchTable **)inst;
Mark Young39389872017-01-19 21:10:49 -07003861 void *addr;
3862
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003863 if (disp_table == NULL) return NULL;
Mark Young39389872017-01-19 21:10:49 -07003864
3865 bool found_name;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003866 addr = loader_lookup_instance_dispatch_table(disp_table, pName, &found_name);
Mark Young39389872017-01-19 21:10:49 -07003867 if (found_name) {
3868 return addr;
3869 }
3870
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003871 if (loader_phys_dev_ext_gpa(loader_get_instance(inst), pName, true, NULL, &addr)) return addr;
Mark Young39389872017-01-19 21:10:49 -07003872
3873 // Don't call down the chain, this would be an infinite loop
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003874 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 -07003875 return NULL;
3876}
3877
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003878static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpdpa_instance_terminator(VkInstance inst, const char *pName) {
Mark Young39389872017-01-19 21:10:49 -07003879 // inst is not wrapped
3880 if (inst == VK_NULL_HANDLE) {
3881 return NULL;
3882 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003883 VkLayerInstanceDispatchTable *disp_table = *(VkLayerInstanceDispatchTable **)inst;
Mark Young39389872017-01-19 21:10:49 -07003884 void *addr;
3885
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003886 if (disp_table == NULL) return NULL;
Mark Young39389872017-01-19 21:10:49 -07003887
3888 bool found_name;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003889 addr = loader_lookup_instance_dispatch_table(disp_table, pName, &found_name);
Mark Young39389872017-01-19 21:10:49 -07003890 if (found_name) {
3891 return addr;
3892 }
3893
3894 // Get the terminator, but don't perform checking since it should already
3895 // have been setup if we get here.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003896 if (loader_phys_dev_ext_gpa(loader_get_instance(inst), pName, false, NULL, &addr)) {
Mark Young39389872017-01-19 21:10:49 -07003897 return addr;
3898 }
3899
3900 // Don't call down the chain, this would be an infinite loop
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003901 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 -07003902 return NULL;
3903}
3904
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003905static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpa_instance_internal(VkInstance inst, const char *pName) {
Mark Young39389872017-01-19 21:10:49 -07003906 if (!strcmp(pName, "vkGetInstanceProcAddr")) {
3907 return (PFN_vkVoidFunction)loader_gpa_instance_internal;
3908 }
3909 if (!strcmp(pName, "vk_layerGetPhysicalDeviceProcAddr")) {
3910 return (PFN_vkVoidFunction)loader_gpdpa_instance_terminator;
3911 }
3912 if (!strcmp(pName, "vkCreateInstance")) {
3913 return (PFN_vkVoidFunction)terminator_CreateInstance;
3914 }
3915 if (!strcmp(pName, "vkCreateDevice")) {
3916 return (PFN_vkVoidFunction)terminator_CreateDevice;
3917 }
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003918
Jon Ashburn27cd5842015-05-12 17:26:48 -06003919 // inst is not wrapped
3920 if (inst == VK_NULL_HANDLE) {
3921 return NULL;
3922 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003923 VkLayerInstanceDispatchTable *disp_table = *(VkLayerInstanceDispatchTable **)inst;
Jon Ashburn27cd5842015-05-12 17:26:48 -06003924 void *addr;
3925
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003926 if (disp_table == NULL) return NULL;
Jon Ashburn27cd5842015-05-12 17:26:48 -06003927
Jon Ashburnc7d3e732016-03-08 09:30:30 -07003928 bool found_name;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003929 addr = loader_lookup_instance_dispatch_table(disp_table, pName, &found_name);
Jon Ashburnc7d3e732016-03-08 09:30:30 -07003930 if (found_name) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06003931 return addr;
Jon Ashburn3d526cb2015-04-13 18:10:06 -06003932 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003933
Jon Ashburnc7d3e732016-03-08 09:30:30 -07003934 // Don't call down the chain, this would be an infinite loop
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003935 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 -07003936 return NULL;
Jon Ashburn3d526cb2015-04-13 18:10:06 -06003937}
3938
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003939VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpa_device_internal(VkDevice device, const char *pName) {
Jon Ashburncc407a22016-04-15 09:25:03 -06003940 struct loader_device *dev;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003941 struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, NULL);
Mark Young16573c72016-06-28 10:52:43 -06003942
Mark Young0f183a82017-02-28 09:58:04 -07003943 // Return this function if a layer above here is asking for the vkGetDeviceProcAddr.
3944 // This is so we can properly intercept any device commands needing a terminator.
3945 if (!strcmp(pName, "vkGetDeviceProcAddr")) {
3946 return (PFN_vkVoidFunction)loader_gpa_device_internal;
3947 }
3948
Mark Young65cb3662016-11-07 13:27:02 -07003949 // NOTE: Device Funcs needing Trampoline/Terminator.
3950 // Overrides for device functions needing a trampoline and
3951 // a terminator because certain device entry-points still need to go
3952 // through a terminator before hitting the ICD. This could be for
3953 // several reasons, but the main one is currently unwrapping an
3954 // object before passing the appropriate info along to the ICD.
3955 // This is why we also have to override the direct ICD call to
3956 // vkGetDeviceProcAddr to intercept those calls.
Mark Young0f183a82017-02-28 09:58:04 -07003957 PFN_vkVoidFunction addr = get_extension_device_proc_terminator(pName);
3958 if (NULL != addr) {
3959 return addr;
Mark Young16573c72016-06-28 10:52:43 -06003960 }
3961
Mark Young0f183a82017-02-28 09:58:04 -07003962 return icd_term->dispatch.GetDeviceProcAddr(device, pName);
Piers Daniell295fe402016-03-29 11:51:11 -06003963}
3964
Mark Young0f183a82017-02-28 09:58:04 -07003965// Initialize device_ext dispatch table entry as follows:
3966// If dev == NULL find all logical devices created within this instance and
3967// init the entry (given by idx) in the ext dispatch table.
3968// If dev != NULL only initialize the entry in the given dev's dispatch table.
3969// The initialization value is gotten by calling down the device chain with
3970// GDPA.
3971// If GDPA returns NULL then don't initialize the dispatch table entry.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003972static 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 -07003973 const char *funcName)
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003974
Jon Ashburn23d36b12016-02-02 17:47:28 -07003975{
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003976 void *gdpa_value;
3977 if (dev != NULL) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003978 gdpa_value = dev->loader_dispatch.core_dispatch.GetDeviceProcAddr(dev->chain_device, funcName);
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003979 if (gdpa_value != NULL) dev->loader_dispatch.ext_dispatch.dev_ext[idx] = (PFN_vkDevExt)gdpa_value;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003980 } else {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003981 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 -06003982 struct loader_device *ldev = icd_term->logical_device_list;
Karl Schultz2558bd32016-02-24 14:39:39 -07003983 while (ldev) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003984 gdpa_value = ldev->loader_dispatch.core_dispatch.GetDeviceProcAddr(ldev->chain_device, funcName);
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003985 if (gdpa_value != NULL) ldev->loader_dispatch.ext_dispatch.dev_ext[idx] = (PFN_vkDevExt)gdpa_value;
Karl Schultz2558bd32016-02-24 14:39:39 -07003986 ldev = ldev->next;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003987 }
3988 }
3989 }
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003990}
3991
Mark Young0f183a82017-02-28 09:58:04 -07003992// Find all dev extension in the hash table and initialize the dispatch table
3993// for dev for each of those extension entrypoints found in hash table.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003994void loader_init_dispatch_dev_ext(struct loader_instance *inst, struct loader_device *dev) {
Mark Young39389872017-01-19 21:10:49 -07003995 for (uint32_t i = 0; i < MAX_NUM_UNKNOWN_EXTS; i++) {
3996 if (inst->dev_ext_disp_hash[i].func_name != NULL)
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003997 loader_init_dispatch_dev_ext_entry(inst, dev, i, inst->dev_ext_disp_hash[i].func_name);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003998 }
3999}
4000
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004001static bool loader_check_icds_for_dev_ext_address(struct loader_instance *inst, const char *funcName) {
Mark Young0153e0b2016-11-03 14:27:13 -06004002 struct loader_icd_term *icd_term;
4003 icd_term = inst->icd_terms;
4004 while (NULL != icd_term) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004005 if (icd_term->scanned_icd->GetInstanceProcAddr(icd_term->instance, funcName))
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004006 // this icd supports funcName
4007 return true;
Mark Young0153e0b2016-11-03 14:27:13 -06004008 icd_term = icd_term->next;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004009 }
4010
4011 return false;
4012}
4013
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004014static 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 -07004015 // Iterate over the layers.
Jon Ashburncc407a22016-04-15 09:25:03 -06004016 for (uint32_t layer = 0; layer < layers->count; ++layer) {
Jeremy Hayes1eb1f622016-03-03 16:03:03 -07004017 // Iterate over the extensions.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004018 const struct loader_device_extension_list *const extensions = &(layers->list[layer].device_extension_list);
4019 for (uint32_t extension = 0; extension < extensions->count; ++extension) {
Jeremy Hayes1eb1f622016-03-03 16:03:03 -07004020 // Iterate over the entry points.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004021 const struct loader_dev_ext_props *const property = &(extensions->list[extension]);
4022 for (uint32_t entry = 0; entry < property->entrypoint_count; ++entry) {
Jon Ashburncc407a22016-04-15 09:25:03 -06004023 if (strcmp(property->entrypoints[entry], funcName) == 0) {
Jeremy Hayes1eb1f622016-03-03 16:03:03 -07004024 return true;
4025 }
4026 }
4027 }
4028 }
4029
4030 return false;
4031}
4032
Jon Ashburn23d36b12016-02-02 17:47:28 -07004033static void loader_free_dev_ext_table(struct loader_instance *inst) {
Mark Young39389872017-01-19 21:10:49 -07004034 for (uint32_t i = 0; i < MAX_NUM_UNKNOWN_EXTS; i++) {
4035 loader_instance_heap_free(inst, inst->dev_ext_disp_hash[i].func_name);
4036 loader_instance_heap_free(inst, inst->dev_ext_disp_hash[i].list.index);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004037 }
Mark Young39389872017-01-19 21:10:49 -07004038 memset(inst->dev_ext_disp_hash, 0, sizeof(inst->dev_ext_disp_hash));
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004039}
4040
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004041static bool loader_add_dev_ext_table(struct loader_instance *inst, uint32_t *ptr_idx, const char *funcName) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004042 uint32_t i;
4043 uint32_t idx = *ptr_idx;
Mark Young39389872017-01-19 21:10:49 -07004044 struct loader_dispatch_hash_list *list = &inst->dev_ext_disp_hash[idx].list;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004045
Mark Young39389872017-01-19 21:10:49 -07004046 if (!inst->dev_ext_disp_hash[idx].func_name) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004047 // no entry here at this idx, so use it
4048 assert(list->capacity == 0);
Mark Young39389872017-01-19 21:10:49 -07004049 inst->dev_ext_disp_hash[idx].func_name =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004050 (char *)loader_instance_heap_alloc(inst, strlen(funcName) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young39389872017-01-19 21:10:49 -07004051 if (inst->dev_ext_disp_hash[idx].func_name == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004052 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4053 "loader_add_dev_ext_table: Failed to allocate memory "
4054 "for func_name %s",
Mark Youngb6399312017-01-10 14:22:15 -07004055 funcName);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004056 return false;
4057 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004058 strncpy(inst->dev_ext_disp_hash[idx].func_name, funcName, strlen(funcName) + 1);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004059 return true;
4060 }
4061
4062 // check for enough capacity
4063 if (list->capacity == 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004064 list->index = loader_instance_heap_alloc(inst, 8 * sizeof(*(list->index)), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004065 if (list->index == NULL) {
Mark Youngbb3a29c2017-05-19 12:29:43 -06004066 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 -07004067 funcName);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004068 return false;
4069 }
4070 list->capacity = 8 * sizeof(*(list->index));
4071 } else if (list->capacity < (list->count + 1) * sizeof(*(list->index))) {
Mark Youngbb3a29c2017-05-19 12:29:43 -06004072 void *new_ptr = loader_instance_heap_realloc(inst, list->index, list->capacity, list->capacity * 2,
4073 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
4074 if (NULL == new_ptr) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004075 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngbb3a29c2017-05-19 12:29:43 -06004076 "loader_add_dev_ext_table: Failed to reallocate memory for list index", funcName);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004077 return false;
4078 }
Mark Youngbb3a29c2017-05-19 12:29:43 -06004079 list->index = new_ptr;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004080 list->capacity *= 2;
4081 }
4082
Jon Ashburn23d36b12016-02-02 17:47:28 -07004083 // find an unused index in the hash table and use it
Mark Young39389872017-01-19 21:10:49 -07004084 i = (idx + 1) % MAX_NUM_UNKNOWN_EXTS;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004085 do {
Mark Young39389872017-01-19 21:10:49 -07004086 if (!inst->dev_ext_disp_hash[i].func_name) {
4087 assert(inst->dev_ext_disp_hash[i].list.capacity == 0);
4088 inst->dev_ext_disp_hash[i].func_name =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004089 (char *)loader_instance_heap_alloc(inst, strlen(funcName) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young39389872017-01-19 21:10:49 -07004090 if (inst->dev_ext_disp_hash[i].func_name == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004091 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4092 "loader_add_dev_ext_table: Failed to allocate memory "
4093 "for func_name %s",
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004094 funcName);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004095 return false;
4096 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004097 strncpy(inst->dev_ext_disp_hash[i].func_name, funcName, strlen(funcName) + 1);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004098 list->index[list->count] = i;
4099 list->count++;
4100 *ptr_idx = i;
4101 return true;
4102 }
Mark Young39389872017-01-19 21:10:49 -07004103 i = (i + 1) % MAX_NUM_UNKNOWN_EXTS;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004104 } while (i != idx);
4105
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004106 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4107 "loader_add_dev_ext_table: Could not insert into hash table; is "
4108 "it full?");
Mark Youngb6399312017-01-10 14:22:15 -07004109
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004110 return false;
4111}
4112
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004113static bool loader_name_in_dev_ext_table(struct loader_instance *inst, uint32_t *idx, const char *funcName) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004114 uint32_t alt_idx;
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004115 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 -07004116
4117 // funcName wasn't at the primary spot in the hash table
4118 // search the list of secondary locations (shallow search, not deep search)
Mark Young39389872017-01-19 21:10:49 -07004119 for (uint32_t i = 0; i < inst->dev_ext_disp_hash[*idx].list.count; i++) {
4120 alt_idx = inst->dev_ext_disp_hash[*idx].list.index[i];
4121 if (!strcmp(inst->dev_ext_disp_hash[*idx].func_name, funcName)) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004122 *idx = alt_idx;
4123 return true;
4124 }
4125 }
4126
4127 return false;
4128}
4129
Mark Young0f183a82017-02-28 09:58:04 -07004130// This function returns generic trampoline code address for unknown entry
4131// points.
4132// Presumably, these unknown entry points (as given by funcName) are device
4133// extension entrypoints. A hash table is used to keep a list of unknown entry
4134// points and their mapping to the device extension dispatch table
4135// (struct loader_dev_ext_dispatch_table).
4136// \returns
4137// For a given entry point string (funcName), if an existing mapping is found
4138// the
4139// trampoline address for that mapping is returned. Otherwise, this unknown
4140// entry point
4141// has not been seen yet. Next check if a layer or ICD supports it. If so then
4142// a
4143// new entry in the hash table is initialized and that trampoline address for
4144// the new entry is returned. Null is returned if the hash table is full or
4145// if no discovered layer or ICD returns a non-NULL GetProcAddr for it.
Jon Ashburn23d36b12016-02-02 17:47:28 -07004146void *loader_dev_ext_gpa(struct loader_instance *inst, const char *funcName) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004147 uint32_t idx;
4148 uint32_t seed = 0;
4149
Mark Young39389872017-01-19 21:10:49 -07004150 idx = murmurhash(funcName, strlen(funcName), seed) % MAX_NUM_UNKNOWN_EXTS;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004151
4152 if (loader_name_in_dev_ext_table(inst, &idx, funcName))
4153 // found funcName already in hash
4154 return loader_get_dev_ext_trampoline(idx);
4155
4156 // Check if funcName is supported in either ICDs or a layer library
Mark Young39389872017-01-19 21:10:49 -07004157 if (!loader_check_icds_for_dev_ext_address(inst, funcName) &&
Lenny Komowb1685e02017-08-29 16:08:39 -06004158 !loader_check_layer_list_for_dev_ext_address(&inst->app_activated_layer_list, funcName)) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004159 // if support found in layers continue on
4160 return NULL;
4161 }
4162
4163 if (loader_add_dev_ext_table(inst, &idx, funcName)) {
4164 // successfully added new table entry
Mark Youngdee312c2017-03-08 13:38:35 -07004165 // init any dev dispatch table entries as needed
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004166 loader_init_dispatch_dev_ext_entry(inst, NULL, idx, funcName);
4167 return loader_get_dev_ext_trampoline(idx);
4168 }
4169
4170 return NULL;
4171}
4172
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004173static bool loader_check_icds_for_phys_dev_ext_address(struct loader_instance *inst, const char *funcName) {
Mark Young39389872017-01-19 21:10:49 -07004174 struct loader_icd_term *icd_term;
4175 icd_term = inst->icd_terms;
4176 while (NULL != icd_term) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004177 if (icd_term->scanned_icd->interface_version >= MIN_PHYS_DEV_EXTENSION_ICD_INTERFACE_VERSION &&
4178 icd_term->scanned_icd->GetPhysicalDeviceProcAddr(icd_term->instance, funcName))
Mark Young39389872017-01-19 21:10:49 -07004179 // this icd supports funcName
4180 return true;
4181 icd_term = icd_term->next;
4182 }
4183
4184 return false;
4185}
4186
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004187static bool loader_check_layer_list_for_phys_dev_ext_address(struct loader_instance *inst, const char *funcName) {
Mark Young283fe1c2017-05-04 12:16:35 -06004188 struct loader_layer_properties *layer_prop_list = inst->expanded_activated_layer_list.list;
4189 for (uint32_t layer = 0; layer < inst->expanded_activated_layer_list.count; ++layer) {
Mark Young39389872017-01-19 21:10:49 -07004190 // If this layer supports the vk_layerGetPhysicalDeviceProcAddr, then call
4191 // it and see if it returns a valid pointer for this function name.
4192 if (layer_prop_list[layer].interface_version > 1) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004193 const struct loader_layer_functions *const functions = &(layer_prop_list[layer].functions);
Mark Young39389872017-01-19 21:10:49 -07004194 if (NULL != functions->get_physical_device_proc_addr &&
Tony Barbour55bd5392017-05-17 12:17:18 -06004195 NULL != functions->get_physical_device_proc_addr((VkInstance)inst->instance, funcName)) {
Mark Young39389872017-01-19 21:10:49 -07004196 return true;
4197 }
4198 }
4199 }
4200
4201 return false;
4202}
4203
Mark Young39389872017-01-19 21:10:49 -07004204static void loader_free_phys_dev_ext_table(struct loader_instance *inst) {
4205 for (uint32_t i = 0; i < MAX_NUM_UNKNOWN_EXTS; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004206 loader_instance_heap_free(inst, inst->phys_dev_ext_disp_hash[i].func_name);
4207 loader_instance_heap_free(inst, inst->phys_dev_ext_disp_hash[i].list.index);
Mark Young39389872017-01-19 21:10:49 -07004208 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004209 memset(inst->phys_dev_ext_disp_hash, 0, sizeof(inst->phys_dev_ext_disp_hash));
Mark Young39389872017-01-19 21:10:49 -07004210}
4211
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004212static 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 -07004213 uint32_t i;
4214 uint32_t idx = *ptr_idx;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004215 struct loader_dispatch_hash_list *list = &inst->phys_dev_ext_disp_hash[idx].list;
Mark Young39389872017-01-19 21:10:49 -07004216
4217 if (!inst->phys_dev_ext_disp_hash[idx].func_name) {
4218 // no entry here at this idx, so use it
4219 assert(list->capacity == 0);
4220 inst->phys_dev_ext_disp_hash[idx].func_name =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004221 (char *)loader_instance_heap_alloc(inst, strlen(funcName) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young39389872017-01-19 21:10:49 -07004222 if (inst->phys_dev_ext_disp_hash[idx].func_name == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004223 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4224 "loader_add_phys_dev_ext_table() can't allocate memory for "
4225 "func_name");
Mark Young39389872017-01-19 21:10:49 -07004226 return false;
4227 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004228 strncpy(inst->phys_dev_ext_disp_hash[idx].func_name, funcName, strlen(funcName) + 1);
Mark Young39389872017-01-19 21:10:49 -07004229 return true;
4230 }
4231
4232 // check for enough capacity
4233 if (list->capacity == 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004234 list->index = loader_instance_heap_alloc(inst, 8 * sizeof(*(list->index)), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young39389872017-01-19 21:10:49 -07004235 if (list->index == NULL) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004236 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 -07004237 return false;
4238 }
4239 list->capacity = 8 * sizeof(*(list->index));
4240 } else if (list->capacity < (list->count + 1) * sizeof(*(list->index))) {
Mark Youngbb3a29c2017-05-19 12:29:43 -06004241 void *new_ptr = loader_instance_heap_realloc(inst, list->index, list->capacity, list->capacity * 2,
4242 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
4243 if (NULL == new_ptr) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004244 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 -07004245 return false;
4246 }
Mark Youngbb3a29c2017-05-19 12:29:43 -06004247 list->index = new_ptr;
Mark Young39389872017-01-19 21:10:49 -07004248 list->capacity *= 2;
4249 }
4250
4251 // find an unused index in the hash table and use it
4252 i = (idx + 1) % MAX_NUM_UNKNOWN_EXTS;
4253 do {
4254 if (!inst->phys_dev_ext_disp_hash[i].func_name) {
4255 assert(inst->phys_dev_ext_disp_hash[i].list.capacity == 0);
4256 inst->phys_dev_ext_disp_hash[i].func_name =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004257 (char *)loader_instance_heap_alloc(inst, strlen(funcName) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young39389872017-01-19 21:10:49 -07004258 if (inst->phys_dev_ext_disp_hash[i].func_name == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004259 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngdee312c2017-03-08 13:38:35 -07004260 "loader_add_dev_ext_table() can't reallocate "
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004261 "func_name memory");
Mark Young39389872017-01-19 21:10:49 -07004262 return false;
4263 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004264 strncpy(inst->phys_dev_ext_disp_hash[i].func_name, funcName, strlen(funcName) + 1);
Mark Young39389872017-01-19 21:10:49 -07004265 list->index[list->count] = i;
4266 list->count++;
4267 *ptr_idx = i;
4268 return true;
4269 }
4270 i = (i + 1) % MAX_NUM_UNKNOWN_EXTS;
4271 } while (i != idx);
4272
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004273 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4274 "loader_add_phys_dev_ext_table() couldn't insert into hash table; is "
4275 "it full?");
Mark Young39389872017-01-19 21:10:49 -07004276 return false;
4277}
4278
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004279static 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 -07004280 uint32_t alt_idx;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004281 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 -07004282 return true;
4283
4284 // funcName wasn't at the primary spot in the hash table
4285 // search the list of secondary locations (shallow search, not deep search)
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004286 for (uint32_t i = 0; i < inst->phys_dev_ext_disp_hash[*idx].list.count; i++) {
Mark Young39389872017-01-19 21:10:49 -07004287 alt_idx = inst->phys_dev_ext_disp_hash[*idx].list.index[i];
4288 if (!strcmp(inst->phys_dev_ext_disp_hash[*idx].func_name, funcName)) {
4289 *idx = alt_idx;
4290 return true;
4291 }
4292 }
4293
4294 return false;
4295}
4296
4297// This function returns a generic trampoline and/or terminator function
4298// address for any unknown physical device extension commands. A hash
4299// table is used to keep a list of unknown entry points and their
4300// mapping to the physical device extension dispatch table (struct
4301// loader_phys_dev_ext_dispatch_table).
4302// For a given entry point string (funcName), if an existing mapping is
4303// found, then the trampoline address for that mapping is returned in
4304// tramp_addr (if it is not NULL) and the terminator address for that
4305// mapping is returned in term_addr (if it is not NULL). Otherwise,
4306// this unknown entry point has not been seen yet.
4307// If it has not been seen before, and perform_checking is 'true',
4308// check if a layer or and ICD supports it. If so then a new entry in
4309// the hash table is initialized and the trampoline and/or terminator
4310// addresses are returned.
4311// Null is returned if the hash table is full or if no discovered layer or
4312// ICD returns a non-NULL GetProcAddr for it.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004313bool 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 -07004314 void **term_addr) {
4315 uint32_t idx;
4316 uint32_t seed = 0;
4317 bool success = false;
4318
4319 if (inst == NULL) {
4320 goto out;
4321 }
4322
4323 if (NULL != tramp_addr) {
4324 *tramp_addr = NULL;
4325 }
4326 if (NULL != term_addr) {
4327 *term_addr = NULL;
4328 }
4329
4330 // We should always check to see if any ICD supports it.
4331 if (!loader_check_icds_for_phys_dev_ext_address(inst, funcName)) {
4332 // If we're not checking layers, or we are and it's not in a layer, just
4333 // return
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004334 if (!perform_checking || !loader_check_layer_list_for_phys_dev_ext_address(inst, funcName)) {
Mark Young39389872017-01-19 21:10:49 -07004335 goto out;
4336 }
4337 }
4338
4339 idx = murmurhash(funcName, strlen(funcName), seed) % MAX_NUM_UNKNOWN_EXTS;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004340 if (perform_checking && !loader_name_in_phys_dev_ext_table(inst, &idx, funcName)) {
Mark Young39389872017-01-19 21:10:49 -07004341 uint32_t i;
4342 bool added = false;
4343
4344 // Only need to add first one to get index in Instance. Others will use
4345 // the same index.
4346 if (!added && loader_add_phys_dev_ext_table(inst, &idx, funcName)) {
4347 added = true;
4348 }
4349
4350 // Setup the ICD function pointers
4351 struct loader_icd_term *icd_term = inst->icd_terms;
4352 while (NULL != icd_term) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004353 if (MIN_PHYS_DEV_EXTENSION_ICD_INTERFACE_VERSION <= icd_term->scanned_icd->interface_version &&
Mark Young39389872017-01-19 21:10:49 -07004354 NULL != icd_term->scanned_icd->GetPhysicalDeviceProcAddr) {
4355 icd_term->phys_dev_ext[idx] =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004356 (PFN_PhysDevExt)icd_term->scanned_icd->GetPhysicalDeviceProcAddr(icd_term->instance, funcName);
Mark Young39389872017-01-19 21:10:49 -07004357
4358 // Make sure we set the instance dispatch to point to the
4359 // loader's terminator now since we can at least handle it
4360 // in one ICD.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004361 inst->disp->phys_dev_ext[idx] = loader_get_phys_dev_ext_termin(idx);
Mark Young39389872017-01-19 21:10:49 -07004362 } else {
4363 icd_term->phys_dev_ext[idx] = NULL;
4364 }
4365
4366 icd_term = icd_term->next;
4367 }
4368
4369 // Now, search for the first layer attached and query using it to get
4370 // the first entry point.
Mark Young283fe1c2017-05-04 12:16:35 -06004371 for (i = 0; i < inst->expanded_activated_layer_list.count; i++) {
4372 struct loader_layer_properties *layer_prop = &inst->expanded_activated_layer_list.list[i];
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004373 if (layer_prop->interface_version > 1 && NULL != layer_prop->functions.get_physical_device_proc_addr) {
Mark Young39389872017-01-19 21:10:49 -07004374 inst->disp->phys_dev_ext[idx] =
Tony Barbour55bd5392017-05-17 12:17:18 -06004375 (PFN_PhysDevExt)layer_prop->functions.get_physical_device_proc_addr((VkInstance)inst->instance, funcName);
Mark Young39389872017-01-19 21:10:49 -07004376 if (NULL != inst->disp->phys_dev_ext[idx]) {
4377 break;
4378 }
4379 }
4380 }
4381 }
4382
4383 if (NULL != tramp_addr) {
4384 *tramp_addr = loader_get_phys_dev_ext_tramp(idx);
4385 }
4386
4387 if (NULL != term_addr) {
4388 *term_addr = loader_get_phys_dev_ext_termin(idx);
4389 }
4390
4391 success = true;
4392
4393out:
4394 return success;
4395}
4396
Jon Ashburn23d36b12016-02-02 17:47:28 -07004397struct loader_instance *loader_get_instance(const VkInstance instance) {
Mark Young0f183a82017-02-28 09:58:04 -07004398 // look up the loader_instance in our list by comparing dispatch tables, as
4399 // there is no guarantee the instance is still a loader_instance* after any
4400 // layers which wrap the instance object.
Jon Ashburne0e64572015-09-30 12:56:42 -06004401 const VkLayerInstanceDispatchTable *disp;
4402 struct loader_instance *ptr_instance = NULL;
Mark Young39389872017-01-19 21:10:49 -07004403 disp = loader_get_instance_layer_dispatch(instance);
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004404 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
Mark Young39389872017-01-19 21:10:49 -07004405 if (&inst->disp->layer_inst_disp == disp) {
Jon Ashburne0e64572015-09-30 12:56:42 -06004406 ptr_instance = inst;
4407 break;
4408 }
4409 }
4410 return ptr_instance;
4411}
4412
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004413static loader_platform_dl_handle loader_open_layer_lib(const struct loader_instance *inst, const char *chain_type,
4414 struct loader_layer_properties *prop) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004415 if ((prop->lib_handle = loader_platform_open_library(prop->lib_name)) == NULL) {
Mark Youngb986b5f2017-05-16 09:48:55 -06004416 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 -06004417 } else {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004418 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Loading layer library %s", prop->lib_name);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004419 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004420
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004421 return prop->lib_handle;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004422}
4423
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004424static void loader_close_layer_lib(const struct loader_instance *inst, struct loader_layer_properties *prop) {
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004425 if (prop->lib_handle) {
4426 loader_platform_close_library(prop->lib_handle);
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004427 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Unloading layer library %s", prop->lib_name);
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004428 prop->lib_handle = NULL;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06004429 }
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004430}
Jon Ashburnd38bfb12014-10-14 19:15:22 -06004431
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004432void loader_deactivate_layers(const struct loader_instance *instance, struct loader_device *device,
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004433 struct loader_layer_list *list) {
Mark Young0f183a82017-02-28 09:58:04 -07004434 // Delete instance list of enabled layers and close any layer libraries
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004435 for (uint32_t i = 0; i < list->count; i++) {
4436 struct loader_layer_properties *layer_prop = &list->list[i];
Courtney Goeltzenleuchter80bfd0e2015-12-17 09:51:22 -07004437
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004438 loader_close_layer_lib(instance, layer_prop);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07004439 }
Mark Young0ad83132016-06-30 13:02:42 -06004440 loader_destroy_layer_list(instance, device, list);
Jon Ashburnb8358052014-11-18 09:06:04 -07004441}
4442
Mark Young0f183a82017-02-28 09:58:04 -07004443// Go through the search_list and find any layers which match type. If layer
4444// type match is found in then add it to ext_list.
Mark Youngf2079b92017-05-02 10:49:46 -06004445static void loader_add_implicit_layers(const struct loader_instance *inst, struct loader_layer_list *target_list,
Mark Young283fe1c2017-05-04 12:16:35 -06004446 struct loader_layer_list *expanded_target_list,
Mark Youngf2079b92017-05-02 10:49:46 -06004447 const struct loader_layer_list *source_list) {
4448 for (uint32_t src_layer = 0; src_layer < source_list->count; src_layer++) {
4449 const struct loader_layer_properties *prop = &source_list->list[src_layer];
4450 if (0 == (prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER)) {
Mark Young283fe1c2017-05-04 12:16:35 -06004451 loader_add_implicit_layer(inst, prop, target_list, expanded_target_list, source_list);
Jon Ashburn0c26e712015-07-02 16:10:32 -06004452 }
4453 }
Jon Ashburn0c26e712015-07-02 16:10:32 -06004454}
4455
Mark Youngf2079b92017-05-02 10:49:46 -06004456// Get the layer name(s) from the env_name environment variable. If layer is found in
4457// 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 -07004458static 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 -06004459 struct loader_layer_list *target_list, struct loader_layer_list *expanded_target_list,
4460 const struct loader_layer_list *source_list) {
Jon Ashburneb6d5682015-07-02 14:10:53 -06004461 char *next, *name;
Mark Youngf2079b92017-05-02 10:49:46 -06004462 char *layer_env = loader_secure_getenv(env_name, inst);
4463 if (layer_env == NULL) {
4464 goto out;
Ian Elliott4470a302015-02-17 10:33:47 -07004465 }
Mark Youngf2079b92017-05-02 10:49:46 -06004466 name = loader_stack_alloc(strlen(layer_env) + 1);
Jon Ashburneb6d5682015-07-02 14:10:53 -06004467 if (name == NULL) {
Mark Youngf2079b92017-05-02 10:49:46 -06004468 goto out;
Ian Elliott4470a302015-02-17 10:33:47 -07004469 }
Mark Youngf2079b92017-05-02 10:49:46 -06004470 strcpy(name, layer_env);
Jon Ashburn38a497f2016-01-04 14:01:38 -07004471
Jon Ashburn23d36b12016-02-02 17:47:28 -07004472 while (name && *name) {
Jon Ashburneb6d5682015-07-02 14:10:53 -06004473 next = loader_get_next_path(name);
Mark Young283fe1c2017-05-04 12:16:35 -06004474 loader_find_layer_name_add_list(inst, name, type_flags, source_list, target_list, expanded_target_list);
Jon Ashburneb6d5682015-07-02 14:10:53 -06004475 name = next;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07004476 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06004477
Mark Youngf2079b92017-05-02 10:49:46 -06004478out:
4479
4480 if (layer_env != NULL) {
4481 loader_free_getenv(layer_env, inst);
4482 }
4483
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004484 return;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06004485}
4486
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004487VkResult loader_enable_instance_layers(struct loader_instance *inst, const VkInstanceCreateInfo *pCreateInfo,
4488 const struct loader_layer_list *instance_layers) {
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06004489 VkResult err;
4490
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06004491 assert(inst && "Cannot have null instance");
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004492
Mark Young283fe1c2017-05-04 12:16:35 -06004493 if (!loader_init_layer_list(inst, &inst->app_activated_layer_list)) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004494 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4495 "loader_enable_instance_layers: Failed to initialize"
Mark Young283fe1c2017-05-04 12:16:35 -06004496 " application version of the layer list");
4497 return VK_ERROR_OUT_OF_HOST_MEMORY;
4498 }
4499
4500 if (!loader_init_layer_list(inst, &inst->expanded_activated_layer_list)) {
4501 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4502 "loader_enable_instance_layers: Failed to initialize"
4503 " expanded version of the layer list");
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06004504 return VK_ERROR_OUT_OF_HOST_MEMORY;
Jon Ashburnbd6c4882015-07-02 12:59:25 -06004505 }
4506
Mark Young0f183a82017-02-28 09:58:04 -07004507 // Add any implicit layers first
Mark Young283fe1c2017-05-04 12:16:35 -06004508 loader_add_implicit_layers(inst, &inst->app_activated_layer_list, &inst->expanded_activated_layer_list, instance_layers);
Jon Ashburn0c26e712015-07-02 16:10:32 -06004509
Mark Young0f183a82017-02-28 09:58:04 -07004510 // Add any layers specified via environment variable next
Lenny Komow3b958392018-01-17 13:53:59 -07004511 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 -06004512 &inst->expanded_activated_layer_list, instance_layers);
Jon Ashburnbd6c4882015-07-02 12:59:25 -06004513
Mark Young0f183a82017-02-28 09:58:04 -07004514 // Add layers specified by the application
Mark Young283fe1c2017-05-04 12:16:35 -06004515 err = loader_add_layer_names_to_list(inst, &inst->app_activated_layer_list, &inst->expanded_activated_layer_list,
4516 pCreateInfo->enabledLayerCount, pCreateInfo->ppEnabledLayerNames, instance_layers);
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06004517
4518 return err;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004519}
4520
Mark Young39389872017-01-19 21:10:49 -07004521// Determine the layer interface version to use.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004522bool loader_get_layer_interface_version(PFN_vkNegotiateLoaderLayerInterfaceVersion fp_negotiate_layer_version,
4523 VkNegotiateLayerInterface *interface_struct) {
Mark Young39389872017-01-19 21:10:49 -07004524 memset(interface_struct, 0, sizeof(VkNegotiateLayerInterface));
Mark Young21aa6d62017-03-29 13:39:27 -06004525 interface_struct->sType = LAYER_NEGOTIATE_INTERFACE_STRUCT;
Mark Young39389872017-01-19 21:10:49 -07004526 interface_struct->loaderLayerInterfaceVersion = 1;
4527
4528 if (fp_negotiate_layer_version != NULL) {
4529 // Layer supports the negotiation API, so call it with the loader's
4530 // latest version supported
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004531 interface_struct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
Mark Young39389872017-01-19 21:10:49 -07004532 VkResult result = fp_negotiate_layer_version(interface_struct);
4533
4534 if (result != VK_SUCCESS) {
4535 // Layer no longer supports the loader's latest interface version so
4536 // fail loading the Layer
4537 return false;
4538 }
4539 }
4540
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004541 if (interface_struct->loaderLayerInterfaceVersion < MIN_SUPPORTED_LOADER_LAYER_INTERFACE_VERSION) {
Mark Young39389872017-01-19 21:10:49 -07004542 // Loader no longer supports the layer's latest interface version so
4543 // fail loading the layer
4544 return false;
4545 }
4546
4547 return true;
4548}
4549
Mark Young0f183a82017-02-28 09:58:04 -07004550// Given the list of layers to activate in the loader_instance
4551// structure. This function will add a VkLayerInstanceCreateInfo
4552// structure to the VkInstanceCreateInfo.pNext pointer.
4553// Each activated layer will have it's own VkLayerInstanceLink
4554// structure that tells the layer what Get*ProcAddr to call to
4555// get function pointers to the next layer down.
4556// Once the chain info has been created this function will
4557// execute the CreateInstance call chain. Each layer will
4558// then have an opportunity in it's CreateInstance function
4559// to setup it's dispatch table when the lower layer returns
4560// successfully.
4561// Each layer can wrap or not-wrap the returned VkInstance object
4562// as it sees fit.
4563// The instance chain is terminated by a loader function
4564// that will call CreateInstance on all available ICD's and
4565// cache those VkInstance objects for future use.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004566VkResult loader_create_instance_chain(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
4567 struct loader_instance *inst, VkInstance *created_instance) {
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004568 uint32_t activated_layers = 0;
4569 VkLayerInstanceCreateInfo chain_info;
4570 VkLayerInstanceLink *layer_instance_link_info = NULL;
4571 VkInstanceCreateInfo loader_create_info;
4572 VkResult res;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004573
Mark Young39389872017-01-19 21:10:49 -07004574 PFN_vkGetInstanceProcAddr next_gipa = loader_gpa_instance_internal;
4575 PFN_vkGetInstanceProcAddr cur_gipa = loader_gpa_instance_internal;
4576 PFN_GetPhysicalDeviceProcAddr next_gpdpa = loader_gpdpa_instance_internal;
4577 PFN_GetPhysicalDeviceProcAddr cur_gpdpa = loader_gpdpa_instance_internal;
Jon Ashburn27cd5842015-05-12 17:26:48 -06004578
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004579 memcpy(&loader_create_info, pCreateInfo, sizeof(VkInstanceCreateInfo));
Jon Ashburn27cd5842015-05-12 17:26:48 -06004580
Mark Young283fe1c2017-05-04 12:16:35 -06004581 if (inst->expanded_activated_layer_list.count > 0) {
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004582 chain_info.u.pLayerInfo = NULL;
4583 chain_info.pNext = pCreateInfo->pNext;
4584 chain_info.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
4585 chain_info.function = VK_LAYER_LINK_INFO;
4586 loader_create_info.pNext = &chain_info;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004587
Mark Young283fe1c2017-05-04 12:16:35 -06004588 layer_instance_link_info = loader_stack_alloc(sizeof(VkLayerInstanceLink) * inst->expanded_activated_layer_list.count);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004589 if (!layer_instance_link_info) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004590 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4591 "loader_create_instance_chain: Failed to alloc Instance"
4592 " objects for layer");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004593 return VK_ERROR_OUT_OF_HOST_MEMORY;
Jon Ashburn27cd5842015-05-12 17:26:48 -06004594 }
4595
Mark Young39389872017-01-19 21:10:49 -07004596 // Create instance chain of enabled layers
Mark Young283fe1c2017-05-04 12:16:35 -06004597 for (int32_t i = inst->expanded_activated_layer_list.count - 1; i >= 0; i--) {
4598 struct loader_layer_properties *layer_prop = &inst->expanded_activated_layer_list.list[i];
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004599 loader_platform_dl_handle lib_handle;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06004600
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004601 lib_handle = loader_open_layer_lib(inst, "instance", layer_prop);
Mark Young39389872017-01-19 21:10:49 -07004602 if (!lib_handle) {
Courtney Goeltzenleuchter524b7e32016-01-14 16:06:06 -07004603 continue;
Mark Young39389872017-01-19 21:10:49 -07004604 }
4605
4606 if (NULL == layer_prop->functions.negotiate_layer_interface) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004607 PFN_vkNegotiateLoaderLayerInterfaceVersion negotiate_interface = NULL;
Mark Young39389872017-01-19 21:10:49 -07004608 bool functions_in_interface = false;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004609 if (strlen(layer_prop->functions.str_negotiate_interface) == 0) {
4610 negotiate_interface = (PFN_vkNegotiateLoaderLayerInterfaceVersion)loader_platform_get_proc_address(
4611 lib_handle, "vkNegotiateLoaderLayerInterfaceVersion");
Mark Young39389872017-01-19 21:10:49 -07004612 } else {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004613 negotiate_interface = (PFN_vkNegotiateLoaderLayerInterfaceVersion)loader_platform_get_proc_address(
4614 lib_handle, layer_prop->functions.str_negotiate_interface);
Mark Young39389872017-01-19 21:10:49 -07004615 }
4616
4617 // If we can negotiate an interface version, then we can also
4618 // get everything we need from the one function call, so try
4619 // that first, and see if we can get all the function pointers
4620 // necessary from that one call.
4621 if (NULL != negotiate_interface) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004622 layer_prop->functions.negotiate_layer_interface = negotiate_interface;
Mark Young39389872017-01-19 21:10:49 -07004623
4624 VkNegotiateLayerInterface interface_struct;
4625
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004626 if (loader_get_layer_interface_version(negotiate_interface, &interface_struct)) {
Mark Youngdee312c2017-03-08 13:38:35 -07004627 // Go ahead and set the properties version to the
Mark Young39389872017-01-19 21:10:49 -07004628 // correct value.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004629 layer_prop->interface_version = interface_struct.loaderLayerInterfaceVersion;
Mark Young39389872017-01-19 21:10:49 -07004630
4631 // If the interface is 2 or newer, we have access to the
4632 // new GetPhysicalDeviceProcAddr function, so grab it,
4633 // and the other necessary functions, from the
4634 // structure.
4635 if (interface_struct.loaderLayerInterfaceVersion > 1) {
4636 cur_gipa = interface_struct.pfnGetInstanceProcAddr;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004637 cur_gpdpa = interface_struct.pfnGetPhysicalDeviceProcAddr;
Mark Young39389872017-01-19 21:10:49 -07004638 if (cur_gipa != NULL) {
4639 // We've set the functions, so make sure we
4640 // don't do the unnecessary calls later.
4641 functions_in_interface = true;
4642 }
4643 }
4644 }
4645 }
4646
4647 if (!functions_in_interface) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004648 if ((cur_gipa = layer_prop->functions.get_instance_proc_addr) == NULL) {
Mark Young39389872017-01-19 21:10:49 -07004649 if (strlen(layer_prop->functions.str_gipa) == 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004650 cur_gipa =
4651 (PFN_vkGetInstanceProcAddr)loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
4652 layer_prop->functions.get_instance_proc_addr = cur_gipa;
Mark Young39389872017-01-19 21:10:49 -07004653 } else {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004654 cur_gipa = (PFN_vkGetInstanceProcAddr)loader_platform_get_proc_address(lib_handle,
4655 layer_prop->functions.str_gipa);
Mark Young39389872017-01-19 21:10:49 -07004656 }
4657
4658 if (NULL == cur_gipa) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004659 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4660 "loader_create_instance_chain: Failed to"
4661 " find \'vkGetInstanceProcAddr\' in "
4662 "layer %s",
Mark Young39389872017-01-19 21:10:49 -07004663 layer_prop->lib_name);
4664 continue;
4665 }
4666 }
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004667 }
4668 }
4669
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004670 layer_instance_link_info[activated_layers].pNext = chain_info.u.pLayerInfo;
4671 layer_instance_link_info[activated_layers].pfnNextGetInstanceProcAddr = next_gipa;
4672 layer_instance_link_info[activated_layers].pfnNextGetPhysicalDeviceProcAddr = next_gpdpa;
Mark Young39389872017-01-19 21:10:49 -07004673 next_gipa = cur_gipa;
4674 if (layer_prop->interface_version > 1 && cur_gpdpa != NULL) {
4675 layer_prop->functions.get_physical_device_proc_addr = cur_gpdpa;
4676 next_gpdpa = cur_gpdpa;
4677 }
4678
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004679 chain_info.u.pLayerInfo = &layer_instance_link_info[activated_layers];
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004680
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004681 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Insert instance layer %s (%s)", layer_prop->info.layerName,
4682 layer_prop->lib_name);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004683
4684 activated_layers++;
4685 }
Jon Ashburn27cd5842015-05-12 17:26:48 -06004686 }
4687
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004688 PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)next_gipa(*created_instance, "vkCreateInstance");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004689 if (fpCreateInstance) {
Jon Ashburnc3c58772016-03-29 11:16:01 -06004690 VkLayerInstanceCreateInfo create_info_disp;
4691
Jon Ashburncc407a22016-04-15 09:25:03 -06004692 create_info_disp.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
Jon Ashburned8f2312016-03-31 10:52:22 -06004693 create_info_disp.function = VK_LOADER_DATA_CALLBACK;
Jon Ashburnc3c58772016-03-29 11:16:01 -06004694
4695 create_info_disp.u.pfnSetInstanceLoaderData = vkSetInstanceDispatch;
4696
4697 create_info_disp.pNext = loader_create_info.pNext;
4698 loader_create_info.pNext = &create_info_disp;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004699 res = fpCreateInstance(&loader_create_info, pAllocator, created_instance);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004700 } else {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004701 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4702 "loader_create_instance_chain: Failed to find "
4703 "\'vkCreateInstance\'");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004704 // Couldn't find CreateInstance function!
4705 res = VK_ERROR_INITIALIZATION_FAILED;
4706 }
4707
Mark Young39389872017-01-19 21:10:49 -07004708 if (res == VK_SUCCESS) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004709 loader_init_instance_core_dispatch_table(&inst->disp->layer_inst_disp, next_gipa, *created_instance);
Jon Ashburn4e8c4162016-03-08 15:21:30 -07004710 inst->instance = *created_instance;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004711 }
4712
4713 return res;
Jon Ashburn27cd5842015-05-12 17:26:48 -06004714}
4715
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004716void loader_activate_instance_layer_extensions(struct loader_instance *inst, VkInstance created_inst) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004717 loader_init_instance_extension_dispatch_table(&inst->disp->layer_inst_disp, inst->disp->layer_inst_disp.GetInstanceProcAddr,
4718 created_inst);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06004719}
4720
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004721VkResult loader_create_device_chain(const struct loader_physical_device_tramp *pd, const VkDeviceCreateInfo *pCreateInfo,
4722 const VkAllocationCallbacks *pAllocator, const struct loader_instance *inst,
4723 struct loader_device *dev) {
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004724 uint32_t activated_layers = 0;
4725 VkLayerDeviceLink *layer_device_link_info;
4726 VkLayerDeviceCreateInfo chain_info;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004727 VkDeviceCreateInfo loader_create_info;
4728 VkResult res;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06004729
Jamie Madill35127872017-03-15 16:17:46 -04004730 PFN_vkGetDeviceProcAddr fpGDPA = NULL, nextGDPA = loader_gpa_device_internal;
4731 PFN_vkGetInstanceProcAddr fpGIPA = NULL, nextGIPA = loader_gpa_instance_internal;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06004732
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004733 memcpy(&loader_create_info, pCreateInfo, sizeof(VkDeviceCreateInfo));
4734
Lenny Komow82e15e02017-10-02 15:08:53 -06004735 // Before we continue, we need to find out if the KHR_device_group extension is in the enabled list. If it is, we then
4736 // need to look for the corresponding VkDeviceGroupDeviceCreateInfoKHR struct in the device list. This is because we
Mark Young0f183a82017-02-28 09:58:04 -07004737 // need to replace all the incoming physical device values (which are really loader trampoline physical device values)
4738 // with the layer/ICD version.
Lenny Komowa1524852017-10-02 15:08:53 -06004739 {
Mark Young0f183a82017-02-28 09:58:04 -07004740 struct VkStructureHeader *pNext = (struct VkStructureHeader *)loader_create_info.pNext;
4741 struct VkStructureHeader *pPrev = (struct VkStructureHeader *)&loader_create_info;
4742 while (NULL != pNext) {
Lenny Komowa1524852017-10-02 15:08:53 -06004743 if (VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO == pNext->sType) {
Lenny Komow82e15e02017-10-02 15:08:53 -06004744 VkDeviceGroupDeviceCreateInfoKHR *cur_struct = (VkDeviceGroupDeviceCreateInfoKHR *)pNext;
Mark Young0f183a82017-02-28 09:58:04 -07004745 if (0 < cur_struct->physicalDeviceCount && NULL != cur_struct->pPhysicalDevices) {
Lenny Komow82e15e02017-10-02 15:08:53 -06004746 VkDeviceGroupDeviceCreateInfoKHR *temp_struct = loader_stack_alloc(sizeof(VkDeviceGroupDeviceCreateInfoKHR));
Mark Young0f183a82017-02-28 09:58:04 -07004747 VkPhysicalDevice *phys_dev_array = NULL;
4748 if (NULL == temp_struct) {
4749 return VK_ERROR_OUT_OF_HOST_MEMORY;
4750 }
Lenny Komow82e15e02017-10-02 15:08:53 -06004751 memcpy(temp_struct, cur_struct, sizeof(VkDeviceGroupDeviceCreateInfoKHR));
Mark Young0f183a82017-02-28 09:58:04 -07004752 phys_dev_array = loader_stack_alloc(sizeof(VkPhysicalDevice) * cur_struct->physicalDeviceCount);
4753 if (NULL == phys_dev_array) {
4754 return VK_ERROR_OUT_OF_HOST_MEMORY;
4755 }
4756
4757 // Before calling down, replace the incoming physical device values (which are really loader trampoline
4758 // physical devices) with the next layer (or possibly even the terminator) physical device values.
4759 struct loader_physical_device_tramp *cur_tramp;
4760 for (uint32_t phys_dev = 0; phys_dev < cur_struct->physicalDeviceCount; phys_dev++) {
4761 cur_tramp = (struct loader_physical_device_tramp *)cur_struct->pPhysicalDevices[phys_dev];
4762 phys_dev_array[phys_dev] = cur_tramp->phys_dev;
4763 }
4764 temp_struct->pPhysicalDevices = phys_dev_array;
4765
4766 // Replace the old struct in the pNext chain with this one.
4767 pPrev->pNext = (const void *)temp_struct;
4768 pNext = (struct VkStructureHeader *)(temp_struct);
4769 }
4770 break;
4771 }
4772
4773 pPrev = pNext;
4774 pNext = (struct VkStructureHeader *)(pPrev->pNext);
4775 }
4776 }
4777
Mark Young283fe1c2017-05-04 12:16:35 -06004778 layer_device_link_info = loader_stack_alloc(sizeof(VkLayerDeviceLink) * dev->expanded_activated_layer_list.count);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004779 if (!layer_device_link_info) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004780 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4781 "loader_create_device_chain: Failed to alloc Device objects"
4782 " for layer. Skipping Layer.");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004783 return VK_ERROR_OUT_OF_HOST_MEMORY;
David Pinedoa0a8a242015-06-24 15:29:18 -06004784 }
Jon Ashburn94e70492015-06-10 10:13:10 -06004785
Mark Young283fe1c2017-05-04 12:16:35 -06004786 if (dev->expanded_activated_layer_list.count > 0) {
Jon Ashburn72690f22016-03-29 12:52:13 -06004787 chain_info.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO;
4788 chain_info.function = VK_LAYER_LINK_INFO;
4789 chain_info.u.pLayerInfo = NULL;
Mark Young39389872017-01-19 21:10:49 -07004790 chain_info.pNext = loader_create_info.pNext;
Jon Ashburn72690f22016-03-29 12:52:13 -06004791 loader_create_info.pNext = &chain_info;
4792
Mark Young39389872017-01-19 21:10:49 -07004793 // Create instance chain of enabled layers
Mark Young283fe1c2017-05-04 12:16:35 -06004794 for (int32_t i = dev->expanded_activated_layer_list.count - 1; i >= 0; i--) {
4795 struct loader_layer_properties *layer_prop = &dev->expanded_activated_layer_list.list[i];
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004796 loader_platform_dl_handle lib_handle;
Mark Young39389872017-01-19 21:10:49 -07004797 bool functions_in_interface = false;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06004798
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004799 lib_handle = loader_open_layer_lib(inst, "device", layer_prop);
Mark Young39389872017-01-19 21:10:49 -07004800 if (!lib_handle) {
Courtney Goeltzenleuchter524b7e32016-01-14 16:06:06 -07004801 continue;
Jon Ashburn21c21ee2015-09-09 11:29:24 -06004802 }
Mark Young39389872017-01-19 21:10:49 -07004803
Mark Young0f183a82017-02-28 09:58:04 -07004804 // If we can negotiate an interface version, then we can also get everything we need from the one function
4805 // 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 -07004806 if (NULL == layer_prop->functions.negotiate_layer_interface) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004807 PFN_vkNegotiateLoaderLayerInterfaceVersion negotiate_interface = NULL;
4808 if (strlen(layer_prop->functions.str_negotiate_interface) == 0) {
4809 negotiate_interface = (PFN_vkNegotiateLoaderLayerInterfaceVersion)loader_platform_get_proc_address(
4810 lib_handle, "vkNegotiateLoaderLayerInterfaceVersion");
Mark Young39389872017-01-19 21:10:49 -07004811 } else {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004812 negotiate_interface = (PFN_vkNegotiateLoaderLayerInterfaceVersion)loader_platform_get_proc_address(
4813 lib_handle, layer_prop->functions.str_negotiate_interface);
Mark Young39389872017-01-19 21:10:49 -07004814 }
4815
4816 if (NULL != negotiate_interface) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004817 layer_prop->functions.negotiate_layer_interface = negotiate_interface;
Mark Young39389872017-01-19 21:10:49 -07004818
4819 VkNegotiateLayerInterface interface_struct;
4820
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004821 if (loader_get_layer_interface_version(negotiate_interface, &interface_struct)) {
Mark Youngdee312c2017-03-08 13:38:35 -07004822 // Go ahead and set the properties version to the correct value.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004823 layer_prop->interface_version = interface_struct.loaderLayerInterfaceVersion;
Mark Young39389872017-01-19 21:10:49 -07004824
Mark Young0f183a82017-02-28 09:58:04 -07004825 // If the interface is 2 or newer, we have access to the new GetPhysicalDeviceProcAddr
4826 // function, so grab it, and the other necessary functions, from the structure.
Mark Young39389872017-01-19 21:10:49 -07004827 if (interface_struct.loaderLayerInterfaceVersion > 1) {
4828 fpGIPA = interface_struct.pfnGetInstanceProcAddr;
4829 fpGDPA = interface_struct.pfnGetDeviceProcAddr;
4830 if (fpGIPA != NULL && fpGDPA) {
4831 // We've set the functions, so make sure we
4832 // don't do the unnecessary calls later.
4833 functions_in_interface = true;
4834 }
4835 }
4836 }
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004837 }
4838 }
4839
Mark Young39389872017-01-19 21:10:49 -07004840 if (!functions_in_interface) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004841 if ((fpGIPA = layer_prop->functions.get_instance_proc_addr) == NULL) {
Mark Young39389872017-01-19 21:10:49 -07004842 if (strlen(layer_prop->functions.str_gipa) == 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004843 fpGIPA = (PFN_vkGetInstanceProcAddr)loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
Mark Young39389872017-01-19 21:10:49 -07004844 layer_prop->functions.get_instance_proc_addr = fpGIPA;
4845 } else
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004846 fpGIPA =
4847 (PFN_vkGetInstanceProcAddr)loader_platform_get_proc_address(lib_handle, layer_prop->functions.str_gipa);
Mark Young39389872017-01-19 21:10:49 -07004848 if (!fpGIPA) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004849 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4850 "loader_create_device_chain: Failed to find "
4851 "\'vkGetInstanceProcAddr\' in layer %s. Skipping"
4852 " layer.",
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004853 layer_prop->lib_name);
Mark Young39389872017-01-19 21:10:49 -07004854 continue;
4855 }
4856 }
4857 if ((fpGDPA = layer_prop->functions.get_device_proc_addr) == NULL) {
4858 if (strlen(layer_prop->functions.str_gdpa) == 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004859 fpGDPA = (PFN_vkGetDeviceProcAddr)loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr");
Mark Young39389872017-01-19 21:10:49 -07004860 layer_prop->functions.get_device_proc_addr = fpGDPA;
4861 } else
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004862 fpGDPA =
4863 (PFN_vkGetDeviceProcAddr)loader_platform_get_proc_address(lib_handle, layer_prop->functions.str_gdpa);
Mark Young39389872017-01-19 21:10:49 -07004864 if (!fpGDPA) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004865 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Failed to find vkGetDeviceProcAddr in layer %s",
4866 layer_prop->lib_name);
Mark Young39389872017-01-19 21:10:49 -07004867 continue;
4868 }
4869 }
4870 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004871 layer_device_link_info[activated_layers].pNext = chain_info.u.pLayerInfo;
4872 layer_device_link_info[activated_layers].pfnNextGetInstanceProcAddr = nextGIPA;
4873 layer_device_link_info[activated_layers].pfnNextGetDeviceProcAddr = nextGDPA;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004874 chain_info.u.pLayerInfo = &layer_device_link_info[activated_layers];
4875 nextGIPA = fpGIPA;
4876 nextGDPA = fpGDPA;
4877
Lenny Komow7ddd4322017-10-16 15:03:37 -06004878 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 -07004879 layer_prop->lib_name);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004880
4881 activated_layers++;
Jon Ashburn94e70492015-06-10 10:13:10 -06004882 }
Jon Ashburn94e70492015-06-10 10:13:10 -06004883 }
4884
Jon Ashburncc407a22016-04-15 09:25:03 -06004885 VkDevice created_device = (VkDevice)dev;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004886 PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)nextGIPA(inst->instance, "vkCreateDevice");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004887 if (fpCreateDevice) {
Jon Ashburned8f2312016-03-31 10:52:22 -06004888 VkLayerDeviceCreateInfo create_info_disp;
4889
Jon Ashburncc407a22016-04-15 09:25:03 -06004890 create_info_disp.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO;
Jon Ashburned8f2312016-03-31 10:52:22 -06004891 create_info_disp.function = VK_LOADER_DATA_CALLBACK;
4892
4893 create_info_disp.u.pfnSetDeviceLoaderData = vkSetDeviceDispatch;
4894
4895 create_info_disp.pNext = loader_create_info.pNext;
4896 loader_create_info.pNext = &create_info_disp;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004897 res = fpCreateDevice(pd->phys_dev, &loader_create_info, pAllocator, &created_device);
Piers Daniellefbbfc12016-04-05 17:28:06 -06004898 if (res != VK_SUCCESS) {
4899 return res;
4900 }
Mark Young65cb3662016-11-07 13:27:02 -07004901 dev->chain_device = created_device;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004902 } else {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004903 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4904 "loader_create_device_chain: Failed to find \'vkCreateDevice\' "
4905 "in layer %s");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004906 // Couldn't find CreateDevice function!
4907 return VK_ERROR_INITIALIZATION_FAILED;
4908 }
Jon Ashburn94e70492015-06-10 10:13:10 -06004909
Mark Young65cb3662016-11-07 13:27:02 -07004910 // Initialize device dispatch table
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004911 loader_init_device_dispatch_table(&dev->loader_dispatch, nextGDPA, dev->chain_device);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004912
4913 return res;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06004914}
Jon Ashburnd38bfb12014-10-14 19:15:22 -06004915
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004916VkResult loader_validate_layers(const struct loader_instance *inst, const uint32_t layer_count,
4917 const char *const *ppEnabledLayerNames, const struct loader_layer_list *list) {
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06004918 struct loader_layer_properties *prop;
4919
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004920 for (uint32_t i = 0; i < layer_count; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004921 VkStringErrorFlags result = vk_string_validate(MaxLoaderStringLength, ppEnabledLayerNames[i]);
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004922 if (result != VK_STRING_ERROR_NONE) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004923 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4924 "loader_validate_layers: Device ppEnabledLayerNames "
4925 "contains string that is too long or is badly formed");
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004926 return VK_ERROR_LAYER_NOT_PRESENT;
4927 }
4928
Jon Ashburn23d36b12016-02-02 17:47:28 -07004929 prop = loader_get_layer_property(ppEnabledLayerNames[i], list);
Mark Youngf2079b92017-05-02 10:49:46 -06004930 if (NULL == prop) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004931 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngc8b807a2017-07-14 17:11:31 -06004932 "loader_validate_layers: Layer %d does not exist in the list of available layers", i);
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06004933 return VK_ERROR_LAYER_NOT_PRESENT;
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06004934 }
4935 }
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06004936 return VK_SUCCESS;
4937}
4938
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004939VkResult loader_validate_instance_extensions(const struct loader_instance *inst, const struct loader_extension_list *icd_exts,
4940 const struct loader_layer_list *instance_layers,
4941 const VkInstanceCreateInfo *pCreateInfo) {
Jon Ashburn5c042ea2015-08-04 11:14:18 -06004942 VkExtensionProperties *extension_prop;
Mark Young48cea0c2017-05-26 14:39:54 -06004943 char *env_value;
4944 bool check_if_known = true;
Lenny Komow3b958392018-01-17 13:53:59 -07004945 VkResult res = VK_SUCCESS;
4946
4947 struct loader_layer_list active_layers;
4948 struct loader_layer_list expanded_layers;
4949 memset(&active_layers, 0, sizeof(active_layers));
4950 memset(&expanded_layers, 0, sizeof(expanded_layers));
4951 if (!loader_init_layer_list(inst, &active_layers)) {
4952 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4953 goto out;
4954 }
4955 if (!loader_init_layer_list(inst, &expanded_layers)) {
4956 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4957 goto out;
4958 }
4959
4960 // Build the lists of active layers (including metalayers) and expanded layers (with metalayers resolved to their components)
4961 loader_add_implicit_layers(inst, &active_layers, &expanded_layers, instance_layers);
4962 loader_add_env_layers(inst, VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER, ENABLED_LAYERS_ENV, &active_layers, &expanded_layers,
4963 instance_layers);
4964 res = loader_add_layer_names_to_list(inst, &active_layers, &expanded_layers, pCreateInfo->enabledLayerCount,
4965 pCreateInfo->ppEnabledLayerNames, instance_layers);
4966 if (VK_SUCCESS != res) {
4967 goto out;
4968 }
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004969
Jon Ashburnf19916e2016-01-11 13:12:43 -07004970 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004971 VkStringErrorFlags result = vk_string_validate(MaxLoaderStringLength, pCreateInfo->ppEnabledExtensionNames[i]);
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004972 if (result != VK_STRING_ERROR_NONE) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004973 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young48cea0c2017-05-26 14:39:54 -06004974 "loader_validate_instance_extensions: Instance ppEnabledExtensionNames contains "
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004975 "string that is too long or is badly formed");
Lenny Komow3b958392018-01-17 13:53:59 -07004976 res = VK_ERROR_EXTENSION_NOT_PRESENT;
4977 goto out;
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004978 }
4979
Mark Young48cea0c2017-05-26 14:39:54 -06004980 // Check if a user wants to disable the instance extension filtering behavior
4981 env_value = loader_getenv("VK_LOADER_DISABLE_INST_EXT_FILTER", inst);
4982 if (NULL != env_value && atoi(env_value) != 0) {
4983 check_if_known = false;
Lenny Komow4053b812016-12-29 16:27:28 -07004984 }
Mark Young48cea0c2017-05-26 14:39:54 -06004985 loader_free_getenv(env_value, inst);
Lenny Komow4053b812016-12-29 16:27:28 -07004986
Mark Young48cea0c2017-05-26 14:39:54 -06004987 if (check_if_known) {
4988 // See if the extension is in the list of supported extensions
4989 bool found = false;
4990 for (uint32_t j = 0; LOADER_INSTANCE_EXTENSIONS[j] != NULL; j++) {
4991 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], LOADER_INSTANCE_EXTENSIONS[j]) == 0) {
4992 found = true;
4993 break;
4994 }
4995 }
4996
4997 // If it isn't in the list, return an error
4998 if (!found) {
4999 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5000 "loader_validate_instance_extensions: Extension %s not found in list of known instance extensions.",
5001 pCreateInfo->ppEnabledExtensionNames[i]);
Lenny Komow3b958392018-01-17 13:53:59 -07005002 res = VK_ERROR_EXTENSION_NOT_PRESENT;
5003 goto out;
Mark Young48cea0c2017-05-26 14:39:54 -06005004 }
Lenny Komow4053b812016-12-29 16:27:28 -07005005 }
5006
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005007 extension_prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i], icd_exts);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06005008
5009 if (extension_prop) {
5010 continue;
5011 }
5012
5013 extension_prop = NULL;
5014
Lenny Komow3b958392018-01-17 13:53:59 -07005015 // Not in global list, search expanded layer extension list
5016 for (uint32_t j = 0; NULL == extension_prop && j < expanded_layers.count; ++j) {
5017 extension_prop =
5018 get_extension_property(pCreateInfo->ppEnabledExtensionNames[i], &expanded_layers.list[j].instance_extension_list);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06005019 }
5020
5021 if (!extension_prop) {
Mark Youngb6399312017-01-10 14:22:15 -07005022 // Didn't find extension name in any of the global layers, error out
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005023 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young48cea0c2017-05-26 14:39:54 -06005024 "loader_validate_instance_extensions: Instance extension %s not supported by available ICDs or enabled "
5025 "layers.",
5026 pCreateInfo->ppEnabledExtensionNames[i]);
Lenny Komow3b958392018-01-17 13:53:59 -07005027 res = VK_ERROR_EXTENSION_NOT_PRESENT;
5028 goto out;
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06005029 }
5030 }
Lenny Komow3b958392018-01-17 13:53:59 -07005031
5032out:
5033 loader_destroy_layer_list(inst, NULL, &active_layers);
5034 loader_destroy_layer_list(inst, NULL, &expanded_layers);
5035 return res;
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06005036}
5037
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005038VkResult loader_validate_device_extensions(struct loader_physical_device_tramp *phys_dev,
5039 const struct loader_layer_list *activated_device_layers,
5040 const struct loader_extension_list *icd_exts, const VkDeviceCreateInfo *pCreateInfo) {
Jon Ashburn5c042ea2015-08-04 11:14:18 -06005041 VkExtensionProperties *extension_prop;
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06005042 struct loader_layer_properties *layer_prop;
5043
Jon Ashburnf19916e2016-01-11 13:12:43 -07005044 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005045 VkStringErrorFlags result = vk_string_validate(MaxLoaderStringLength, pCreateInfo->ppEnabledExtensionNames[i]);
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07005046 if (result != VK_STRING_ERROR_NONE) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005047 loader_log(phys_dev->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young48cea0c2017-05-26 14:39:54 -06005048 "loader_validate_device_extensions: Device ppEnabledExtensionNames contains "
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005049 "string that is too long or is badly formed");
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07005050 return VK_ERROR_EXTENSION_NOT_PRESENT;
5051 }
5052
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06005053 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
Jon Ashburn014438f2016-03-01 19:51:07 -07005054 extension_prop = get_extension_property(extension_name, icd_exts);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06005055
5056 if (extension_prop) {
5057 continue;
5058 }
5059
Mark Youngb6399312017-01-10 14:22:15 -07005060 // Not in global list, search activated layer extension lists
Jon Ashburn471f44c2016-01-13 12:51:43 -07005061 for (uint32_t j = 0; j < activated_device_layers->count; j++) {
5062 layer_prop = &activated_device_layers->list[j];
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06005063
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005064 extension_prop = get_dev_extension_property(extension_name, &layer_prop->device_extension_list);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06005065 if (extension_prop) {
Mark Youngb6399312017-01-10 14:22:15 -07005066 // Found the extension in one of the layers enabled by the app.
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06005067 break;
5068 }
5069 }
5070
5071 if (!extension_prop) {
Mark Youngb6399312017-01-10 14:22:15 -07005072 // Didn't find extension name in any of the device layers, error out
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005073 loader_log(phys_dev->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young48cea0c2017-05-26 14:39:54 -06005074 "loader_validate_device_extensions: Device extension %s not supported by selected physical device "
5075 "or enabled layers.",
5076 pCreateInfo->ppEnabledExtensionNames[i]);
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06005077 return VK_ERROR_EXTENSION_NOT_PRESENT;
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06005078 }
5079 }
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06005080 return VK_SUCCESS;
5081}
5082
Mark Youngb6399312017-01-10 14:22:15 -07005083// Terminator functions for the Instance chain
5084// All named terminator_<Vulakn API name>
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005085VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
5086 const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) {
Mark Young0153e0b2016-11-03 14:27:13 -06005087 struct loader_icd_term *icd_term;
Jon Ashburn5c042ea2015-08-04 11:14:18 -06005088 VkExtensionProperties *prop;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06005089 char **filtered_extension_names = NULL;
5090 VkInstanceCreateInfo icd_create_info;
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06005091 VkResult res = VK_SUCCESS;
Mark Young8b4edb52016-11-11 09:31:55 -07005092 bool one_icd_successful = false;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07005093
Jon Ashburncc407a22016-04-15 09:25:03 -06005094 struct loader_instance *ptr_instance = (struct loader_instance *)*pInstance;
Tony Barbour3c78ff42015-12-04 13:24:39 -07005095 memcpy(&icd_create_info, pCreateInfo, sizeof(icd_create_info));
5096
Jon Ashburnf19916e2016-01-11 13:12:43 -07005097 icd_create_info.enabledLayerCount = 0;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06005098 icd_create_info.ppEnabledLayerNames = NULL;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06005099
Mark Youngb6399312017-01-10 14:22:15 -07005100 // NOTE: Need to filter the extensions to only those supported by the ICD.
5101 // No ICD will advertise support for layers. An ICD library could
5102 // support a layer, but it would be independent of the actual ICD,
5103 // just in the same library.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005104 filtered_extension_names = loader_stack_alloc(pCreateInfo->enabledExtensionCount * sizeof(char *));
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06005105 if (!filtered_extension_names) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005106 loader_log(ptr_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young48cea0c2017-05-26 14:39:54 -06005107 "terminator_CreateInstance: Failed create extension name array for %d extensions",
Mark Youngb6399312017-01-10 14:22:15 -07005108 pCreateInfo->enabledExtensionCount);
Mark Young3a587792016-08-19 15:25:08 -06005109 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5110 goto out;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06005111 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005112 icd_create_info.ppEnabledExtensionNames = (const char *const *)filtered_extension_names;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06005113
Mark Young0153e0b2016-11-03 14:27:13 -06005114 for (uint32_t i = 0; i < ptr_instance->icd_tramp_list.count; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005115 icd_term = loader_icd_add(ptr_instance, &ptr_instance->icd_tramp_list.scanned_list[i]);
Mark Young0153e0b2016-11-03 14:27:13 -06005116 if (NULL == icd_term) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005117 loader_log(ptr_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngc8b807a2017-07-14 17:11:31 -06005118 "terminator_CreateInstance: Failed to add ICD %d to ICD trampoline list.", i);
Mark Young3a587792016-08-19 15:25:08 -06005119 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5120 goto out;
Mark Young0ad83132016-06-30 13:02:42 -06005121 }
Mark Young6267ae62017-01-12 12:27:19 -07005122
Lenny Komowa44cc852017-09-12 22:54:21 -06005123 // If any error happens after here, we need to remove the ICD from the list,
5124 // because we've already added it, but haven't validated it
5125
Mark Young0ad83132016-06-30 13:02:42 -06005126 icd_create_info.enabledExtensionCount = 0;
5127 struct loader_extension_list icd_exts;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06005128
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005129 loader_log(ptr_instance, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Build ICD instance extension list");
Mark Young0f183a82017-02-28 09:58:04 -07005130 // traverse scanned icd list adding non-duplicate extensions to the list
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005131 res = loader_init_generic_list(ptr_instance, (struct loader_generic_list *)&icd_exts, sizeof(VkExtensionProperties));
Mark Young3a587792016-08-19 15:25:08 -06005132 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
5133 // If out of memory, bail immediately.
5134 goto out;
5135 } else if (VK_SUCCESS != res) {
Mark Young7e471292016-09-06 09:53:45 -06005136 // Something bad happened with this ICD, so free it and try the
5137 // next.
Mark Young0153e0b2016-11-03 14:27:13 -06005138 ptr_instance->icd_terms = icd_term->next;
5139 icd_term->next = NULL;
5140 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
Mark Young3a587792016-08-19 15:25:08 -06005141 continue;
5142 }
5143
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005144 res = loader_add_instance_extensions(ptr_instance, icd_term->scanned_icd->EnumerateInstanceExtensionProperties,
5145 icd_term->scanned_icd->lib_name, &icd_exts);
Mark Youngdb13a2a2016-09-06 13:53:03 -06005146 if (VK_SUCCESS != res) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005147 loader_destroy_generic_list(ptr_instance, (struct loader_generic_list *)&icd_exts);
Mark Youngdb13a2a2016-09-06 13:53:03 -06005148 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
5149 // If out of memory, bail immediately.
5150 goto out;
5151 } else {
Mark Young0f183a82017-02-28 09:58:04 -07005152 // Something bad happened with this ICD, so free it and try the next.
Mark Young0153e0b2016-11-03 14:27:13 -06005153 ptr_instance->icd_terms = icd_term->next;
5154 icd_term->next = NULL;
5155 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
Mark Youngdb13a2a2016-09-06 13:53:03 -06005156 continue;
5157 }
Mark Young3a587792016-08-19 15:25:08 -06005158 }
Courtney Goeltzenleuchter36eeb742015-12-21 16:41:47 -07005159
Mark Young0ad83132016-06-30 13:02:42 -06005160 for (uint32_t j = 0; j < pCreateInfo->enabledExtensionCount; j++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005161 prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[j], &icd_exts);
Mark Young0ad83132016-06-30 13:02:42 -06005162 if (prop) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005163 filtered_extension_names[icd_create_info.enabledExtensionCount] = (char *)pCreateInfo->ppEnabledExtensionNames[j];
Mark Young0ad83132016-06-30 13:02:42 -06005164 icd_create_info.enabledExtensionCount++;
Jon Ashburn46888392015-01-29 15:45:51 -07005165 }
5166 }
Mark Young0ad83132016-06-30 13:02:42 -06005167
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005168 loader_destroy_generic_list(ptr_instance, (struct loader_generic_list *)&icd_exts);
Mark Young0ad83132016-06-30 13:02:42 -06005169
Lenny Komowe12b3362017-11-03 13:14:32 -06005170 // Get the driver version from vkEnumerateInstanceVersion
5171 uint32_t icd_version = VK_API_VERSION_1_0;
5172 PFN_vkEnumerateInstanceVersion icd_enumerate_instance_version = (PFN_vkEnumerateInstanceVersion)
5173 loader_platform_get_proc_address(icd_term->scanned_icd->handle, "vkEnumerateInstanceVersion");
5174 VkResult icd_result = VK_SUCCESS;
5175 if (icd_enumerate_instance_version != NULL) {
5176 icd_result = icd_enumerate_instance_version(&icd_version);
5177 if (icd_result != VK_SUCCESS) {
5178 icd_version = VK_API_VERSION_1_0;
5179 loader_log(ptr_instance, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "terminator_CreateInstance: ICD \"%s\" "
5180 "vkEnumerateInstanceVersion returned error. The ICD will be treated as a 1.0 ICD",
5181 icd_term->scanned_icd->lib_name);
5182 }
5183 }
5184
Lenny Komowa1524852017-10-02 15:08:53 -06005185 // Create an instance, substituting the version to 1.0 if necessary
Lenny Komow838df732017-10-11 13:39:33 -06005186 VkApplicationInfo icd_app_info;
Lenny Komow05c419b2017-10-11 09:20:52 -06005187 uint32_t requested_version = pCreateInfo == NULL || pCreateInfo->pApplicationInfo == NULL ? VK_API_VERSION_1_0 : pCreateInfo->pApplicationInfo->apiVersion;
Lenny Komowe12b3362017-11-03 13:14:32 -06005188 if (requested_version > icd_version) {
Lenny Komowa1524852017-10-02 15:08:53 -06005189 if (icd_create_info.pApplicationInfo == NULL) {
5190 memset(&icd_app_info, 0, sizeof(icd_app_info));
5191 } else {
5192 memcpy(&icd_app_info, icd_create_info.pApplicationInfo, sizeof(icd_app_info));
5193 }
5194 icd_app_info.apiVersion = icd_term->scanned_icd->api_version;
5195 icd_create_info.pApplicationInfo = &icd_app_info;
5196 }
Lenny Komowe12b3362017-11-03 13:14:32 -06005197 icd_result = ptr_instance->icd_tramp_list.scanned_list[i].CreateInstance(&icd_create_info, pAllocator, &(icd_term->instance));
Mark Young8b4edb52016-11-11 09:31:55 -07005198 if (VK_ERROR_OUT_OF_HOST_MEMORY == icd_result) {
Mark Young3a587792016-08-19 15:25:08 -06005199 // If out of memory, bail immediately.
Mark Young8b4edb52016-11-11 09:31:55 -07005200 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young3a587792016-08-19 15:25:08 -06005201 goto out;
Mark Young8b4edb52016-11-11 09:31:55 -07005202 } else if (VK_SUCCESS != icd_result) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005203 loader_log(ptr_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
5204 "terminator_CreateInstance: Failed to CreateInstance in "
5205 "ICD %d. Skipping ICD.",
Mark Youngb6399312017-01-10 14:22:15 -07005206 i);
Mark Young0153e0b2016-11-03 14:27:13 -06005207 ptr_instance->icd_terms = icd_term->next;
5208 icd_term->next = NULL;
5209 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
Mark Young3a587792016-08-19 15:25:08 -06005210 continue;
5211 }
Mark Young0ad83132016-06-30 13:02:42 -06005212
Mark Young0f183a82017-02-28 09:58:04 -07005213 if (!loader_icd_init_entries(icd_term, icd_term->instance,
5214 ptr_instance->icd_tramp_list.scanned_list[i].GetInstanceProcAddr)) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005215 loader_log(ptr_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
5216 "terminator_CreateInstance: Failed to CreateInstance and find "
5217 "entrypoints with ICD. Skipping ICD.");
Lenny Komowa44cc852017-09-12 22:54:21 -06005218 ptr_instance->icd_terms = icd_term->next;
5219 icd_term->next = NULL;
5220 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
Mark Young3a587792016-08-19 15:25:08 -06005221 continue;
Mark Young0ad83132016-06-30 13:02:42 -06005222 }
Mark Young8b4edb52016-11-11 09:31:55 -07005223
5224 // If we made it this far, at least one ICD was successful
5225 one_icd_successful = true;
Jon Ashburn46888392015-01-29 15:45:51 -07005226 }
Jon Ashburn1beab2d2015-01-26 14:51:40 -07005227
Mark Young0f183a82017-02-28 09:58:04 -07005228 // If no ICDs were added to instance list and res is unchanged from it's initial value, the loader was unable to
5229 // find a suitable ICD.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005230 if (VK_SUCCESS == res && (ptr_instance->icd_terms == NULL || !one_icd_successful)) {
Mark Young3a587792016-08-19 15:25:08 -06005231 res = VK_ERROR_INCOMPATIBLE_DRIVER;
5232 }
5233
5234out:
5235
5236 if (VK_SUCCESS != res) {
Mark Young0153e0b2016-11-03 14:27:13 -06005237 while (NULL != ptr_instance->icd_terms) {
5238 icd_term = ptr_instance->icd_terms;
5239 ptr_instance->icd_terms = icd_term->next;
5240 if (NULL != icd_term->instance) {
Mark Young0f183a82017-02-28 09:58:04 -07005241 icd_term->dispatch.DestroyInstance(icd_term->instance, pAllocator);
Mark Young3a587792016-08-19 15:25:08 -06005242 }
Mark Young0153e0b2016-11-03 14:27:13 -06005243 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06005244 }
Ian Elliotteb450762015-02-05 15:19:15 -07005245 }
Jon Ashburn46888392015-01-29 15:45:51 -07005246
Mark Young3a587792016-08-19 15:25:08 -06005247 return res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07005248}
5249
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005250VKAPI_ATTR void VKAPI_CALL terminator_DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
Courtney Goeltzenleuchterdeceded2015-06-08 15:04:02 -06005251 struct loader_instance *ptr_instance = loader_instance(instance);
Karl Schultze2ef9e62017-01-13 14:01:35 -07005252 if (NULL == ptr_instance) {
5253 return;
5254 }
Mark Young0153e0b2016-11-03 14:27:13 -06005255 struct loader_icd_term *icd_terms = ptr_instance->icd_terms;
5256 struct loader_icd_term *next_icd_term;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07005257
5258 // Remove this instance from the list of instances:
5259 struct loader_instance *prev = NULL;
5260 struct loader_instance *next = loader.instances;
5261 while (next != NULL) {
5262 if (next == ptr_instance) {
5263 // Remove this instance from the list:
5264 if (prev)
5265 prev->next = next->next;
Jon Ashburnc5c49602015-02-03 09:26:59 -07005266 else
5267 loader.instances = next->next;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07005268 break;
5269 }
5270 prev = next;
5271 next = next->next;
5272 }
Jon Ashburn1beab2d2015-01-26 14:51:40 -07005273
Mark Young0153e0b2016-11-03 14:27:13 -06005274 while (NULL != icd_terms) {
5275 if (icd_terms->instance) {
Mark Young0f183a82017-02-28 09:58:04 -07005276 icd_terms->dispatch.DestroyInstance(icd_terms->instance, pAllocator);
Tony Barbourf20f87b2015-04-22 09:02:32 -06005277 }
Mark Young0153e0b2016-11-03 14:27:13 -06005278 next_icd_term = icd_terms->next;
5279 icd_terms->instance = VK_NULL_HANDLE;
5280 loader_icd_destroy(ptr_instance, icd_terms, pAllocator);
Jon Ashburna6fd2612015-06-16 14:43:19 -06005281
Mark Young0153e0b2016-11-03 14:27:13 -06005282 icd_terms = next_icd_term;
Jon Ashburn46888392015-01-29 15:45:51 -07005283 }
Jon Ashburn491cd042016-05-16 14:01:18 -06005284
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005285 loader_delete_layer_properties(ptr_instance, &ptr_instance->instance_layer_list);
Mark Young0153e0b2016-11-03 14:27:13 -06005286 loader_scanned_icd_clear(ptr_instance, &ptr_instance->icd_tramp_list);
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005287 loader_destroy_generic_list(ptr_instance, (struct loader_generic_list *)&ptr_instance->ext_list);
Mark Young39389872017-01-19 21:10:49 -07005288 if (NULL != ptr_instance->phys_devs_term) {
Mark Young0193d652016-12-28 16:10:10 -07005289 for (uint32_t i = 0; i < ptr_instance->phys_dev_count_term; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005290 loader_instance_heap_free(ptr_instance, ptr_instance->phys_devs_term[i]);
Lenny Komow8a1f8a52016-12-20 15:35:11 -07005291 }
Mark Young0ad83132016-06-30 13:02:42 -06005292 loader_instance_heap_free(ptr_instance, ptr_instance->phys_devs_term);
Lenny Komow8a1f8a52016-12-20 15:35:11 -07005293 }
Mark Youngd66edd52017-03-10 17:31:18 -07005294 if (NULL != ptr_instance->phys_dev_groups_term) {
5295 for (uint32_t i = 0; i < ptr_instance->phys_dev_group_count_term; i++) {
5296 loader_instance_heap_free(ptr_instance, ptr_instance->phys_dev_groups_term[i]);
5297 }
5298 loader_instance_heap_free(ptr_instance, ptr_instance->phys_dev_groups_term);
5299 }
Jon Ashburnfc1031e2015-11-17 15:31:02 -07005300 loader_free_dev_ext_table(ptr_instance);
Mark Young39389872017-01-19 21:10:49 -07005301 loader_free_phys_dev_ext_table(ptr_instance);
Jon Ashburn1beab2d2015-01-26 14:51:40 -07005302}
5303
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005304VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo,
5305 const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
Mark Young0ad83132016-06-30 13:02:42 -06005306 VkResult res = VK_SUCCESS;
Mark Young0153e0b2016-11-03 14:27:13 -06005307 struct loader_physical_device_term *phys_dev_term;
5308 phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
5309 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Jon Ashburn24cd4be2015-11-01 14:04:06 -07005310
Jon Ashburncc407a22016-04-15 09:25:03 -06005311 struct loader_device *dev = (struct loader_device *)*pDevice;
Mark Young0f183a82017-02-28 09:58:04 -07005312 PFN_vkCreateDevice fpCreateDevice = icd_term->dispatch.CreateDevice;
Mark Young0ad83132016-06-30 13:02:42 -06005313 struct loader_extension_list icd_exts;
5314
Joey Bzdekc2536de2017-10-23 17:13:33 -06005315 struct VkStructureHeader *caller_dgci_container = NULL;
5316 VkDeviceGroupDeviceCreateInfoKHX *caller_dgci = NULL;
5317
Mark Young65cb3662016-11-07 13:27:02 -07005318 dev->phys_dev_term = phys_dev_term;
5319
Mark Young0ad83132016-06-30 13:02:42 -06005320 icd_exts.list = NULL;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06005321
Jon Ashburn1530c342016-02-26 13:14:27 -07005322 if (fpCreateDevice == NULL) {
Mark Young0153e0b2016-11-03 14:27:13 -06005323 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07005324 "terminator_CreateDevice: No vkCreateDevice command exposed "
5325 "by ICD %s",
Mark Young0153e0b2016-11-03 14:27:13 -06005326 icd_term->scanned_icd->lib_name);
Mark Young0ad83132016-06-30 13:02:42 -06005327 res = VK_ERROR_INITIALIZATION_FAILED;
5328 goto out;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06005329 }
5330
Jon Ashburn1530c342016-02-26 13:14:27 -07005331 VkDeviceCreateInfo localCreateInfo;
5332 memcpy(&localCreateInfo, pCreateInfo, sizeof(localCreateInfo));
Jon Ashburn1530c342016-02-26 13:14:27 -07005333
Mark Youngb6399312017-01-10 14:22:15 -07005334 // NOTE: Need to filter the extensions to only those supported by the ICD.
Mark Younge1ea9012017-03-09 14:17:40 -07005335 // No ICD will advertise support for layers. An ICD library could support a layer,
5336 // but it would be independent of the actual ICD, just in the same library.
Jon Ashburn1530c342016-02-26 13:14:27 -07005337 char **filtered_extension_names = NULL;
Mark Younge1ea9012017-03-09 14:17:40 -07005338 if (0 < pCreateInfo->enabledExtensionCount) {
5339 filtered_extension_names = loader_stack_alloc(pCreateInfo->enabledExtensionCount * sizeof(char *));
5340 if (NULL == filtered_extension_names) {
5341 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5342 "terminator_CreateDevice: Failed to create extension name "
5343 "storage for %d extensions %d",
5344 pCreateInfo->enabledExtensionCount);
5345 return VK_ERROR_OUT_OF_HOST_MEMORY;
5346 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06005347 }
5348
Jon Ashburn1530c342016-02-26 13:14:27 -07005349 localCreateInfo.enabledLayerCount = 0;
5350 localCreateInfo.ppEnabledLayerNames = NULL;
5351
5352 localCreateInfo.enabledExtensionCount = 0;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005353 localCreateInfo.ppEnabledExtensionNames = (const char *const *)filtered_extension_names;
Jon Ashburn1530c342016-02-26 13:14:27 -07005354
Mark Youngb6399312017-01-10 14:22:15 -07005355 // Get the physical device (ICD) extensions
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005356 res = loader_init_generic_list(icd_term->this_instance, (struct loader_generic_list *)&icd_exts, sizeof(VkExtensionProperties));
Mark Young3a587792016-08-19 15:25:08 -06005357 if (VK_SUCCESS != res) {
Mark Young0ad83132016-06-30 13:02:42 -06005358 goto out;
Jon Ashburn014438f2016-03-01 19:51:07 -07005359 }
5360
Mark Young0f183a82017-02-28 09:58:04 -07005361 res = loader_add_device_extensions(icd_term->this_instance, icd_term->dispatch.EnumerateDeviceExtensionProperties,
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005362 phys_dev_term->phys_dev, icd_term->scanned_icd->lib_name, &icd_exts);
Jon Ashburn014438f2016-03-01 19:51:07 -07005363 if (res != VK_SUCCESS) {
Mark Young0ad83132016-06-30 13:02:42 -06005364 goto out;
Jon Ashburn014438f2016-03-01 19:51:07 -07005365 }
5366
Jon Ashburn1530c342016-02-26 13:14:27 -07005367 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
5368 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005369 VkExtensionProperties *prop = get_extension_property(extension_name, &icd_exts);
Jon Ashburn1530c342016-02-26 13:14:27 -07005370 if (prop) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005371 filtered_extension_names[localCreateInfo.enabledExtensionCount] = (char *)extension_name;
Jon Ashburn1530c342016-02-26 13:14:27 -07005372 localCreateInfo.enabledExtensionCount++;
Mark Young9a3ddd42016-10-21 16:25:47 -06005373 } else {
Lenny Komow8314e542018-01-03 10:37:54 -07005374 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005375 "vkCreateDevice extension %s not available for "
5376 "devices associated with ICD %s",
Mark Young0153e0b2016-11-03 14:27:13 -06005377 extension_name, icd_term->scanned_icd->lib_name);
Jon Ashburn1530c342016-02-26 13:14:27 -07005378 }
5379 }
5380
Mark Young0f183a82017-02-28 09:58:04 -07005381 // Before we continue, If KHX_device_group is the list of enabled and viable extensions, then we then need to look for the
Lenny Komowa1524852017-10-02 15:08:53 -06005382 // corresponding VkDeviceGroupDeviceCreateInfo struct in the device list and replace all the physical device values (which
Mark Young0f183a82017-02-28 09:58:04 -07005383 // are really loader physical device terminator values) with the ICD versions.
Lenny Komowa1524852017-10-02 15:08:53 -06005384 //if (icd_term->this_instance->enabled_known_extensions.khr_device_group_creation == 1) {
5385 {
Mark Young0f183a82017-02-28 09:58:04 -07005386 struct VkStructureHeader *pNext = (struct VkStructureHeader *)localCreateInfo.pNext;
5387 struct VkStructureHeader *pPrev = (struct VkStructureHeader *)&localCreateInfo;
5388 while (NULL != pNext) {
Lenny Komowa1524852017-10-02 15:08:53 -06005389 if (VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO == pNext->sType) {
5390 VkDeviceGroupDeviceCreateInfo *cur_struct = (VkDeviceGroupDeviceCreateInfo *)pNext;
Mark Young0f183a82017-02-28 09:58:04 -07005391 if (0 < cur_struct->physicalDeviceCount && NULL != cur_struct->pPhysicalDevices) {
Lenny Komowa1524852017-10-02 15:08:53 -06005392 VkDeviceGroupDeviceCreateInfo *temp_struct = loader_stack_alloc(sizeof(VkDeviceGroupDeviceCreateInfo));
Mark Young0f183a82017-02-28 09:58:04 -07005393 VkPhysicalDevice *phys_dev_array = NULL;
5394 if (NULL == temp_struct) {
5395 return VK_ERROR_OUT_OF_HOST_MEMORY;
5396 }
Lenny Komowa1524852017-10-02 15:08:53 -06005397 memcpy(temp_struct, cur_struct, sizeof(VkDeviceGroupDeviceCreateInfo));
Mark Young0f183a82017-02-28 09:58:04 -07005398 phys_dev_array = loader_stack_alloc(sizeof(VkPhysicalDevice) * cur_struct->physicalDeviceCount);
5399 if (NULL == phys_dev_array) {
5400 return VK_ERROR_OUT_OF_HOST_MEMORY;
5401 }
5402
5403 // Before calling down, replace the incoming physical device values (which are really loader terminator
5404 // physical devices) with the ICDs physical device values.
5405 struct loader_physical_device_term *cur_term;
5406 for (uint32_t phys_dev = 0; phys_dev < cur_struct->physicalDeviceCount; phys_dev++) {
5407 cur_term = (struct loader_physical_device_term *)cur_struct->pPhysicalDevices[phys_dev];
5408 phys_dev_array[phys_dev] = cur_term->phys_dev;
5409 }
5410 temp_struct->pPhysicalDevices = phys_dev_array;
5411
Joey Bzdekc2536de2017-10-23 17:13:33 -06005412 // Keep track of pointers to restore pNext chain before returning
5413 caller_dgci_container = pPrev;
5414 caller_dgci = cur_struct;
5415
Mark Young0f183a82017-02-28 09:58:04 -07005416 // Replace the old struct in the pNext chain with this one.
5417 pPrev->pNext = (const void *)temp_struct;
5418 pNext = (struct VkStructureHeader *)(temp_struct);
5419 }
5420 break;
5421 }
5422
5423 pPrev = pNext;
5424 pNext = (struct VkStructureHeader *)(pPrev->pNext);
5425 }
5426 }
5427
Lenny Komow34d78d22017-05-24 15:47:15 -06005428 // Handle loader emulation for structs that are not supported by the ICD:
5429 // Presently, the emulation leaves the pNext chain alone. This means that the ICD will receive items in the chain which
5430 // are not recognized by the ICD. If this causes the ICD to fail, then the items would have to be removed here. The current
5431 // implementation does not remove them because copying the pNext chain would be impossible if the loader does not recognize
5432 // the any of the struct types, as the loader would not know the size to allocate and copy.
Lenny Komowa1524852017-10-02 15:08:53 -06005433 //if (icd_term->dispatch.GetPhysicalDeviceFeatures2 == NULL && icd_term->dispatch.GetPhysicalDeviceFeatures2KHR == NULL) {
5434 {
Lenny Komow34d78d22017-05-24 15:47:15 -06005435 const void *pNext = localCreateInfo.pNext;
5436 while (pNext != NULL) {
5437 switch (*(VkStructureType *)pNext) {
Lenny Komowa1524852017-10-02 15:08:53 -06005438 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2: {
Lenny Komow34d78d22017-05-24 15:47:15 -06005439 const VkPhysicalDeviceFeatures2KHR *features = pNext;
5440
Lenny Komowa1524852017-10-02 15:08:53 -06005441 if (icd_term->dispatch.GetPhysicalDeviceFeatures2 == NULL && icd_term->dispatch.GetPhysicalDeviceFeatures2KHR == NULL) {
5442 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
5443 "vkCreateDevice: Emulating handling of VkPhysicalDeviceFeatures2 in pNext chain for ICD \"%s\"",
5444 icd_term->scanned_icd->lib_name);
5445
5446 // Verify that VK_KHR_get_physical_device_properties2 is enabled
5447 if (icd_term->this_instance->enabled_known_extensions.khr_get_physical_device_properties2) {
5448 localCreateInfo.pEnabledFeatures = &features->features;
5449 }
Lenny Komow34d78d22017-05-24 15:47:15 -06005450 }
5451
5452 // Leave this item in the pNext chain for now
5453
5454 pNext = features->pNext;
5455 break;
5456 }
5457
Lenny Komowa1524852017-10-02 15:08:53 -06005458 case VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO: {
Lenny Komow82e15e02017-10-02 15:08:53 -06005459 const VkDeviceGroupDeviceCreateInfoKHR *group_info = pNext;
Lenny Komow34d78d22017-05-24 15:47:15 -06005460
Lenny Komowa1524852017-10-02 15:08:53 -06005461 if (icd_term->dispatch.EnumeratePhysicalDeviceGroups == NULL && icd_term->dispatch.EnumeratePhysicalDeviceGroupsKHR == NULL) {
5462 loader_log(
5463 icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
5464 "vkCreateDevice: Emulating handling of VkPhysicalDeviceGroupProperties in pNext chain for ICD \"%s\"",
5465 icd_term->scanned_icd->lib_name);
5466
5467 // The group must contain only this one device, since physical device groups aren't actually supported
5468 if (group_info->physicalDeviceCount != 1) {
5469 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Lenny Komow34d78d22017-05-24 15:47:15 -06005470 "vkCreateDevice: Emulation failed to create device from device group info");
Lenny Komowa1524852017-10-02 15:08:53 -06005471 res = VK_ERROR_INITIALIZATION_FAILED;
5472 goto out;
5473 }
Lenny Komow34d78d22017-05-24 15:47:15 -06005474 }
5475
5476 // Nothing needs to be done here because we're leaving the item in the pNext chain and because the spec states
5477 // that the physicalDevice argument must be included in the device group, and we've already checked that it is
5478
5479 pNext = group_info->pNext;
5480 break;
5481 }
5482
5483 // Multiview properties are also allowed, but since VK_KHX_multiview is a device extension, we'll just let the ICD
5484 // handle that error when the user enables the extension here
5485 default: {
5486 const struct VkStructureHeader *header = pNext;
5487 pNext = header->pNext;
5488 break;
5489 }
5490 }
5491 }
5492 }
5493
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005494 res = fpCreateDevice(phys_dev_term->phys_dev, &localCreateInfo, pAllocator, &dev->icd_device);
Jon Ashburn1530c342016-02-26 13:14:27 -07005495 if (res != VK_SUCCESS) {
Mark Young0153e0b2016-11-03 14:27:13 -06005496 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07005497 "terminator_CreateDevice: Failed in ICD %s vkCreateDevice"
5498 "call",
Mark Young0153e0b2016-11-03 14:27:13 -06005499 icd_term->scanned_icd->lib_name);
Mark Young0ad83132016-06-30 13:02:42 -06005500 goto out;
Jon Ashburn1530c342016-02-26 13:14:27 -07005501 }
5502
Mark Young65cb3662016-11-07 13:27:02 -07005503 *pDevice = dev->icd_device;
Mark Young0153e0b2016-11-03 14:27:13 -06005504 loader_add_logical_device(icd_term->this_instance, icd_term, dev);
Jon Ashburn1530c342016-02-26 13:14:27 -07005505
Mark Young0f183a82017-02-28 09:58:04 -07005506 // Init dispatch pointer in new device object
Jon Ashburn1530c342016-02-26 13:14:27 -07005507 loader_init_dispatch(*pDevice, &dev->loader_dispatch);
5508
Mark Young0ad83132016-06-30 13:02:42 -06005509out:
5510 if (NULL != icd_exts.list) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005511 loader_destroy_generic_list(icd_term->this_instance, (struct loader_generic_list *)&icd_exts);
Mark Young0ad83132016-06-30 13:02:42 -06005512 }
5513
Joey Bzdekc2536de2017-10-23 17:13:33 -06005514 // Restore pNext pointer to old VkDeviceGroupDeviceCreateInfoKHX
5515 // in the chain to maintain consistency for the caller.
5516 if (caller_dgci_container != NULL) {
5517 caller_dgci_container->pNext = caller_dgci;
5518 }
5519
Jon Ashburn1530c342016-02-26 13:14:27 -07005520 return res;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06005521}
5522
Mark Young6267ae62017-01-12 12:27:19 -07005523VkResult setupLoaderTrampPhysDevs(VkInstance instance) {
Jon Ashburn24cd4be2015-11-01 14:04:06 -07005524 VkResult res = VK_SUCCESS;
Mark Young6267ae62017-01-12 12:27:19 -07005525 VkPhysicalDevice *local_phys_devs = NULL;
5526 struct loader_instance *inst;
5527 uint32_t total_count = 0;
5528 struct loader_physical_device_tramp **new_phys_devs = NULL;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07005529
Mark Young6267ae62017-01-12 12:27:19 -07005530 inst = loader_get_instance(instance);
5531 if (NULL == inst) {
5532 res = VK_ERROR_INITIALIZATION_FAILED;
5533 goto out;
5534 }
Mark Youngd66edd52017-03-10 17:31:18 -07005535
Mark Youngbb3a29c2017-05-19 12:29:43 -06005536 // Query how many GPUs there
Mark Youngd66edd52017-03-10 17:31:18 -07005537 res = inst->disp->layer_inst_disp.EnumeratePhysicalDevices(instance, &total_count, NULL);
5538 if (res != VK_SUCCESS) {
5539 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5540 "setupLoaderTrampPhysDevs: Failed during dispatch call "
5541 "of \'vkEnumeratePhysicalDevices\' to lower layers or "
5542 "loader to get count.");
5543 goto out;
5544 }
5545
5546 // Really use what the total GPU count is since Optimus and other layers may mess
5547 // the count up.
Mark Young6267ae62017-01-12 12:27:19 -07005548 total_count = inst->total_gpu_count;
5549
5550 // Create an array for the new physical devices, which will be stored
5551 // in the instance for the trampoline code.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005552 new_phys_devs = (struct loader_physical_device_tramp **)loader_instance_heap_alloc(
5553 inst, total_count * sizeof(struct loader_physical_device_tramp *), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young6267ae62017-01-12 12:27:19 -07005554 if (NULL == new_phys_devs) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005555 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5556 "setupLoaderTrampPhysDevs: Failed to allocate new physical device"
5557 " array of size %d",
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005558 total_count);
Mark Youngd8382d72016-12-23 16:59:58 -07005559 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5560 goto out;
5561 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005562 memset(new_phys_devs, 0, total_count * sizeof(struct loader_physical_device_tramp *));
Jon Ashburn014438f2016-03-01 19:51:07 -07005563
Mark Young6267ae62017-01-12 12:27:19 -07005564 // Create a temporary array (on the stack) to keep track of the
5565 // returned VkPhysicalDevice values.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005566 local_phys_devs = loader_stack_alloc(sizeof(VkPhysicalDevice) * total_count);
Mark Young6267ae62017-01-12 12:27:19 -07005567 if (NULL == local_phys_devs) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005568 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5569 "setupLoaderTrampPhysDevs: Failed to allocate local "
5570 "physical device array of size %d",
Mark Young6267ae62017-01-12 12:27:19 -07005571 total_count);
5572 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5573 goto out;
5574 }
5575 memset(local_phys_devs, 0, sizeof(VkPhysicalDevice) * total_count);
5576
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005577 res = inst->disp->layer_inst_disp.EnumeratePhysicalDevices(instance, &total_count, local_phys_devs);
Mark Young6267ae62017-01-12 12:27:19 -07005578 if (VK_SUCCESS != res) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005579 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5580 "setupLoaderTrampPhysDevs: Failed during dispatch call "
5581 "of \'vkEnumeratePhysicalDevices\' to lower layers or "
Mark Youngd66edd52017-03-10 17:31:18 -07005582 "loader to get content.");
Mark Young6267ae62017-01-12 12:27:19 -07005583 goto out;
5584 }
5585
5586 // Copy or create everything to fill the new array of physical devices
5587 for (uint32_t new_idx = 0; new_idx < total_count; new_idx++) {
Mark Young6267ae62017-01-12 12:27:19 -07005588 // Check if this physical device is already in the old buffer
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005589 for (uint32_t old_idx = 0; old_idx < inst->phys_dev_count_tramp; old_idx++) {
5590 if (local_phys_devs[new_idx] == inst->phys_devs_tramp[old_idx]->phys_dev) {
Mark Young6267ae62017-01-12 12:27:19 -07005591 new_phys_devs[new_idx] = inst->phys_devs_tramp[old_idx];
5592 break;
5593 }
Mark Youngd8382d72016-12-23 16:59:58 -07005594 }
5595
Mark Young6267ae62017-01-12 12:27:19 -07005596 // If this physical device isn't in the old buffer, create it
5597 if (NULL == new_phys_devs[new_idx]) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005598 new_phys_devs[new_idx] = (struct loader_physical_device_tramp *)loader_instance_heap_alloc(
5599 inst, sizeof(struct loader_physical_device_tramp), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young6267ae62017-01-12 12:27:19 -07005600 if (NULL == new_phys_devs[new_idx]) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005601 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5602 "setupLoaderTrampPhysDevs: Failed to allocate "
5603 "physical device trampoline object %d",
Mark Young6267ae62017-01-12 12:27:19 -07005604 new_idx);
5605 total_count = new_idx;
Mark Youngd8382d72016-12-23 16:59:58 -07005606 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5607 goto out;
5608 }
5609
Mark Young6267ae62017-01-12 12:27:19 -07005610 // Initialize the new physicalDevice object
5611 loader_set_dispatch((void *)new_phys_devs[new_idx], inst->disp);
5612 new_phys_devs[new_idx]->this_instance = inst;
5613 new_phys_devs[new_idx]->phys_dev = local_phys_devs[new_idx];
Mark Young559d7502016-09-26 11:38:46 -06005614 }
Lenny Komowa5e01122016-12-22 15:29:43 -07005615 }
Mark Young559d7502016-09-26 11:38:46 -06005616
Lenny Komowa5e01122016-12-22 15:29:43 -07005617out:
Mark Youngd8382d72016-12-23 16:59:58 -07005618
Mark Young6267ae62017-01-12 12:27:19 -07005619 if (VK_SUCCESS != res) {
5620 if (NULL != new_phys_devs) {
5621 for (uint32_t i = 0; i < total_count; i++) {
5622 loader_instance_heap_free(inst, new_phys_devs[i]);
Lenny Komowa5e01122016-12-22 15:29:43 -07005623 }
5624 loader_instance_heap_free(inst, new_phys_devs);
Mark Young6267ae62017-01-12 12:27:19 -07005625 }
5626 total_count = 0;
5627 } else {
5628 // Free everything that didn't carry over to the new array of
5629 // physical devices
5630 if (NULL != inst->phys_devs_tramp) {
5631 for (uint32_t i = 0; i < inst->phys_dev_count_tramp; i++) {
5632 bool found = false;
5633 for (uint32_t j = 0; j < total_count; j++) {
5634 if (inst->phys_devs_tramp[i] == new_phys_devs[j]) {
5635 found = true;
5636 break;
5637 }
5638 }
5639 if (!found) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005640 loader_instance_heap_free(inst, inst->phys_devs_tramp[i]);
Mark Young6267ae62017-01-12 12:27:19 -07005641 }
5642 }
5643 loader_instance_heap_free(inst, inst->phys_devs_tramp);
5644 }
Mark Youngd8382d72016-12-23 16:59:58 -07005645
Mark Young6267ae62017-01-12 12:27:19 -07005646 // Swap in the new physical device list
5647 inst->phys_dev_count_tramp = total_count;
5648 inst->phys_devs_tramp = new_phys_devs;
5649 }
5650
5651 return res;
5652}
5653
5654VkResult setupLoaderTermPhysDevs(struct loader_instance *inst) {
5655 VkResult res = VK_SUCCESS;
5656 struct loader_icd_term *icd_term;
5657 struct loader_phys_dev_per_icd *icd_phys_dev_array = NULL;
5658 struct loader_physical_device_term **new_phys_devs = NULL;
Mark Young6267ae62017-01-12 12:27:19 -07005659
5660 inst->total_gpu_count = 0;
5661
5662 // Allocate something to store the physical device characteristics
5663 // that we read from each ICD.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005664 icd_phys_dev_array =
5665 (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 -07005666 if (NULL == icd_phys_dev_array) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005667 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5668 "setupLoaderTermPhysDevs: Failed to allocate temporary "
5669 "ICD Physical device info array of size %d",
Mark Young6267ae62017-01-12 12:27:19 -07005670 inst->total_gpu_count);
5671 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5672 goto out;
5673 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005674 memset(icd_phys_dev_array, 0, sizeof(struct loader_phys_dev_per_icd) * inst->total_icd_count);
Mark Young6267ae62017-01-12 12:27:19 -07005675 icd_term = inst->icd_terms;
5676
5677 // For each ICD, query the number of physical devices, and then get an
5678 // internal value for those physical devices.
Karl Schultz47dd59d2017-01-20 13:19:20 -07005679 for (uint32_t icd_idx = 0; NULL != icd_term; icd_term = icd_term->next, icd_idx++) {
Mark Young0f183a82017-02-28 09:58:04 -07005680 res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &icd_phys_dev_array[icd_idx].count, NULL);
Mark Young6267ae62017-01-12 12:27:19 -07005681 if (VK_SUCCESS != res) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005682 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5683 "setupLoaderTermPhysDevs: Call to "
5684 "ICD %d's \'vkEnumeratePhysicalDevices\' failed with"
5685 " error 0x%08x",
Karl Schultz47dd59d2017-01-20 13:19:20 -07005686 icd_idx, res);
Mark Young6267ae62017-01-12 12:27:19 -07005687 goto out;
5688 }
5689
Karl Schultz47dd59d2017-01-20 13:19:20 -07005690 icd_phys_dev_array[icd_idx].phys_devs =
5691 (VkPhysicalDevice *)loader_stack_alloc(icd_phys_dev_array[icd_idx].count * sizeof(VkPhysicalDevice));
5692 if (NULL == icd_phys_dev_array[icd_idx].phys_devs) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005693 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5694 "setupLoaderTermPhysDevs: Failed to allocate temporary "
5695 "ICD Physical device array for ICD %d of size %d",
Karl Schultz47dd59d2017-01-20 13:19:20 -07005696 icd_idx, inst->total_gpu_count);
Mark Young6267ae62017-01-12 12:27:19 -07005697 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5698 goto out;
5699 }
5700
Mark Young0f183a82017-02-28 09:58:04 -07005701 res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &(icd_phys_dev_array[icd_idx].count),
5702 icd_phys_dev_array[icd_idx].phys_devs);
Mark Young6267ae62017-01-12 12:27:19 -07005703 if (VK_SUCCESS != res) {
5704 goto out;
5705 }
Karl Schultz47dd59d2017-01-20 13:19:20 -07005706 inst->total_gpu_count += icd_phys_dev_array[icd_idx].count;
5707 icd_phys_dev_array[icd_idx].this_icd_term = icd_term;
Mark Young6267ae62017-01-12 12:27:19 -07005708 }
5709
5710 if (0 == inst->total_gpu_count) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005711 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5712 "setupLoaderTermPhysDevs: Failed to detect any valid"
5713 " GPUs in the current config");
Mark Young6267ae62017-01-12 12:27:19 -07005714 res = VK_ERROR_INITIALIZATION_FAILED;
5715 goto out;
5716 }
5717
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005718 new_phys_devs = loader_instance_heap_alloc(inst, sizeof(struct loader_physical_device_term *) * inst->total_gpu_count,
5719 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young6267ae62017-01-12 12:27:19 -07005720 if (NULL == new_phys_devs) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005721 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5722 "setupLoaderTermPhysDevs: Failed to allocate new physical"
5723 " device array of size %d",
Mark Young6267ae62017-01-12 12:27:19 -07005724 inst->total_gpu_count);
5725 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5726 goto out;
5727 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005728 memset(new_phys_devs, 0, sizeof(struct loader_physical_device_term *) * inst->total_gpu_count);
Mark Young6267ae62017-01-12 12:27:19 -07005729
5730 // Copy or create everything to fill the new array of physical devices
5731 uint32_t idx = 0;
5732 for (uint32_t icd_idx = 0; icd_idx < inst->total_icd_count; icd_idx++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005733 for (uint32_t pd_idx = 0; pd_idx < icd_phys_dev_array[icd_idx].count; pd_idx++) {
Mark Young6267ae62017-01-12 12:27:19 -07005734 // Check if this physical device is already in the old buffer
5735 if (NULL != inst->phys_devs_term) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005736 for (uint32_t old_idx = 0; old_idx < inst->phys_dev_count_term; old_idx++) {
5737 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 -07005738 new_phys_devs[idx] = inst->phys_devs_term[old_idx];
5739 break;
5740 }
5741 }
5742 }
5743 // If this physical device isn't in the old buffer, then we
5744 // need to create it.
5745 if (NULL == new_phys_devs[idx]) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005746 new_phys_devs[idx] = loader_instance_heap_alloc(inst, sizeof(struct loader_physical_device_term),
5747 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young6267ae62017-01-12 12:27:19 -07005748 if (NULL == new_phys_devs[idx]) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005749 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5750 "setupLoaderTermPhysDevs: Failed to allocate "
5751 "physical device terminator object %d",
Mark Young6267ae62017-01-12 12:27:19 -07005752 idx);
5753 inst->total_gpu_count = idx;
5754 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5755 goto out;
5756 }
5757
5758 loader_set_dispatch((void *)new_phys_devs[idx], inst->disp);
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005759 new_phys_devs[idx]->this_icd_term = icd_phys_dev_array[icd_idx].this_icd_term;
Mark Young6267ae62017-01-12 12:27:19 -07005760 new_phys_devs[idx]->icd_index = (uint8_t)(icd_idx);
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005761 new_phys_devs[idx]->phys_dev = icd_phys_dev_array[icd_idx].phys_devs[pd_idx];
Mark Young6267ae62017-01-12 12:27:19 -07005762 }
5763 idx++;
5764 }
5765 }
5766
5767out:
5768
5769 if (VK_SUCCESS != res) {
Mark Young156e8552017-02-03 16:27:42 -07005770 if (NULL != new_phys_devs) {
5771 // We've encountered an error, so we should free the new buffers.
Mark Young6267ae62017-01-12 12:27:19 -07005772 for (uint32_t i = 0; i < inst->total_gpu_count; i++) {
5773 loader_instance_heap_free(inst, new_phys_devs[i]);
5774 }
Mark Young156e8552017-02-03 16:27:42 -07005775 loader_instance_heap_free(inst, new_phys_devs);
Mark Young6267ae62017-01-12 12:27:19 -07005776 }
Mark Young156e8552017-02-03 16:27:42 -07005777 inst->total_gpu_count = 0;
Mark Young6267ae62017-01-12 12:27:19 -07005778 } else {
5779 // Free everything that didn't carry over to the new array of
5780 // physical devices. Everything else will have been copied over
5781 // to the new array.
5782 if (NULL != inst->phys_devs_term) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005783 for (uint32_t cur_pd = 0; cur_pd < inst->phys_dev_count_term; cur_pd++) {
Mark Young6267ae62017-01-12 12:27:19 -07005784 bool found = false;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005785 for (uint32_t new_pd_idx = 0; new_pd_idx < inst->total_gpu_count; new_pd_idx++) {
5786 if (inst->phys_devs_term[cur_pd] == new_phys_devs[new_pd_idx]) {
Mark Young6267ae62017-01-12 12:27:19 -07005787 found = true;
5788 break;
5789 }
5790 }
5791 if (!found) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005792 loader_instance_heap_free(inst, inst->phys_devs_term[cur_pd]);
Mark Young6267ae62017-01-12 12:27:19 -07005793 }
5794 }
5795 loader_instance_heap_free(inst, inst->phys_devs_term);
5796 }
5797
5798 // Swap out old and new devices list
5799 inst->phys_dev_count_term = inst->total_gpu_count;
5800 inst->phys_devs_term = new_phys_devs;
5801 }
5802
5803 return res;
5804}
5805
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005806VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount,
5807 VkPhysicalDevice *pPhysicalDevices) {
Mark Young6267ae62017-01-12 12:27:19 -07005808 struct loader_instance *inst = (struct loader_instance *)instance;
5809 VkResult res = VK_SUCCESS;
5810
Mark Youngd66edd52017-03-10 17:31:18 -07005811 // Always call the setup loader terminator physical devices because they may
5812 // have changed at any point.
5813 res = setupLoaderTermPhysDevs(inst);
5814 if (VK_SUCCESS != res) {
5815 goto out;
Mark Young6267ae62017-01-12 12:27:19 -07005816 }
5817
5818 uint32_t copy_count = inst->total_gpu_count;
5819 if (NULL != pPhysicalDevices) {
5820 if (copy_count > *pPhysicalDeviceCount) {
5821 copy_count = *pPhysicalDeviceCount;
5822 res = VK_INCOMPLETE;
5823 }
5824
5825 for (uint32_t i = 0; i < copy_count; i++) {
5826 pPhysicalDevices[i] = (VkPhysicalDevice)inst->phys_devs_term[i];
Jon Ashburn014438f2016-03-01 19:51:07 -07005827 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06005828 }
Mark Young559d7502016-09-26 11:38:46 -06005829
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07005830 *pPhysicalDeviceCount = copy_count;
5831
Mark Young6267ae62017-01-12 12:27:19 -07005832out:
5833
Jon Ashburn24cd4be2015-11-01 14:04:06 -07005834 return res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07005835}
5836
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005837VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
5838 VkPhysicalDeviceProperties *pProperties) {
5839 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Mark Young0153e0b2016-11-03 14:27:13 -06005840 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Young0f183a82017-02-28 09:58:04 -07005841 if (NULL != icd_term->dispatch.GetPhysicalDeviceProperties) {
5842 icd_term->dispatch.GetPhysicalDeviceProperties(phys_dev_term->phys_dev, pProperties);
Mark Youngb6399312017-01-10 14:22:15 -07005843 }
Tony Barbour59a47322015-06-24 16:06:58 -06005844}
5845
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005846VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice,
5847 uint32_t *pQueueFamilyPropertyCount,
5848 VkQueueFamilyProperties *pProperties) {
5849 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Mark Young0153e0b2016-11-03 14:27:13 -06005850 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Young0f183a82017-02-28 09:58:04 -07005851 if (NULL != icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties) {
5852 icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties(phys_dev_term->phys_dev, pQueueFamilyPropertyCount, pProperties);
Mark Youngb6399312017-01-10 14:22:15 -07005853 }
Tony Barbour59a47322015-06-24 16:06:58 -06005854}
5855
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005856VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice,
5857 VkPhysicalDeviceMemoryProperties *pProperties) {
5858 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Mark Young0153e0b2016-11-03 14:27:13 -06005859 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Young0f183a82017-02-28 09:58:04 -07005860 if (NULL != icd_term->dispatch.GetPhysicalDeviceMemoryProperties) {
5861 icd_term->dispatch.GetPhysicalDeviceMemoryProperties(phys_dev_term->phys_dev, pProperties);
Mark Youngb6399312017-01-10 14:22:15 -07005862 }
Jon Ashburn3da71f22015-05-14 12:43:38 -06005863}
5864
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005865VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice,
5866 VkPhysicalDeviceFeatures *pFeatures) {
5867 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Mark Young0153e0b2016-11-03 14:27:13 -06005868 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Young0f183a82017-02-28 09:58:04 -07005869 if (NULL != icd_term->dispatch.GetPhysicalDeviceFeatures) {
5870 icd_term->dispatch.GetPhysicalDeviceFeatures(phys_dev_term->phys_dev, pFeatures);
Mark Youngb6399312017-01-10 14:22:15 -07005871 }
Chris Forbesbc0bb772015-06-21 22:55:02 +12005872}
5873
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005874VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format,
5875 VkFormatProperties *pFormatInfo) {
5876 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Mark Young0153e0b2016-11-03 14:27:13 -06005877 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Young0f183a82017-02-28 09:58:04 -07005878 if (NULL != icd_term->dispatch.GetPhysicalDeviceFormatProperties) {
5879 icd_term->dispatch.GetPhysicalDeviceFormatProperties(phys_dev_term->phys_dev, format, pFormatInfo);
Mark Youngb6399312017-01-10 14:22:15 -07005880 }
Chris Forbesbc0bb772015-06-21 22:55:02 +12005881}
5882
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005883VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format,
5884 VkImageType type, VkImageTiling tiling,
5885 VkImageUsageFlags usage, VkImageCreateFlags flags,
5886 VkImageFormatProperties *pImageFormatProperties) {
5887 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Mark Young0153e0b2016-11-03 14:27:13 -06005888 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Young0f183a82017-02-28 09:58:04 -07005889 if (NULL == icd_term->dispatch.GetPhysicalDeviceImageFormatProperties) {
Mark Youngb6399312017-01-10 14:22:15 -07005890 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5891 "Encountered the vkEnumerateDeviceLayerProperties "
5892 "terminator. This means a layer improperly continued.");
Chia-I Wu17241042015-10-31 00:31:16 +08005893 return VK_ERROR_INITIALIZATION_FAILED;
Mark Youngb6399312017-01-10 14:22:15 -07005894 }
Mark Young0f183a82017-02-28 09:58:04 -07005895 return icd_term->dispatch.GetPhysicalDeviceImageFormatProperties(phys_dev_term->phys_dev, format, type, tiling, usage, flags,
5896 pImageFormatProperties);
Jon Ashburn754864f2015-07-23 18:49:07 -06005897}
5898
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005899VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format,
5900 VkImageType type, VkSampleCountFlagBits samples,
5901 VkImageUsageFlags usage, VkImageTiling tiling,
5902 uint32_t *pNumProperties,
5903 VkSparseImageFormatProperties *pProperties) {
5904 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Mark Young0153e0b2016-11-03 14:27:13 -06005905 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Young0f183a82017-02-28 09:58:04 -07005906 if (NULL != icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties) {
5907 icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties(phys_dev_term->phys_dev, format, type, samples, usage,
5908 tiling, pNumProperties, pProperties);
Mark Youngb6399312017-01-10 14:22:15 -07005909 }
Mark Lobodzinski16e8bef2015-07-03 15:58:09 -06005910}
5911
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005912VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
5913 const char *pLayerName, uint32_t *pPropertyCount,
5914 VkExtensionProperties *pProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06005915 struct loader_physical_device_term *phys_dev_term;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07005916
Mark Young3a587792016-08-19 15:25:08 -06005917 struct loader_layer_list implicit_layer_list = {0};
5918 struct loader_extension_list all_exts = {0};
5919 struct loader_extension_list icd_exts = {0};
Jon Ashburn471f44c2016-01-13 12:51:43 -07005920
Jon Ashburndc5d9202016-02-29 13:00:51 -07005921 assert(pLayerName == NULL || strlen(pLayerName) == 0);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06005922
Mark Young0f183a82017-02-28 09:58:04 -07005923 // Any layer or trampoline wrapping should be removed at this point in time can just cast to the expected
5924 // type for VkPhysicalDevice.
Mark Young0153e0b2016-11-03 14:27:13 -06005925 phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Jon Ashburn471f44c2016-01-13 12:51:43 -07005926
Mark Young0f183a82017-02-28 09:58:04 -07005927 // This case is during the call down the instance chain with pLayerName == NULL
Mark Young0153e0b2016-11-03 14:27:13 -06005928 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Jon Ashburndc5d9202016-02-29 13:00:51 -07005929 uint32_t icd_ext_count = *pPropertyCount;
5930 VkResult res;
Jon Ashburn471f44c2016-01-13 12:51:43 -07005931
Mark Young0f183a82017-02-28 09:58:04 -07005932 // Get the available device extensions
5933 res = icd_term->dispatch.EnumerateDeviceExtensionProperties(phys_dev_term->phys_dev, NULL, &icd_ext_count, pProperties);
Mark Young3a587792016-08-19 15:25:08 -06005934 if (res != VK_SUCCESS) {
5935 goto out;
5936 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07005937
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005938 if (!loader_init_layer_list(icd_term->this_instance, &implicit_layer_list)) {
Mark Young3a587792016-08-19 15:25:08 -06005939 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5940 goto out;
5941 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07005942
Mark Young283fe1c2017-05-04 12:16:35 -06005943 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 -07005944 // We need to determine which implicit layers are active, and then add their extensions. This can't be cached as
5945 // it depends on results of environment variables (which can change).
Jon Ashburndc5d9202016-02-29 13:00:51 -07005946 if (pProperties != NULL) {
Mark Young0f183a82017-02-28 09:58:04 -07005947 // Initialize dev_extension list within the physicalDevice object
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005948 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 -06005949 if (res != VK_SUCCESS) {
5950 goto out;
5951 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07005952
Mark Young0f183a82017-02-28 09:58:04 -07005953 // We need to determine which implicit layers are active, and then add their extensions. This can't be cached as
5954 // it depends on results of environment variables (which can change).
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005955 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 -06005956 if (res != VK_SUCCESS) {
5957 goto out;
5958 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07005959
Mark Young283fe1c2017-05-04 12:16:35 -06005960 loader_add_implicit_layers(icd_term->this_instance, &implicit_layer_list, NULL,
5961 &icd_term->this_instance->instance_layer_list);
Jon Ashburn471f44c2016-01-13 12:51:43 -07005962
Jon Ashburndc5d9202016-02-29 13:00:51 -07005963 for (uint32_t i = 0; i < implicit_layer_list.count; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005964 for (uint32_t j = 0; j < implicit_layer_list.list[i].device_extension_list.count; j++) {
5965 res = loader_add_to_ext_list(icd_term->this_instance, &all_exts, 1,
5966 &implicit_layer_list.list[i].device_extension_list.list[j].props);
Mark Young3a587792016-08-19 15:25:08 -06005967 if (res != VK_SUCCESS) {
5968 goto out;
5969 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07005970 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07005971 }
Jon Ashburndc5d9202016-02-29 13:00:51 -07005972 uint32_t capacity = *pPropertyCount;
5973 VkExtensionProperties *props = pProperties;
Jon Ashburn471f44c2016-01-13 12:51:43 -07005974
Jon Ashburndc5d9202016-02-29 13:00:51 -07005975 for (uint32_t i = 0; i < all_exts.count && i < capacity; i++) {
5976 props[i] = all_exts.list[i];
5977 }
Mark Young0f183a82017-02-28 09:58:04 -07005978
5979 // Wasn't enough space for the extensions, we did partial copy now return VK_INCOMPLETE
Jon Ashburndc5d9202016-02-29 13:00:51 -07005980 if (capacity < all_exts.count) {
5981 res = VK_INCOMPLETE;
5982 } else {
5983 *pPropertyCount = all_exts.count;
5984 }
Jon Ashburndc5d9202016-02-29 13:00:51 -07005985 } else {
Mark Young0f183a82017-02-28 09:58:04 -07005986 // Just return the count; need to add in the count of implicit layer extensions
5987 // don't worry about duplicates being added in the count
Jon Ashburndc5d9202016-02-29 13:00:51 -07005988 *pPropertyCount = icd_ext_count;
5989
5990 for (uint32_t i = 0; i < implicit_layer_list.count; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005991 *pPropertyCount += implicit_layer_list.list[i].device_extension_list.count;
Jon Ashburndc5d9202016-02-29 13:00:51 -07005992 }
5993 res = VK_SUCCESS;
Jon Ashburnb82c1852015-08-11 14:49:54 -06005994 }
Jon Ashburndc5d9202016-02-29 13:00:51 -07005995
Mark Young3a587792016-08-19 15:25:08 -06005996out:
5997
5998 if (NULL != implicit_layer_list.list) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005999 loader_destroy_generic_list(icd_term->this_instance, (struct loader_generic_list *)&implicit_layer_list);
Mark Young3a587792016-08-19 15:25:08 -06006000 }
6001 if (NULL != all_exts.list) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07006002 loader_destroy_generic_list(icd_term->this_instance, (struct loader_generic_list *)&all_exts);
Mark Young3a587792016-08-19 15:25:08 -06006003 }
6004 if (NULL != icd_exts.list) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07006005 loader_destroy_generic_list(icd_term->this_instance, (struct loader_generic_list *)&icd_exts);
Mark Young3a587792016-08-19 15:25:08 -06006006 }
6007
Jon Ashburndc5d9202016-02-29 13:00:51 -07006008 return res;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06006009}
6010
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07006011VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
6012 VkLayerProperties *pProperties) {
6013 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Mark Youngb6399312017-01-10 14:22:15 -07006014 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07006015 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
6016 "Encountered the vkEnumerateDeviceLayerProperties "
6017 "terminator. This means a layer improperly continued.");
Mark Youngb6399312017-01-10 14:22:15 -07006018 // Should never get here this call isn't dispatched down the chain
Jon Ashburndc5d9202016-02-29 13:00:51 -07006019 return VK_ERROR_INITIALIZATION_FAILED;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06006020}
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07006021
Jon Ashburnf2b4e382016-02-10 20:50:19 -07006022VkStringErrorFlags vk_string_validate(const int max_length, const char *utf8) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07006023 VkStringErrorFlags result = VK_STRING_ERROR_NONE;
Karl Schultz2558bd32016-02-24 14:39:39 -07006024 int num_char_bytes = 0;
Jon Ashburnf2b4e382016-02-10 20:50:19 -07006025 int i, j;
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07006026
Courtney Goeltzenleuchter7a3486d2016-12-21 16:24:34 -07006027 for (i = 0; i <= max_length; i++) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07006028 if (utf8[i] == 0) {
6029 break;
Courtney Goeltzenleuchter7a3486d2016-12-21 16:24:34 -07006030 } else if (i == max_length) {
6031 result |= VK_STRING_ERROR_LENGTH;
6032 break;
Mark Lobodzinski36b4de22016-02-12 11:30:14 -07006033 } else if ((utf8[i] >= 0x20) && (utf8[i] < 0x7f)) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07006034 num_char_bytes = 0;
Jon Ashburnf2b4e382016-02-10 20:50:19 -07006035 } else if ((utf8[i] & UTF8_ONE_BYTE_MASK) == UTF8_ONE_BYTE_CODE) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07006036 num_char_bytes = 1;
Jon Ashburnf2b4e382016-02-10 20:50:19 -07006037 } else if ((utf8[i] & UTF8_TWO_BYTE_MASK) == UTF8_TWO_BYTE_CODE) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07006038 num_char_bytes = 2;
6039 } else if ((utf8[i] & UTF8_THREE_BYTE_MASK) == UTF8_THREE_BYTE_CODE) {
6040 num_char_bytes = 3;
6041 } else {
6042 result = VK_STRING_ERROR_BAD_DATA;
6043 }
6044
6045 // Validate the following num_char_bytes of data
6046 for (j = 0; (j < num_char_bytes) && (i < max_length); j++) {
6047 if (++i == max_length) {
6048 result |= VK_STRING_ERROR_LENGTH;
6049 break;
6050 }
6051 if ((utf8[i] & UTF8_DATA_BYTE_MASK) != UTF8_DATA_BYTE_CODE) {
6052 result |= VK_STRING_ERROR_BAD_DATA;
6053 }
6054 }
6055 }
6056 return result;
6057}
Lenny Komow3cf3ac72017-12-19 16:38:37 -07006058
6059VKAPI_ATTR VkResult VKAPI_CALL
6060terminator_EnumerateInstanceExtensionProperties(const VkEnumerateInstanceExtensionPropertiesChain *chain, const char *pLayerName,
6061 uint32_t *pPropertyCount, VkExtensionProperties *pProperties) {
6062 struct loader_extension_list *global_ext_list = NULL;
6063 struct loader_layer_list instance_layers;
6064 struct loader_extension_list local_ext_list;
6065 struct loader_icd_tramp_list icd_tramp_list;
6066 uint32_t copy_size;
6067 VkResult res = VK_SUCCESS;
6068
6069 // tls_instance = NULL;
6070 memset(&local_ext_list, 0, sizeof(local_ext_list));
6071 memset(&instance_layers, 0, sizeof(instance_layers));
Lenny Komow3cf3ac72017-12-19 16:38:37 -07006072
6073 // Get layer libraries if needed
6074 if (pLayerName && strlen(pLayerName) != 0) {
6075 if (vk_string_validate(MaxLoaderStringLength, pLayerName) != VK_STRING_ERROR_NONE) {
6076 assert(VK_FALSE &&
6077 "vkEnumerateInstanceExtensionProperties: "
6078 "pLayerName is too long or is badly formed");
6079 res = VK_ERROR_EXTENSION_NOT_PRESENT;
6080 goto out;
6081 }
6082
6083 loader_layer_scan(NULL, &instance_layers);
6084 for (uint32_t i = 0; i < instance_layers.count; i++) {
6085 struct loader_layer_properties *props = &instance_layers.list[i];
6086 if (strcmp(props->info.layerName, pLayerName) == 0) {
6087 global_ext_list = &props->instance_extension_list;
6088 break;
6089 }
6090 }
6091 } else {
6092 // Scan/discover all ICD libraries
6093 memset(&icd_tramp_list, 0, sizeof(icd_tramp_list));
6094 res = loader_icd_scan(NULL, &icd_tramp_list);
6095 if (VK_SUCCESS != res) {
6096 goto out;
6097 }
6098 // Get extensions from all ICD's, merge so no duplicates
6099 res = loader_get_icd_loader_instance_extensions(NULL, &icd_tramp_list, &local_ext_list);
6100 if (VK_SUCCESS != res) {
6101 goto out;
6102 }
6103 loader_scanned_icd_clear(NULL, &icd_tramp_list);
6104
6105 // Append enabled implicit layers.
6106 loader_implicit_layer_scan(NULL, &instance_layers);
6107 for (uint32_t i = 0; i < instance_layers.count; i++) {
6108 if (!loader_is_implicit_layer_enabled(NULL, &instance_layers.list[i])) {
6109 continue;
6110 }
6111 struct loader_extension_list *ext_list = &instance_layers.list[i].instance_extension_list;
6112 loader_add_to_ext_list(NULL, &local_ext_list, ext_list->count, ext_list->list);
6113 }
6114
6115 global_ext_list = &local_ext_list;
6116 }
6117
6118 if (global_ext_list == NULL) {
6119 res = VK_ERROR_LAYER_NOT_PRESENT;
6120 goto out;
6121 }
6122
6123 if (pProperties == NULL) {
6124 *pPropertyCount = global_ext_list->count;
6125 goto out;
6126 }
6127
6128 copy_size = *pPropertyCount < global_ext_list->count ? *pPropertyCount : global_ext_list->count;
6129 for (uint32_t i = 0; i < copy_size; i++) {
6130 memcpy(&pProperties[i], &global_ext_list->list[i], sizeof(VkExtensionProperties));
6131 }
6132 *pPropertyCount = copy_size;
6133
6134 if (copy_size < global_ext_list->count) {
6135 res = VK_INCOMPLETE;
6136 goto out;
6137 }
6138
6139out:
6140
6141 loader_destroy_generic_list(NULL, (struct loader_generic_list *)&local_ext_list);
6142 loader_delete_layer_properties(NULL, &instance_layers);
6143 return res;
6144}
6145
6146VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateInstanceLayerProperties(const VkEnumerateInstanceLayerPropertiesChain *chain,
6147 uint32_t *pPropertyCount,
6148 VkLayerProperties *pProperties) {
6149 VkResult result = VK_SUCCESS;
6150 struct loader_layer_list instance_layer_list;
6151 tls_instance = NULL;
6152
Lenny Komow23342982018-01-19 11:22:28 -07006153 LOADER_PLATFORM_THREAD_ONCE(&once_init, loader_initialize);
6154
Lenny Komow3cf3ac72017-12-19 16:38:37 -07006155 uint32_t copy_size;
6156
6157 // Get layer libraries
6158 memset(&instance_layer_list, 0, sizeof(instance_layer_list));
6159 loader_layer_scan(NULL, &instance_layer_list);
6160
6161 if (pProperties == NULL) {
6162 *pPropertyCount = instance_layer_list.count;
6163 goto out;
6164 }
6165
6166 copy_size = (*pPropertyCount < instance_layer_list.count) ? *pPropertyCount : instance_layer_list.count;
6167 for (uint32_t i = 0; i < copy_size; i++) {
6168 memcpy(&pProperties[i], &instance_layer_list.list[i].info, sizeof(VkLayerProperties));
6169 }
6170
6171 *pPropertyCount = copy_size;
6172
6173 if (copy_size < instance_layer_list.count) {
6174 result = VK_INCOMPLETE;
6175 goto out;
6176 }
6177
6178out:
6179
6180 loader_delete_layer_properties(NULL, &instance_layer_list);
6181 return result;
6182}
Lenny Komow158e9d92018-01-15 15:43:36 -07006183
Lenny Komow23342982018-01-19 11:22:28 -07006184#if defined(_WIN32) && defined(LOADER_DYNAMIC_LIB)
Lenny Komow158e9d92018-01-15 15:43:36 -07006185BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved) {
6186 switch (reason) {
6187 case DLL_PROCESS_ATTACH:
6188 loader_initialize();
6189 break;
6190 case DLL_PROCESS_DETACH:
6191 if (NULL == reserved) {
6192 loader_release();
6193 }
6194 break;
6195 default:
6196 // Do nothing
6197 break;
6198 }
6199 return TRUE;
6200}
Lenny Komow23342982018-01-19 11:22:28 -07006201#elif !defined(_WIN32)
Lenny Komow158e9d92018-01-15 15:43:36 -07006202__attribute__((constructor)) void loader_init_library() { loader_initialize(); }
6203
6204__attribute__((destructor)) void loader_free_library() { loader_release(); }
6205#endif
Lenny Komow82e15e02017-10-02 15:08:53 -06006206
6207// ---- Vulkan Core 1.1 terminators
6208
Lenny Komow76f0f732017-10-02 15:58:17 -06006209VkResult setupLoaderTermPhysDevGroups(struct loader_instance *inst) {
6210 VkResult res = VK_SUCCESS;
6211 struct loader_icd_term *icd_term;
6212 uint32_t total_count = 0;
6213 uint32_t cur_icd_group_count = 0;
6214 VkPhysicalDeviceGroupPropertiesKHR **new_phys_dev_groups = NULL;
6215 VkPhysicalDeviceGroupPropertiesKHR *local_phys_dev_groups = NULL;
Lenny Komowa1524852017-10-02 15:08:53 -06006216 PFN_vkEnumeratePhysicalDeviceGroups fpEnumeratePhysicalDeviceGroups = NULL;
Lenny Komow76f0f732017-10-02 15:58:17 -06006217
6218 if (0 == inst->phys_dev_count_term) {
6219 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
6220 "setupLoaderTermPhysDevGroups: Loader failed to setup physical "
Lenny Komowa1524852017-10-02 15:08:53 -06006221 "device terminator info before calling \'EnumeratePhysicalDeviceGroups\'.");
Lenny Komow76f0f732017-10-02 15:58:17 -06006222 assert(false);
6223 res = VK_ERROR_INITIALIZATION_FAILED;
6224 goto out;
6225 }
6226
6227 // For each ICD, query the number of physical device groups, and then get an
6228 // internal value for those physical devices.
6229 icd_term = inst->icd_terms;
6230 for (uint32_t icd_idx = 0; NULL != icd_term; icd_term = icd_term->next, icd_idx++) {
Lenny Komowa1524852017-10-02 15:08:53 -06006231 // Get the function pointer to use to call into the ICD. This could be the core or KHR version
6232 if (inst->enabled_known_extensions.khr_device_group_creation) {
6233 fpEnumeratePhysicalDeviceGroups = icd_term->dispatch.EnumeratePhysicalDeviceGroupsKHR;
6234 } else {
6235 fpEnumeratePhysicalDeviceGroups = icd_term->dispatch.EnumeratePhysicalDeviceGroups;
6236 }
6237
Lenny Komow76f0f732017-10-02 15:58:17 -06006238 cur_icd_group_count = 0;
Lenny Komowa1524852017-10-02 15:08:53 -06006239 if (NULL == fpEnumeratePhysicalDeviceGroups) {
Lenny Komow76f0f732017-10-02 15:58:17 -06006240 // Treat each ICD's GPU as it's own group if the extension isn't supported
6241 res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &cur_icd_group_count, NULL);
6242 if (res != VK_SUCCESS) {
6243 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
6244 "setupLoaderTermPhysDevGroups: Failed during dispatch call of "
6245 "\'EnumeratePhysicalDevices\' to ICD %d to get plain phys dev count.",
6246 icd_idx);
6247 goto out;
6248 }
6249 } else {
6250 // Query the actual group info
Lenny Komowa1524852017-10-02 15:08:53 -06006251 res = fpEnumeratePhysicalDeviceGroups(icd_term->instance, &cur_icd_group_count, NULL);
Lenny Komow76f0f732017-10-02 15:58:17 -06006252 if (res != VK_SUCCESS) {
6253 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
6254 "setupLoaderTermPhysDevGroups: Failed during dispatch call of "
Lenny Komowa1524852017-10-02 15:08:53 -06006255 "\'EnumeratePhysicalDeviceGroups\' to ICD %d to get count.",
Lenny Komow76f0f732017-10-02 15:58:17 -06006256 icd_idx);
6257 goto out;
6258 }
6259 }
6260 total_count += cur_icd_group_count;
6261 }
6262
6263 // Create an array for the new physical device groups, which will be stored
6264 // in the instance for the Terminator code.
Lenny Komowa1524852017-10-02 15:08:53 -06006265 new_phys_dev_groups = (VkPhysicalDeviceGroupProperties **)loader_instance_heap_alloc(
6266 inst, total_count * sizeof(VkPhysicalDeviceGroupProperties *), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Lenny Komow76f0f732017-10-02 15:58:17 -06006267 if (NULL == new_phys_dev_groups) {
6268 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
6269 "setupLoaderTermPhysDevGroups: Failed to allocate new physical device"
6270 " group array of size %d",
6271 total_count);
6272 res = VK_ERROR_OUT_OF_HOST_MEMORY;
6273 goto out;
6274 }
Lenny Komowa1524852017-10-02 15:08:53 -06006275 memset(new_phys_dev_groups, 0, total_count * sizeof(VkPhysicalDeviceGroupProperties *));
Lenny Komow76f0f732017-10-02 15:58:17 -06006276
6277 // Create a temporary array (on the stack) to keep track of the
6278 // returned VkPhysicalDevice values.
Lenny Komowa1524852017-10-02 15:08:53 -06006279 local_phys_dev_groups = loader_stack_alloc(sizeof(VkPhysicalDeviceGroupProperties) * total_count);
Lenny Komow76f0f732017-10-02 15:58:17 -06006280 if (NULL == local_phys_dev_groups) {
6281 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
6282 "setupLoaderTermPhysDevGroups: Failed to allocate local "
6283 "physical device group array of size %d",
6284 total_count);
6285 res = VK_ERROR_OUT_OF_HOST_MEMORY;
6286 goto out;
6287 }
6288 // Initialize the memory to something valid
Lenny Komowa1524852017-10-02 15:08:53 -06006289 memset(local_phys_dev_groups, 0, sizeof(VkPhysicalDeviceGroupProperties) * total_count);
Lenny Komow76f0f732017-10-02 15:58:17 -06006290 for (uint32_t group = 0; group < total_count; group++) {
6291 local_phys_dev_groups[group].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHR;
6292 local_phys_dev_groups[group].pNext = NULL;
6293 local_phys_dev_groups[group].subsetAllocation = false;
6294 }
6295
6296 cur_icd_group_count = 0;
6297 icd_term = inst->icd_terms;
6298 for (uint32_t icd_idx = 0; NULL != icd_term; icd_term = icd_term->next, icd_idx++) {
6299 uint32_t count_this_time = total_count - cur_icd_group_count;
6300
Lenny Komowa1524852017-10-02 15:08:53 -06006301 // Get the function pointer to use to call into the ICD. This could be the core or KHR version
6302 if (inst->enabled_known_extensions.khr_device_group_creation) {
6303 fpEnumeratePhysicalDeviceGroups = icd_term->dispatch.EnumeratePhysicalDeviceGroupsKHR;
6304 } else {
6305 fpEnumeratePhysicalDeviceGroups = icd_term->dispatch.EnumeratePhysicalDeviceGroups;
6306 }
6307
6308 if (NULL == fpEnumeratePhysicalDeviceGroups) {
Lenny Komow76f0f732017-10-02 15:58:17 -06006309 VkPhysicalDevice* phys_dev_array = loader_stack_alloc(sizeof(VkPhysicalDevice) * count_this_time);
6310 if (NULL == phys_dev_array) {
6311 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
6312 "setupLoaderTermPhysDevGroups: Failed to allocate local "
6313 "physical device array of size %d",
6314 count_this_time);
6315 res = VK_ERROR_OUT_OF_HOST_MEMORY;
6316 goto out;
6317 }
6318
6319 res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &count_this_time, phys_dev_array);
6320 if (res != VK_SUCCESS) {
6321 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
6322 "setupLoaderTermPhysDevGroups: Failed during dispatch call of "
6323 "\'EnumeratePhysicalDevices\' to ICD %d to get plain phys dev count.",
6324 icd_idx);
6325 goto out;
6326 }
6327
6328 // Add each GPU as it's own group
6329 for (uint32_t indiv_gpu = 0; indiv_gpu < count_this_time; indiv_gpu++) {
6330 local_phys_dev_groups[indiv_gpu + cur_icd_group_count].physicalDeviceCount = 1;
6331 local_phys_dev_groups[indiv_gpu + cur_icd_group_count].physicalDevices[0] = phys_dev_array[indiv_gpu];
6332 }
6333
6334 } else {
Lenny Komowa1524852017-10-02 15:08:53 -06006335 res = fpEnumeratePhysicalDeviceGroups(icd_term->instance, &count_this_time, &local_phys_dev_groups[cur_icd_group_count]);
Lenny Komow76f0f732017-10-02 15:58:17 -06006336 if (VK_SUCCESS != res) {
6337 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
6338 "setupLoaderTermPhysDevGroups: Failed during dispatch call of "
Lenny Komowa1524852017-10-02 15:08:53 -06006339 "\'EnumeratePhysicalDeviceGroups\' to ICD %d to get content.",
Lenny Komow76f0f732017-10-02 15:58:17 -06006340 icd_idx);
6341 goto out;
6342 }
6343 }
6344
6345 cur_icd_group_count += count_this_time;
6346 }
6347
6348 // Replace all the physical device IDs with the proper loader values
6349 for (uint32_t group = 0; group < total_count; group++) {
6350 for (uint32_t group_gpu = 0; group_gpu < local_phys_dev_groups[group].physicalDeviceCount; group_gpu++) {
6351 bool found = false;
6352 for (uint32_t term_gpu = 0; term_gpu < inst->phys_dev_count_term; term_gpu++) {
6353 if (local_phys_dev_groups[group].physicalDevices[group_gpu] == inst->phys_devs_term[term_gpu]->phys_dev) {
6354 local_phys_dev_groups[group].physicalDevices[group_gpu] = (VkPhysicalDevice)inst->phys_devs_term[term_gpu];
6355 found = true;
6356 break;
6357 }
6358 }
6359 if (!found) {
6360 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
6361 "setupLoaderTermPhysDevGroups: Failed to find GPU %d in group %d"
Lenny Komowa1524852017-10-02 15:08:53 -06006362 " returned by \'EnumeratePhysicalDeviceGroups\' in list returned"
Lenny Komow76f0f732017-10-02 15:58:17 -06006363 " by \'EnumeratePhysicalDevices\'", group_gpu, group);
6364 res = VK_ERROR_INITIALIZATION_FAILED;
6365 goto out;
6366 }
6367 }
6368 }
6369
6370 // Copy or create everything to fill the new array of physical device groups
6371 for (uint32_t new_idx = 0; new_idx < total_count; new_idx++) {
6372 // Check if this physical device group with the same contents is already in the old buffer
6373 for (uint32_t old_idx = 0; old_idx < inst->phys_dev_group_count_term; old_idx++) {
6374 if (local_phys_dev_groups[new_idx].physicalDeviceCount == inst->phys_dev_groups_term[old_idx]->physicalDeviceCount) {
6375 bool found_all_gpus = true;
6376 for (uint32_t old_gpu = 0; old_gpu < inst->phys_dev_groups_term[old_idx]->physicalDeviceCount; old_gpu++) {
6377 bool found_gpu = false;
6378 for (uint32_t new_gpu = 0; new_gpu < local_phys_dev_groups[new_idx].physicalDeviceCount; new_gpu++) {
6379 if (local_phys_dev_groups[new_idx].physicalDevices[new_gpu] == inst->phys_dev_groups_term[old_idx]->physicalDevices[old_gpu]) {
6380 found_gpu = true;
6381 break;
6382 }
6383 }
6384
6385 if (!found_gpu) {
6386 found_all_gpus = false;
6387 break;
6388 }
6389 }
6390 if (!found_all_gpus) {
6391 continue;
6392 } else {
6393 new_phys_dev_groups[new_idx] = inst->phys_dev_groups_term[old_idx];
6394 break;
6395 }
6396 }
6397 }
6398
6399 // If this physical device group isn't in the old buffer, create it
6400 if (NULL == new_phys_dev_groups[new_idx]) {
6401 new_phys_dev_groups[new_idx] = (VkPhysicalDeviceGroupPropertiesKHR *)loader_instance_heap_alloc(
6402 inst, sizeof(VkPhysicalDeviceGroupPropertiesKHR), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
6403 if (NULL == new_phys_dev_groups[new_idx]) {
6404 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
6405 "setupLoaderTermPhysDevGroups: Failed to allocate "
6406 "physical device group Terminator object %d",
6407 new_idx);
6408 total_count = new_idx;
6409 res = VK_ERROR_OUT_OF_HOST_MEMORY;
6410 goto out;
6411 }
6412 memcpy(new_phys_dev_groups[new_idx], &local_phys_dev_groups[new_idx],
6413 sizeof(VkPhysicalDeviceGroupPropertiesKHR));
6414 }
6415 }
6416
6417out:
6418
6419 if (VK_SUCCESS != res) {
6420 if (NULL != new_phys_dev_groups) {
6421 for (uint32_t i = 0; i < total_count; i++) {
6422 loader_instance_heap_free(inst, new_phys_dev_groups[i]);
6423 }
6424 loader_instance_heap_free(inst, new_phys_dev_groups);
6425 }
6426 total_count = 0;
6427 } else {
6428 // Free everything that didn't carry over to the new array of
6429 // physical device groups
6430 if (NULL != inst->phys_dev_groups_term) {
6431 for (uint32_t i = 0; i < inst->phys_dev_group_count_term; i++) {
6432 bool found = false;
6433 for (uint32_t j = 0; j < total_count; j++) {
6434 if (inst->phys_dev_groups_term[i] == new_phys_dev_groups[j]) {
6435 found = true;
6436 break;
6437 }
6438 }
6439 if (!found) {
6440 loader_instance_heap_free(inst, inst->phys_dev_groups_term[i]);
6441 }
6442 }
6443 loader_instance_heap_free(inst, inst->phys_dev_groups_term);
6444 }
6445
6446 // Swap in the new physical device group list
6447 inst->phys_dev_group_count_term = total_count;
6448 inst->phys_dev_groups_term = new_phys_dev_groups;
6449 }
6450
6451 return res;
6452}
6453
Lenny Komow82e15e02017-10-02 15:08:53 -06006454VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDeviceGroups(
6455 VkInstance instance, uint32_t *pPhysicalDeviceGroupCount,
6456 VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties) {
6457 struct loader_instance *inst = (struct loader_instance *)instance;
6458 VkResult res = VK_SUCCESS;
6459
6460 // Always call the setup loader terminator physical device groups because they may
6461 // have changed at any point.
6462 res = setupLoaderTermPhysDevGroups(inst);
6463 if (VK_SUCCESS != res) {
6464 goto out;
6465 }
6466
6467 uint32_t copy_count = inst->phys_dev_group_count_term;
6468 if (NULL != pPhysicalDeviceGroupProperties) {
6469 if (copy_count > *pPhysicalDeviceGroupCount) {
6470 copy_count = *pPhysicalDeviceGroupCount;
6471 res = VK_INCOMPLETE;
6472 }
6473
6474 for (uint32_t i = 0; i < copy_count; i++) {
6475 memcpy(&pPhysicalDeviceGroupProperties[i], inst->phys_dev_groups_term[i],
6476 sizeof(VkPhysicalDeviceGroupPropertiesKHR));
6477 }
6478 }
6479
6480 *pPhysicalDeviceGroupCount = copy_count;
6481
6482out:
6483
6484 return res;
6485}
6486
6487VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice,
6488 VkPhysicalDeviceFeatures2 *pFeatures) {
6489 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
6490 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Lenny Komowa1524852017-10-02 15:08:53 -06006491 const struct loader_instance *inst = icd_term->this_instance;
Lenny Komow82e15e02017-10-02 15:08:53 -06006492
Lenny Komowa1524852017-10-02 15:08:53 -06006493 // Get the function pointer to use to call into the ICD. This could be the core or KHR version
6494 PFN_vkGetPhysicalDeviceFeatures2 fpGetPhysicalDeviceFeatures2 = NULL;
6495 if (inst != NULL && inst->enabled_known_extensions.khr_get_physical_device_properties2) {
6496 fpGetPhysicalDeviceFeatures2 = icd_term->dispatch.GetPhysicalDeviceFeatures2KHR;
6497 } else {
6498 fpGetPhysicalDeviceFeatures2 = icd_term->dispatch.GetPhysicalDeviceFeatures2;
6499 }
6500
Lenny Komow88dc89b2017-11-03 14:37:11 -06006501 if (fpGetPhysicalDeviceFeatures2 != NULL || !inst->enabled_known_extensions.khr_get_physical_device_properties2) {
Lenny Komow82e15e02017-10-02 15:08:53 -06006502 // Pass the call to the driver
Lenny Komowa1524852017-10-02 15:08:53 -06006503 fpGetPhysicalDeviceFeatures2(phys_dev_term->phys_dev, pFeatures);
Lenny Komow82e15e02017-10-02 15:08:53 -06006504 } else {
6505 // Emulate the call
6506 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006507 "vkGetPhysicalDeviceFeatures2: Emulating call in ICD \"%s\" using vkGetPhysicalDeviceFeatures",
Lenny Komow82e15e02017-10-02 15:08:53 -06006508 icd_term->scanned_icd->lib_name);
6509
Lenny Komow802a9652017-10-03 13:59:21 -06006510 // Write to the VkPhysicalDeviceFeatures2 struct
Lenny Komow82e15e02017-10-02 15:08:53 -06006511 icd_term->dispatch.GetPhysicalDeviceFeatures(phys_dev_term->phys_dev, &pFeatures->features);
6512
6513 void *pNext = pFeatures->pNext;
6514 while (pNext != NULL) {
6515 switch (*(VkStructureType *)pNext) {
Lenny Komow802a9652017-10-03 13:59:21 -06006516 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES: {
Lenny Komow82e15e02017-10-02 15:08:53 -06006517 // Skip the check if VK_KHR_multiview is enabled because it's a device extension
6518 // Write to the VkPhysicalDeviceMultiviewFeaturesKHR struct
6519 VkPhysicalDeviceMultiviewFeaturesKHR *multiview_features = pNext;
6520 multiview_features->multiview = VK_FALSE;
6521 multiview_features->multiviewGeometryShader = VK_FALSE;
6522 multiview_features->multiviewTessellationShader = VK_FALSE;
6523
6524 pNext = multiview_features->pNext;
6525 break;
6526 }
6527 default: {
6528 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006529 "vkGetPhysicalDeviceFeatures2: Emulation found unrecognized structure type in pFeatures->pNext - "
Lenny Komow82e15e02017-10-02 15:08:53 -06006530 "this struct will be ignored");
6531
6532 struct VkStructureHeader *header = pNext;
6533 pNext = (void *)header->pNext;
6534 break;
6535 }
6536 }
6537 }
6538 }
6539}
6540
6541VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,
6542 VkPhysicalDeviceProperties2 *pProperties) {
6543 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
6544 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Lenny Komowa1524852017-10-02 15:08:53 -06006545 const struct loader_instance *inst = icd_term->this_instance;
Lenny Komow82e15e02017-10-02 15:08:53 -06006546
Lenny Komowa1524852017-10-02 15:08:53 -06006547 // Get the function pointer to use to call into the ICD. This could be the core or KHR version
6548 PFN_vkGetPhysicalDeviceProperties2 fpGetPhysicalDeviceProperties2 = NULL;
6549 if (inst != NULL && inst->enabled_known_extensions.khr_get_physical_device_properties2) {
6550 fpGetPhysicalDeviceProperties2 = icd_term->dispatch.GetPhysicalDeviceProperties2KHR;
6551 } else {
6552 fpGetPhysicalDeviceProperties2 = icd_term->dispatch.GetPhysicalDeviceProperties2;
6553 }
6554
Lenny Komow88dc89b2017-11-03 14:37:11 -06006555 if (fpGetPhysicalDeviceProperties2 != NULL || !inst->enabled_known_extensions.khr_get_physical_device_properties2) {
Lenny Komow82e15e02017-10-02 15:08:53 -06006556 // Pass the call to the driver
Lenny Komowa1524852017-10-02 15:08:53 -06006557 fpGetPhysicalDeviceProperties2(phys_dev_term->phys_dev, pProperties);
Lenny Komow82e15e02017-10-02 15:08:53 -06006558 } else {
6559 // Emulate the call
6560 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006561 "vkGetPhysicalDeviceProperties2: Emulating call in ICD \"%s\" using vkGetPhysicalDeviceProperties",
Lenny Komow82e15e02017-10-02 15:08:53 -06006562 icd_term->scanned_icd->lib_name);
6563
Lenny Komow802a9652017-10-03 13:59:21 -06006564 // Write to the VkPhysicalDeviceProperties2 struct
Lenny Komow82e15e02017-10-02 15:08:53 -06006565 icd_term->dispatch.GetPhysicalDeviceProperties(phys_dev_term->phys_dev, &pProperties->properties);
6566
6567 void *pNext = pProperties->pNext;
6568 while (pNext != NULL) {
6569 switch (*(VkStructureType *)pNext) {
Lenny Komow802a9652017-10-03 13:59:21 -06006570 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES: {
Lenny Komow82e15e02017-10-02 15:08:53 -06006571 VkPhysicalDeviceIDPropertiesKHR *id_properties = pNext;
6572
6573 // Verify that "VK_KHR_external_memory_capabilities" is enabled
6574 if (icd_term->this_instance->enabled_known_extensions.khr_external_memory_capabilities) {
6575 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006576 "vkGetPhysicalDeviceProperties2: Emulation cannot generate unique IDs for struct "
6577 "VkPhysicalDeviceIDProperties - setting IDs to zero instead");
Lenny Komow82e15e02017-10-02 15:08:53 -06006578
6579 // Write to the VkPhysicalDeviceIDPropertiesKHR struct
6580 memset(id_properties->deviceUUID, 0, VK_UUID_SIZE);
6581 memset(id_properties->driverUUID, 0, VK_UUID_SIZE);
6582 id_properties->deviceLUIDValid = VK_FALSE;
6583 }
6584
6585 pNext = id_properties->pNext;
6586 break;
6587 }
6588 default: {
6589 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
6590 "vkGetPhysicalDeviceProperties2KHR: Emulation found unrecognized structure type in "
6591 "pProperties->pNext - this struct will be ignored");
6592
6593 struct VkStructureHeader *header = pNext;
6594 pNext = (void *)header->pNext;
6595 break;
6596 }
6597 }
6598 }
6599 }
6600}
6601
6602VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format,
6603 VkFormatProperties2 *pFormatProperties) {
6604 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
6605 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Lenny Komowa1524852017-10-02 15:08:53 -06006606 const struct loader_instance *inst = icd_term->this_instance;
Lenny Komow82e15e02017-10-02 15:08:53 -06006607
Lenny Komowa1524852017-10-02 15:08:53 -06006608 // Get the function pointer to use to call into the ICD. This could be the core or KHR version
6609 PFN_vkGetPhysicalDeviceFormatProperties2 fpGetPhysicalDeviceFormatProperties2 = NULL;
6610 if (inst != NULL && inst->enabled_known_extensions.khr_get_physical_device_properties2) {
6611 fpGetPhysicalDeviceFormatProperties2 = icd_term->dispatch.GetPhysicalDeviceFormatProperties2KHR;
6612 } else {
6613 fpGetPhysicalDeviceFormatProperties2 = icd_term->dispatch.GetPhysicalDeviceFormatProperties2;
6614 }
6615
Lenny Komow88dc89b2017-11-03 14:37:11 -06006616 if (fpGetPhysicalDeviceFormatProperties2 != NULL || !inst->enabled_known_extensions.khr_get_physical_device_properties2) {
Lenny Komow82e15e02017-10-02 15:08:53 -06006617 // Pass the call to the driver
Lenny Komowa1524852017-10-02 15:08:53 -06006618 fpGetPhysicalDeviceFormatProperties2(phys_dev_term->phys_dev, format, pFormatProperties);
Lenny Komow82e15e02017-10-02 15:08:53 -06006619 } else {
6620 // Emulate the call
6621 loader_log(
6622 icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006623 "vkGetPhysicalDeviceFormatProperties2: Emulating call in ICD \"%s\" using vkGetPhysicalDeviceFormatProperties",
Lenny Komow82e15e02017-10-02 15:08:53 -06006624 icd_term->scanned_icd->lib_name);
6625
Lenny Komow802a9652017-10-03 13:59:21 -06006626 // Write to the VkFormatProperties2 struct
Lenny Komow82e15e02017-10-02 15:08:53 -06006627 icd_term->dispatch.GetPhysicalDeviceFormatProperties(phys_dev_term->phys_dev, format, &pFormatProperties->formatProperties);
6628
6629 if (pFormatProperties->pNext != NULL) {
6630 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006631 "vkGetPhysicalDeviceFormatProperties2: Emulation found unrecognized structure type in "
Lenny Komow82e15e02017-10-02 15:08:53 -06006632 "pFormatProperties->pNext - this struct will be ignored");
6633 }
6634 }
6635}
6636
6637VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceImageFormatProperties2(
6638 VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2KHR *pImageFormatInfo,
6639 VkImageFormatProperties2KHR *pImageFormatProperties) {
6640 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
6641 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Lenny Komowa1524852017-10-02 15:08:53 -06006642 const struct loader_instance *inst = icd_term->this_instance;
Lenny Komow82e15e02017-10-02 15:08:53 -06006643
Lenny Komowa1524852017-10-02 15:08:53 -06006644 // Get the function pointer to use to call into the ICD. This could be the core or KHR version
6645 PFN_vkGetPhysicalDeviceImageFormatProperties2 fpGetPhysicalDeviceImageFormatProperties2 = NULL;
6646 if (inst != NULL && inst->enabled_known_extensions.khr_get_physical_device_properties2) {
6647 fpGetPhysicalDeviceImageFormatProperties2 = icd_term->dispatch.GetPhysicalDeviceImageFormatProperties2KHR;
6648 } else {
6649 fpGetPhysicalDeviceImageFormatProperties2 = icd_term->dispatch.GetPhysicalDeviceImageFormatProperties2;
6650 }
6651
Lenny Komow88dc89b2017-11-03 14:37:11 -06006652 if (fpGetPhysicalDeviceImageFormatProperties2 != NULL || !inst->enabled_known_extensions.khr_get_physical_device_properties2) {
Lenny Komow82e15e02017-10-02 15:08:53 -06006653 // Pass the call to the driver
Lenny Komowa1524852017-10-02 15:08:53 -06006654 return fpGetPhysicalDeviceImageFormatProperties2(phys_dev_term->phys_dev, pImageFormatInfo, pImageFormatProperties);
Lenny Komow82e15e02017-10-02 15:08:53 -06006655 } else {
6656 // Emulate the call
6657 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006658 "vkGetPhysicalDeviceImageFormatProperties2: Emulating call in ICD \"%s\" using "
Lenny Komow82e15e02017-10-02 15:08:53 -06006659 "vkGetPhysicalDeviceImageFormatProperties",
6660 icd_term->scanned_icd->lib_name);
6661
6662 // If there is more info in either pNext, then this is unsupported
6663 if (pImageFormatInfo->pNext != NULL || pImageFormatProperties->pNext != NULL) {
6664 return VK_ERROR_FORMAT_NOT_SUPPORTED;
6665 }
6666
6667 // Write to the VkImageFormatProperties2KHR struct
6668 return icd_term->dispatch.GetPhysicalDeviceImageFormatProperties(
6669 phys_dev_term->phys_dev, pImageFormatInfo->format, pImageFormatInfo->type, pImageFormatInfo->tiling,
6670 pImageFormatInfo->usage, pImageFormatInfo->flags, &pImageFormatProperties->imageFormatProperties);
6671 }
6672}
6673
6674VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceQueueFamilyProperties2(
6675 VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
6676 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
6677 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Lenny Komowa1524852017-10-02 15:08:53 -06006678 const struct loader_instance *inst = icd_term->this_instance;
Lenny Komow82e15e02017-10-02 15:08:53 -06006679
Lenny Komowa1524852017-10-02 15:08:53 -06006680 // Get the function pointer to use to call into the ICD. This could be the core or KHR version
6681 PFN_vkGetPhysicalDeviceQueueFamilyProperties2 fpGetPhysicalDeviceQueueFamilyProperties2 = NULL;
6682 if (inst != NULL && inst->enabled_known_extensions.khr_get_physical_device_properties2) {
6683 fpGetPhysicalDeviceQueueFamilyProperties2 = icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties2KHR;
6684 } else {
6685 fpGetPhysicalDeviceQueueFamilyProperties2 = icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties2;
6686 }
6687
Lenny Komow88dc89b2017-11-03 14:37:11 -06006688 if (fpGetPhysicalDeviceQueueFamilyProperties2 != NULL || !inst->enabled_known_extensions.khr_get_physical_device_properties2) {
Lenny Komow82e15e02017-10-02 15:08:53 -06006689 // Pass the call to the driver
Lenny Komowa1524852017-10-02 15:08:53 -06006690 fpGetPhysicalDeviceQueueFamilyProperties2(phys_dev_term->phys_dev, pQueueFamilyPropertyCount, pQueueFamilyProperties);
Lenny Komow82e15e02017-10-02 15:08:53 -06006691 } else {
6692 // Emulate the call
6693 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006694 "vkGetPhysicalDeviceQueueFamilyProperties2: Emulating call in ICD \"%s\" using "
Lenny Komow82e15e02017-10-02 15:08:53 -06006695 "vkGetPhysicalDeviceQueueFamilyProperties",
6696 icd_term->scanned_icd->lib_name);
6697
6698 if (pQueueFamilyProperties == NULL || *pQueueFamilyPropertyCount == 0) {
6699 // Write to pQueueFamilyPropertyCount
6700 icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties(phys_dev_term->phys_dev, pQueueFamilyPropertyCount, NULL);
6701 } else {
6702 // Allocate a temporary array for the output of the old function
6703 VkQueueFamilyProperties *properties = loader_stack_alloc(*pQueueFamilyPropertyCount * sizeof(VkQueueFamilyProperties));
6704 if (properties == NULL) {
6705 *pQueueFamilyPropertyCount = 0;
6706 loader_log(
6707 icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006708 "vkGetPhysicalDeviceQueueFamilyProperties2: Out of memory - Failed to allocate array for loader emulation.");
Lenny Komow82e15e02017-10-02 15:08:53 -06006709 return;
6710 }
6711
6712 icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties(phys_dev_term->phys_dev, pQueueFamilyPropertyCount,
6713 properties);
6714 for (uint32_t i = 0; i < *pQueueFamilyPropertyCount; ++i) {
6715 // Write to the VkQueueFamilyProperties2KHR struct
6716 memcpy(&pQueueFamilyProperties[i].queueFamilyProperties, &properties[i], sizeof(VkQueueFamilyProperties));
6717
6718 if (pQueueFamilyProperties[i].pNext != NULL) {
6719 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006720 "vkGetPhysicalDeviceQueueFamilyProperties2: Emulation found unrecognized structure type in "
Lenny Komow82e15e02017-10-02 15:08:53 -06006721 "pQueueFamilyProperties[%d].pNext - this struct will be ignored",
6722 i);
6723 }
6724 }
6725 }
6726 }
6727}
6728
6729VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceMemoryProperties2(
6730 VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2 *pMemoryProperties) {
6731 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
6732 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Lenny Komowa1524852017-10-02 15:08:53 -06006733 const struct loader_instance *inst = icd_term->this_instance;
Lenny Komow82e15e02017-10-02 15:08:53 -06006734
Lenny Komowa1524852017-10-02 15:08:53 -06006735 // Get the function pointer to use to call into the ICD. This could be the core or KHR version
6736 PFN_vkGetPhysicalDeviceMemoryProperties2 fpGetPhysicalDeviceMemoryProperties2 = NULL;
6737 if (inst != NULL && inst->enabled_known_extensions.khr_get_physical_device_properties2) {
6738 fpGetPhysicalDeviceMemoryProperties2 = icd_term->dispatch.GetPhysicalDeviceMemoryProperties2KHR;
6739 } else {
6740 fpGetPhysicalDeviceMemoryProperties2 = icd_term->dispatch.GetPhysicalDeviceMemoryProperties2;
6741 }
6742
Lenny Komow88dc89b2017-11-03 14:37:11 -06006743 if (fpGetPhysicalDeviceMemoryProperties2 != NULL || !inst->enabled_known_extensions.khr_get_physical_device_properties2) {
Lenny Komow82e15e02017-10-02 15:08:53 -06006744 // Pass the call to the driver
Lenny Komowa1524852017-10-02 15:08:53 -06006745 fpGetPhysicalDeviceMemoryProperties2(phys_dev_term->phys_dev, pMemoryProperties);
Lenny Komow82e15e02017-10-02 15:08:53 -06006746 } else {
6747 // Emulate the call
6748 loader_log(
6749 icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006750 "vkGetPhysicalDeviceMemoryProperties2: Emulating call in ICD \"%s\" using vkGetPhysicalDeviceMemoryProperties",
Lenny Komow82e15e02017-10-02 15:08:53 -06006751 icd_term->scanned_icd->lib_name);
6752
6753 // Write to the VkPhysicalDeviceMemoryProperties2 struct
6754 icd_term->dispatch.GetPhysicalDeviceMemoryProperties(phys_dev_term->phys_dev, &pMemoryProperties->memoryProperties);
6755
6756 if (pMemoryProperties->pNext != NULL) {
6757 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006758 "vkGetPhysicalDeviceMemoryProperties2: Emulation found unrecognized structure type in "
Lenny Komow82e15e02017-10-02 15:08:53 -06006759 "pMemoryProperties->pNext - this struct will be ignored");
6760 }
6761 }
6762}
6763
6764VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceSparseImageFormatProperties2(
6765 VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2KHR *pFormatInfo, uint32_t *pPropertyCount,
6766 VkSparseImageFormatProperties2KHR *pProperties) {
6767 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
6768 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Lenny Komowa1524852017-10-02 15:08:53 -06006769 const struct loader_instance *inst = icd_term->this_instance;
Lenny Komow82e15e02017-10-02 15:08:53 -06006770
Lenny Komowa1524852017-10-02 15:08:53 -06006771 // Get the function pointer to use to call into the ICD. This could be the core or KHR version
6772 PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 fpGetPhysicalDeviceSparseImageFormatProperties2 = NULL;
6773 if (inst != NULL && inst->enabled_known_extensions.khr_get_physical_device_properties2) {
6774 fpGetPhysicalDeviceSparseImageFormatProperties2 = icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties2KHR;
6775 } else {
6776 fpGetPhysicalDeviceSparseImageFormatProperties2 = icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties2;
6777 }
6778
Lenny Komow88dc89b2017-11-03 14:37:11 -06006779 if (fpGetPhysicalDeviceSparseImageFormatProperties2 != NULL || !inst->enabled_known_extensions.khr_get_physical_device_properties2) {
Lenny Komow82e15e02017-10-02 15:08:53 -06006780 // Pass the call to the driver
Lenny Komowa1524852017-10-02 15:08:53 -06006781 fpGetPhysicalDeviceSparseImageFormatProperties2(phys_dev_term->phys_dev, pFormatInfo, pPropertyCount, pProperties);
Lenny Komow82e15e02017-10-02 15:08:53 -06006782 } else {
6783 // Emulate the call
6784 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006785 "vkGetPhysicalDeviceSparseImageFormatProperties2: Emulating call in ICD \"%s\" using "
Lenny Komow82e15e02017-10-02 15:08:53 -06006786 "vkGetPhysicalDeviceSparseImageFormatProperties",
6787 icd_term->scanned_icd->lib_name);
6788
6789 if (pFormatInfo->pNext != NULL) {
6790 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006791 "vkGetPhysicalDeviceSparseImageFormatProperties2: Emulation found unrecognized structure type in "
Lenny Komow82e15e02017-10-02 15:08:53 -06006792 "pFormatInfo->pNext - this struct will be ignored");
6793 }
6794
6795 if (pProperties == NULL || *pPropertyCount == 0) {
6796 // Write to pPropertyCount
6797 icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties(
6798 phys_dev_term->phys_dev, pFormatInfo->format, pFormatInfo->type, pFormatInfo->samples, pFormatInfo->usage,
6799 pFormatInfo->tiling, pPropertyCount, NULL);
6800 } else {
6801 // Allocate a temporary array for the output of the old function
6802 VkSparseImageFormatProperties *properties =
6803 loader_stack_alloc(*pPropertyCount * sizeof(VkSparseImageMemoryRequirements));
6804 if (properties == NULL) {
6805 *pPropertyCount = 0;
6806 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006807 "vkGetPhysicalDeviceSparseImageFormatProperties2: Out of memory - Failed to allocate array for "
Lenny Komow82e15e02017-10-02 15:08:53 -06006808 "loader emulation.");
6809 return;
6810 }
6811
6812 icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties(
6813 phys_dev_term->phys_dev, pFormatInfo->format, pFormatInfo->type, pFormatInfo->samples, pFormatInfo->usage,
6814 pFormatInfo->tiling, pPropertyCount, properties);
6815 for (uint32_t i = 0; i < *pPropertyCount; ++i) {
6816 // Write to the VkSparseImageFormatProperties2KHR struct
6817 memcpy(&pProperties[i].properties, &properties[i], sizeof(VkSparseImageFormatProperties));
6818
6819 if (pProperties[i].pNext != NULL) {
6820 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006821 "vkGetPhysicalDeviceSparseImageFormatProperties2: Emulation found unrecognized structure type in "
Lenny Komow82e15e02017-10-02 15:08:53 -06006822 "pProperties[%d].pNext - this struct will be ignored",
6823 i);
6824 }
6825 }
6826 }
6827 }
6828}
6829
6830VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceExternalBufferProperties(
6831 VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo,
6832 VkExternalBufferProperties *pExternalBufferProperties) {
6833 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
6834 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Lenny Komowa1524852017-10-02 15:08:53 -06006835 const struct loader_instance *inst = icd_term->this_instance;
Lenny Komow82e15e02017-10-02 15:08:53 -06006836
Lenny Komowa1524852017-10-02 15:08:53 -06006837 // Get the function pointer to use to call into the ICD. This could be the core or KHR version
6838 PFN_vkGetPhysicalDeviceExternalBufferProperties fpGetPhysicalDeviceExternalBufferProperties = NULL;
6839 if (inst != NULL && inst->enabled_known_extensions.khr_external_memory_capabilities) {
6840 fpGetPhysicalDeviceExternalBufferProperties = icd_term->dispatch.GetPhysicalDeviceExternalBufferPropertiesKHR;
6841 } else {
6842 fpGetPhysicalDeviceExternalBufferProperties = icd_term->dispatch.GetPhysicalDeviceExternalBufferProperties;
6843 }
6844
Lenny Komow88dc89b2017-11-03 14:37:11 -06006845 if (fpGetPhysicalDeviceExternalBufferProperties || !inst->enabled_known_extensions.khr_external_memory_capabilities) {
Lenny Komow82e15e02017-10-02 15:08:53 -06006846 // Pass the call to the driver
Lenny Komowa1524852017-10-02 15:08:53 -06006847 fpGetPhysicalDeviceExternalBufferProperties(phys_dev_term->phys_dev, pExternalBufferInfo, pExternalBufferProperties);
Lenny Komow82e15e02017-10-02 15:08:53 -06006848 } else {
6849 // Emulate the call
6850 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006851 "vkGetPhysicalDeviceExternalBufferProperties: Emulating call in ICD \"%s\"", icd_term->scanned_icd->lib_name);
Lenny Komow82e15e02017-10-02 15:08:53 -06006852
6853 if (pExternalBufferInfo->pNext != NULL) {
6854 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006855 "vkGetPhysicalDeviceExternalBufferProperties: Emulation found unrecognized structure type in "
Lenny Komow82e15e02017-10-02 15:08:53 -06006856 "pExternalBufferInfo->pNext - this struct will be ignored");
6857 }
6858
6859 // Fill in everything being unsupported
6860 memset(&pExternalBufferProperties->externalMemoryProperties, 0, sizeof(VkExternalMemoryPropertiesKHR));
6861
6862 if (pExternalBufferProperties->pNext != NULL) {
6863 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006864 "vkGetPhysicalDeviceExternalBufferProperties: Emulation found unrecognized structure type in "
Lenny Komow82e15e02017-10-02 15:08:53 -06006865 "pExternalBufferProperties->pNext - this struct will be ignored");
6866 }
6867 }
6868}
6869
6870VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceExternalSemaphoreProperties(
6871 VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo *pExternalSemaphoreInfo,
6872 VkExternalSemaphoreProperties *pExternalSemaphoreProperties) {
6873 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
6874 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Lenny Komowa1524852017-10-02 15:08:53 -06006875 const struct loader_instance *inst = icd_term->this_instance;
Lenny Komow82e15e02017-10-02 15:08:53 -06006876
Lenny Komowa1524852017-10-02 15:08:53 -06006877 // Get the function pointer to use to call into the ICD. This could be the core or KHR version
6878 PFN_vkGetPhysicalDeviceExternalSemaphoreProperties fpGetPhysicalDeviceExternalSemaphoreProperties = NULL;
6879 if (inst != NULL && inst->enabled_known_extensions.khr_external_semaphore_capabilities) {
6880 fpGetPhysicalDeviceExternalSemaphoreProperties = icd_term->dispatch.GetPhysicalDeviceExternalSemaphorePropertiesKHR;
6881 } else {
6882 fpGetPhysicalDeviceExternalSemaphoreProperties = icd_term->dispatch.GetPhysicalDeviceExternalSemaphoreProperties;
6883 }
6884
Lenny Komow88dc89b2017-11-03 14:37:11 -06006885 if (fpGetPhysicalDeviceExternalSemaphoreProperties != NULL || !inst->enabled_known_extensions.khr_external_semaphore_capabilities) {
Lenny Komow82e15e02017-10-02 15:08:53 -06006886 // Pass the call to the driver
Lenny Komowa1524852017-10-02 15:08:53 -06006887 fpGetPhysicalDeviceExternalSemaphoreProperties(phys_dev_term->phys_dev, pExternalSemaphoreInfo, pExternalSemaphoreProperties);
Lenny Komow82e15e02017-10-02 15:08:53 -06006888 } else {
6889 // Emulate the call
6890 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006891 "vkGetPhysicalDeviceExternalSemaphoreProperties: Emulating call in ICD \"%s\"",
Lenny Komow82e15e02017-10-02 15:08:53 -06006892 icd_term->scanned_icd->lib_name);
6893
6894 if (pExternalSemaphoreInfo->pNext != NULL) {
6895 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006896 "vkGetPhysicalDeviceExternalSemaphoreProperties: Emulation found unrecognized structure type in "
Lenny Komow82e15e02017-10-02 15:08:53 -06006897 "pExternalSemaphoreInfo->pNext - this struct will be ignored");
6898 }
6899
6900 // Fill in everything being unsupported
6901 pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
6902 pExternalSemaphoreProperties->compatibleHandleTypes = 0;
6903 pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
6904
6905 if (pExternalSemaphoreProperties->pNext != NULL) {
6906 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006907 "vkGetPhysicalDeviceExternalSemaphoreProperties: Emulation found unrecognized structure type in "
Lenny Komow82e15e02017-10-02 15:08:53 -06006908 "pExternalSemaphoreProperties->pNext - this struct will be ignored");
6909 }
6910 }
6911}
6912
6913VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceExternalFenceProperties(
6914 VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo *pExternalFenceInfo,
6915 VkExternalFenceProperties *pExternalFenceProperties) {
6916 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
6917 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Lenny Komowa1524852017-10-02 15:08:53 -06006918 const struct loader_instance *inst = icd_term->this_instance;
Lenny Komow82e15e02017-10-02 15:08:53 -06006919
Lenny Komowa1524852017-10-02 15:08:53 -06006920 // Get the function pointer to use to call into the ICD. This could be the core or KHR version
6921 PFN_vkGetPhysicalDeviceExternalFenceProperties fpGetPhysicalDeviceExternalFenceProperties = NULL;
6922 if (inst != NULL && inst->enabled_known_extensions.khr_external_fence_capabilities) {
6923 fpGetPhysicalDeviceExternalFenceProperties = icd_term->dispatch.GetPhysicalDeviceExternalFencePropertiesKHR;
6924 } else {
6925 fpGetPhysicalDeviceExternalFenceProperties = icd_term->dispatch.GetPhysicalDeviceExternalFenceProperties;
6926 }
6927
Lenny Komow88dc89b2017-11-03 14:37:11 -06006928 if (fpGetPhysicalDeviceExternalFenceProperties != NULL || !inst->enabled_known_extensions.khr_external_fence_capabilities) {
Lenny Komow82e15e02017-10-02 15:08:53 -06006929 // Pass the call to the driver
Lenny Komowa1524852017-10-02 15:08:53 -06006930 fpGetPhysicalDeviceExternalFenceProperties(phys_dev_term->phys_dev, pExternalFenceInfo, pExternalFenceProperties);
Lenny Komow82e15e02017-10-02 15:08:53 -06006931 } else {
6932 // Emulate the call
6933 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006934 "vkGetPhysicalDeviceExternalFenceProperties: Emulating call in ICD \"%s\"", icd_term->scanned_icd->lib_name);
Lenny Komow82e15e02017-10-02 15:08:53 -06006935
6936 if (pExternalFenceInfo->pNext != NULL) {
6937 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006938 "vkGetPhysicalDeviceExternalFenceProperties: Emulation found unrecognized structure type in "
Lenny Komow82e15e02017-10-02 15:08:53 -06006939 "pExternalFenceInfo->pNext - this struct will be ignored");
6940 }
6941
6942 // Fill in everything being unsupported
6943 pExternalFenceProperties->exportFromImportedHandleTypes = 0;
6944 pExternalFenceProperties->compatibleHandleTypes = 0;
6945 pExternalFenceProperties->externalFenceFeatures = 0;
6946
6947 if (pExternalFenceProperties->pNext != NULL) {
6948 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006949 "vkGetPhysicalDeviceExternalFenceProperties: Emulation found unrecognized structure type in "
Lenny Komow82e15e02017-10-02 15:08:53 -06006950 "pExternalFenceProperties->pNext - this struct will be ignored");
6951 }
6952 }
6953}