blob: 1e7a8049249b962fd27d398d6aab339d9da8207f [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"
Mark Young6ba8abe2017-11-09 10:37:04 -070048#include "debug_utils.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
Lenny Komow16586112018-02-13 15:58:47 -0700101// This loader supports Vulkan API version 1.1
102uint32_t loader_major_version = 1;
103uint32_t loader_minor_version = 1;
104
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700105void *loader_instance_heap_alloc(const struct loader_instance *instance, size_t size, VkSystemAllocationScope alloc_scope) {
Mark Young0ad83132016-06-30 13:02:42 -0600106 void *pMemory = NULL;
107#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
108 {
109#else
Chia-I Wu3432a0c2015-10-27 18:04:07 +0800110 if (instance && instance->alloc_callbacks.pfnAllocation) {
Mark Young0f183a82017-02-28 09:58:04 -0700111 // These are internal structures, so it's best to align everything to
112 // the largest unit size which is the size of a uint64_t.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700113 pMemory = instance->alloc_callbacks.pfnAllocation(instance->alloc_callbacks.pUserData, size, sizeof(uint64_t), alloc_scope);
Mark Young0ad83132016-06-30 13:02:42 -0600114 } else {
115#endif
116 pMemory = malloc(size);
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600117 }
Mark Youngf2079b92017-05-02 10:49:46 -0600118
Mark Young0ad83132016-06-30 13:02:42 -0600119 return pMemory;
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600120}
121
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700122void loader_instance_heap_free(const struct loader_instance *instance, void *pMemory) {
Mark Young0ad83132016-06-30 13:02:42 -0600123 if (pMemory != NULL) {
124#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
125 {
126#else
127 if (instance && instance->alloc_callbacks.pfnFree) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700128 instance->alloc_callbacks.pfnFree(instance->alloc_callbacks.pUserData, pMemory);
Mark Young0ad83132016-06-30 13:02:42 -0600129 } else {
130#endif
131 free(pMemory);
Mark Youngd077f992016-06-30 11:03:59 -0600132 }
Mark Young4b0b9222016-06-29 18:33:53 -0600133 }
Mark Young4b0b9222016-06-29 18:33:53 -0600134}
135
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700136void *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 -0600137 VkSystemAllocationScope alloc_scope) {
138 void *pNewMem = NULL;
139 if (pMemory == NULL || orig_size == 0) {
140 pNewMem = loader_instance_heap_alloc(instance, size, alloc_scope);
141 } else if (size == 0) {
142 loader_instance_heap_free(instance, pMemory);
143#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
144#else
145 } else if (instance && instance->alloc_callbacks.pfnReallocation) {
Mark Young0f183a82017-02-28 09:58:04 -0700146 // These are internal structures, so it's best to align everything to
147 // the largest unit size which is the size of a uint64_t.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700148 pNewMem = instance->alloc_callbacks.pfnReallocation(instance->alloc_callbacks.pUserData, pMemory, size, sizeof(uint64_t),
149 alloc_scope);
Mark Young0ad83132016-06-30 13:02:42 -0600150#endif
151 } else {
152 pNewMem = realloc(pMemory, size);
153 }
154 return pNewMem;
Mark Young4b0b9222016-06-29 18:33:53 -0600155}
156
Mark Young0ad83132016-06-30 13:02:42 -0600157void *loader_instance_tls_heap_alloc(size_t size) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700158 return loader_instance_heap_alloc(tls_instance, size, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Mark Young4b0b9222016-06-29 18:33:53 -0600159}
Mark Young4b0b9222016-06-29 18:33:53 -0600160
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700161void loader_instance_tls_heap_free(void *pMemory) { loader_instance_heap_free(tls_instance, pMemory); }
Mark Young0ad83132016-06-30 13:02:42 -0600162
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700163void *loader_device_heap_alloc(const struct loader_device *device, size_t size, VkSystemAllocationScope alloc_scope) {
Mark Young0ad83132016-06-30 13:02:42 -0600164 void *pMemory = NULL;
165#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
166 {
167#else
168 if (device && device->alloc_callbacks.pfnAllocation) {
Mark Young0f183a82017-02-28 09:58:04 -0700169 // These are internal structures, so it's best to align everything to
170 // the largest unit size which is the size of a uint64_t.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700171 pMemory = device->alloc_callbacks.pfnAllocation(device->alloc_callbacks.pUserData, size, sizeof(uint64_t), alloc_scope);
Mark Young0ad83132016-06-30 13:02:42 -0600172 } else {
173#endif
174 pMemory = malloc(size);
175 }
176 return pMemory;
177}
178
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700179void loader_device_heap_free(const struct loader_device *device, void *pMemory) {
Mark Young0ad83132016-06-30 13:02:42 -0600180 if (pMemory != NULL) {
181#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
182 {
183#else
184 if (device && device->alloc_callbacks.pfnFree) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700185 device->alloc_callbacks.pfnFree(device->alloc_callbacks.pUserData, pMemory);
Mark Young0ad83132016-06-30 13:02:42 -0600186 } else {
187#endif
188 free(pMemory);
189 }
190 }
191}
192
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700193void *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 -0600194 VkSystemAllocationScope alloc_scope) {
195 void *pNewMem = NULL;
196 if (pMemory == NULL || orig_size == 0) {
197 pNewMem = loader_device_heap_alloc(device, size, alloc_scope);
198 } else if (size == 0) {
199 loader_device_heap_free(device, pMemory);
200#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
201#else
202 } else if (device && device->alloc_callbacks.pfnReallocation) {
Mark Young0f183a82017-02-28 09:58:04 -0700203 // These are internal structures, so it's best to align everything to
204 // the largest unit size which is the size of a uint64_t.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700205 pNewMem = device->alloc_callbacks.pfnReallocation(device->alloc_callbacks.pUserData, pMemory, size, sizeof(uint64_t),
206 alloc_scope);
Mark Young0ad83132016-06-30 13:02:42 -0600207#endif
208 } else {
209 pNewMem = realloc(pMemory, size);
210 }
211 return pNewMem;
212}
213
214// Environment variables
Karl Schultz2e5ed332017-12-12 10:33:01 -0500215#if defined(__linux__) || defined(__APPLE__)
Mark Young0ad83132016-06-30 13:02:42 -0600216
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700217static inline char *loader_getenv(const char *name, const struct loader_instance *inst) {
Mark Young0ad83132016-06-30 13:02:42 -0600218 // No allocation of memory necessary for Linux, but we should at least touch
219 // the inst pointer to get rid of compiler warnings.
220 (void)inst;
Mark Youngd8c6b692017-03-09 11:39:41 -0700221 return getenv(name);
222}
223
Mark Youngd8c6b692017-03-09 11:39:41 -0700224static inline char *loader_secure_getenv(const char *name, const struct loader_instance *inst) {
Karl Schultz2e5ed332017-12-12 10:33:01 -0500225#if defined(__APPLE__)
226 // Apple does not appear to have a secure getenv implementation.
227 // The main difference between secure getenv and getenv is that secure getenv
228 // returns NULL if the process is being run with elevated privileges by a normal user.
229 // The idea is to prevent the reading of malicious environment variables by a process
230 // that can do damage.
231 // This algorithm is derived from glibc code that sets an internal
232 // variable (__libc_enable_secure) if the process is running under setuid or setgid.
233 return geteuid() != getuid() || getegid() != getgid() ? NULL : loader_getenv(name, inst);
234#else
235// Linux
Mark Youngba7ee022017-03-09 10:41:25 -0700236#ifdef HAVE_SECURE_GETENV
Karl Schultz2e5ed332017-12-12 10:33:01 -0500237 (void)inst;
Mark Youngba7ee022017-03-09 10:41:25 -0700238 return secure_getenv(name);
239#elif defined(HAVE___SECURE_GETENV)
Karl Schultz2e5ed332017-12-12 10:33:01 -0500240 (void)inst;
Mark Youngf2f2a662017-03-08 10:11:52 -0700241 return __secure_getenv(name);
242#else
Mark Youngf2079b92017-05-02 10:49:46 -0600243#pragma message( \
244 "Warning: Falling back to non-secure getenv for environmental lookups! Consider" \
245 " updating to a different libc.")
Mark Youngd8c6b692017-03-09 11:39:41 -0700246 return loader_getenv(name, inst);
Mark Youngf2f2a662017-03-08 10:11:52 -0700247#endif
Karl Schultz2e5ed332017-12-12 10:33:01 -0500248#endif
Mark Young0ad83132016-06-30 13:02:42 -0600249}
Mark Youngf2f2a662017-03-08 10:11:52 -0700250
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700251static inline void loader_free_getenv(char *val, const struct loader_instance *inst) {
Mark Young0ad83132016-06-30 13:02:42 -0600252 // No freeing of memory necessary for Linux, but we should at least touch
253 // the val and inst pointers to get rid of compiler warnings.
254 (void)val;
255 (void)inst;
256}
257
258#elif defined(WIN32)
259
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700260static inline char *loader_getenv(const char *name, const struct loader_instance *inst) {
Mark Young0ad83132016-06-30 13:02:42 -0600261 char *retVal;
262 DWORD valSize;
263
264 valSize = GetEnvironmentVariableA(name, NULL, 0);
265
266 // valSize DOES include the null terminator, so for any set variable
267 // will always be at least 1. If it's 0, the variable wasn't set.
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700268 if (valSize == 0) return NULL;
Mark Young0ad83132016-06-30 13:02:42 -0600269
270 // Allocate the space necessary for the registry entry
271 if (NULL != inst && NULL != inst->alloc_callbacks.pfnAllocation) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700272 retVal = (char *)inst->alloc_callbacks.pfnAllocation(inst->alloc_callbacks.pUserData, valSize, sizeof(char *),
273 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Mark Young0ad83132016-06-30 13:02:42 -0600274 } else {
275 retVal = (char *)malloc(valSize);
276 }
277
278 if (NULL != retVal) {
279 GetEnvironmentVariableA(name, retVal, valSize);
280 }
281
282 return retVal;
283}
284
Mark Youngd8c6b692017-03-09 11:39:41 -0700285static inline char *loader_secure_getenv(const char *name, const struct loader_instance *inst) {
Mark Youngbb3a29c2017-05-19 12:29:43 -0600286 // No secure version for Windows as far as I know
Mark Youngd8c6b692017-03-09 11:39:41 -0700287 return loader_getenv(name, inst);
288}
289
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700290static inline void loader_free_getenv(char *val, const struct loader_instance *inst) {
Mark Young0ad83132016-06-30 13:02:42 -0600291 if (NULL != inst && NULL != inst->alloc_callbacks.pfnFree) {
292 inst->alloc_callbacks.pfnFree(inst->alloc_callbacks.pUserData, val);
293 } else {
294 free((void *)val);
295 }
296}
297
298#else
299
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700300static inline char *loader_getenv(const char *name, const struct loader_instance *inst) {
Mark Young0ad83132016-06-30 13:02:42 -0600301 // stub func
302 (void)inst;
303 (void)name;
304 return NULL;
305}
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700306static inline void loader_free_getenv(char *val, const struct loader_instance *inst) {
Mark Young0ad83132016-06-30 13:02:42 -0600307 // stub func
308 (void)val;
309 (void)inst;
310}
311
312#endif
313
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700314void loader_log(const struct loader_instance *inst, VkFlags msg_type, int32_t msg_code, const char *format, ...) {
Jon Ashburn86723b02015-07-31 15:47:59 -0600315 char msg[512];
Mark Young2c84c0c2017-01-13 10:27:03 -0700316 char cmd_line_msg[512];
Mark Young5de3af72017-04-25 08:08:29 -0600317 size_t cmd_line_size = sizeof(cmd_line_msg);
Jon Ashburnffad94d2015-06-30 14:46:22 -0700318 va_list ap;
319 int ret;
320
Jon Ashburnffad94d2015-06-30 14:46:22 -0700321 va_start(ap, format);
322 ret = vsnprintf(msg, sizeof(msg), format, ap);
Jon Ashburn23d36b12016-02-02 17:47:28 -0700323 if ((ret >= (int)sizeof(msg)) || ret < 0) {
324 msg[sizeof(msg) - 1] = '\0';
Jon Ashburnffad94d2015-06-30 14:46:22 -0700325 }
326 va_end(ap);
327
Courtney Goeltzenleuchter73477392015-12-03 13:48:01 -0700328 if (inst) {
Lenny Komow281033b2018-02-13 17:35:28 -0700329 VkDebugUtilsMessageSeverityFlagBitsEXT severity = 0;
Mark Young6ba8abe2017-11-09 10:37:04 -0700330 VkDebugUtilsMessageTypeFlagsEXT type;
331 VkDebugUtilsMessengerCallbackDataEXT callback_data;
332 VkDebugUtilsObjectNameInfoEXT object_name;
333
334 if ((msg_type & LOADER_INFO_BIT) != 0) {
335 severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
336 } else if ((msg_type & LOADER_WARN_BIT) != 0) {
337 severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
338 } else if ((msg_type & LOADER_ERROR_BIT) != 0) {
339 severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
340 } else if ((msg_type & LOADER_DEBUG_BIT) != 0) {
341 severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
342 }
343
344 if ((msg_type & LOADER_PERF_BIT) != 0) {
345 type = VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
346 } else {
347 type = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
348 }
349
350 callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
351 callback_data.pNext = NULL;
352 callback_data.flags = 0;
353 callback_data.pMessageIdName = "Loader Message";
354 callback_data.messageIdNumber = 0;
355 callback_data.pMessage = msg;
356 callback_data.queueLabelCount = 0;
357 callback_data.pQueueLabels = NULL;
358 callback_data.cmdBufLabelCount = 0;
359 callback_data.pCmdBufLabels = NULL;
360 callback_data.objectCount = 1;
361 callback_data.pObjects = &object_name;
362 object_name.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
363 object_name.pNext = NULL;
364 object_name.objectType = VK_OBJECT_TYPE_INSTANCE;
365 object_name.objectHandle = (uint64_t)(uintptr_t)inst;
366 object_name.pObjectName = NULL;
367
368 util_SubmitDebugUtilsMessageEXT(inst, severity, type, &callback_data);
Courtney Goeltzenleuchter73477392015-12-03 13:48:01 -0700369 }
370
371 if (!(msg_type & g_loader_log_msgs)) {
372 return;
373 }
374
Mark Young2c84c0c2017-01-13 10:27:03 -0700375 cmd_line_msg[0] = '\0';
Mark Young5de3af72017-04-25 08:08:29 -0600376 cmd_line_size -= 1;
377 size_t original_size = cmd_line_size;
Mark Young2c84c0c2017-01-13 10:27:03 -0700378
379 va_start(ap, format);
380 if ((msg_type & LOADER_INFO_BIT) != 0) {
Mark Young6ef95f42017-02-17 09:02:23 -0700381 strncat(cmd_line_msg, "INFO", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700382 cmd_line_size -= 4;
383 }
384 if ((msg_type & LOADER_WARN_BIT) != 0) {
Mark Young5de3af72017-04-25 08:08:29 -0600385 if (cmd_line_size != original_size) {
Mark Young6ef95f42017-02-17 09:02:23 -0700386 strncat(cmd_line_msg, " | ", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700387 cmd_line_size -= 3;
388 }
Mark Young6ef95f42017-02-17 09:02:23 -0700389 strncat(cmd_line_msg, "WARNING", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700390 cmd_line_size -= 7;
391 }
392 if ((msg_type & LOADER_PERF_BIT) != 0) {
Mark Young5de3af72017-04-25 08:08:29 -0600393 if (cmd_line_size != original_size) {
Mark Young6ef95f42017-02-17 09:02:23 -0700394 strncat(cmd_line_msg, " | ", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700395 cmd_line_size -= 3;
396 }
Mark Young6ef95f42017-02-17 09:02:23 -0700397 strncat(cmd_line_msg, "PERF", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700398 cmd_line_size -= 4;
399 }
400 if ((msg_type & LOADER_ERROR_BIT) != 0) {
Mark Young5de3af72017-04-25 08:08:29 -0600401 if (cmd_line_size != original_size) {
Mark Young6ef95f42017-02-17 09:02:23 -0700402 strncat(cmd_line_msg, " | ", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700403 cmd_line_size -= 3;
404 }
Mark Young6ef95f42017-02-17 09:02:23 -0700405 strncat(cmd_line_msg, "ERROR", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700406 cmd_line_size -= 5;
407 }
408 if ((msg_type & LOADER_DEBUG_BIT) != 0) {
Mark Young5de3af72017-04-25 08:08:29 -0600409 if (cmd_line_size != original_size) {
Mark Young6ef95f42017-02-17 09:02:23 -0700410 strncat(cmd_line_msg, " | ", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700411 cmd_line_size -= 3;
412 }
Mark Young6ef95f42017-02-17 09:02:23 -0700413 strncat(cmd_line_msg, "DEBUG", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700414 cmd_line_size -= 5;
415 }
Mark Young5de3af72017-04-25 08:08:29 -0600416 if (cmd_line_size != original_size) {
Mark Young6ef95f42017-02-17 09:02:23 -0700417 strncat(cmd_line_msg, ": ", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700418 cmd_line_size -= 2;
419 }
Mark Young5de3af72017-04-25 08:08:29 -0600420
421 if (0 < cmd_line_size) {
422 // If the message is too long, trim it down
423 if (strlen(msg) > cmd_line_size) {
424 msg[cmd_line_size - 1] = '\0';
425 }
426 strncat(cmd_line_msg, msg, cmd_line_size);
427 } else {
428 // Shouldn't get here, but check to make sure if we've already overrun
429 // the string boundary
430 assert(false);
431 }
Mark Young2c84c0c2017-01-13 10:27:03 -0700432
Ian Elliott4470a302015-02-17 10:33:47 -0700433#if defined(WIN32)
Mark Young2c84c0c2017-01-13 10:27:03 -0700434 OutputDebugString(cmd_line_msg);
mschottb9cdb782015-07-22 14:11:29 +0200435 OutputDebugString("\n");
Jon Ashburnffad94d2015-06-30 14:46:22 -0700436#endif
Mark Young5de3af72017-04-25 08:08:29 -0600437
Mark Young2c84c0c2017-01-13 10:27:03 -0700438 fputs(cmd_line_msg, stderr);
Jon Ashburnffad94d2015-06-30 14:46:22 -0700439 fputc('\n', stderr);
440}
441
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700442VKAPI_ATTR VkResult VKAPI_CALL vkSetInstanceDispatch(VkInstance instance, void *object) {
Jon Ashburnc3c58772016-03-29 11:16:01 -0600443 struct loader_instance *inst = loader_get_instance(instance);
444 if (!inst) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700445 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
446 "vkSetInstanceDispatch: Can not retrieve Instance "
447 "dispatch table.");
Jon Ashburnc3c58772016-03-29 11:16:01 -0600448 return VK_ERROR_INITIALIZATION_FAILED;
449 }
450 loader_set_dispatch(object, inst->disp);
451 return VK_SUCCESS;
452}
453
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700454VKAPI_ATTR VkResult VKAPI_CALL vkSetDeviceDispatch(VkDevice device, void *object) {
Jon Ashburned8f2312016-03-31 10:52:22 -0600455 struct loader_device *dev;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700456 struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, NULL);
Jon Ashburned8f2312016-03-31 10:52:22 -0600457
Mark Young0153e0b2016-11-03 14:27:13 -0600458 if (NULL == icd_term) {
Jon Ashburned8f2312016-03-31 10:52:22 -0600459 return VK_ERROR_INITIALIZATION_FAILED;
460 }
461 loader_set_dispatch(object, &dev->loader_dispatch);
462 return VK_SUCCESS;
463}
464
Lenny Komowf7c09382017-08-31 16:35:08 -0600465#if defined(_WIN32)
Norbert Garnys7dc9a592018-02-13 16:32:03 +0100466
467// Append the JSON path data to the list and allocate/grow the list if it's not large enough.
468// Function returns true if filename was appended to reg_data list.
469// Caller should free reg_data.
470static bool loaderAddJsonEntry(const struct loader_instance *inst,
471 char **reg_data, // list of JSON files
472 PDWORD total_size, // size of reg_data
473 LPCTSTR key_name, // key name - used for debug prints - i.e. VulkanDriverName
474 DWORD key_type, // key data type
475 LPSTR json_path, // JSON string to add to the list reg_data
476 DWORD json_size, // size in bytes of json_path
477 VkResult *result) {
478 if (NULL == *reg_data) {
479 *reg_data = loader_instance_heap_alloc(inst, *total_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
480 if (NULL == *reg_data) {
481 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
482 "loaderAddJsonEntry: Failed to allocate space for registry data for key %s", json_path);
483 *result = VK_ERROR_OUT_OF_HOST_MEMORY;
484 return false;
485 }
486 *reg_data[0] = '\0';
487 } else if (strlen(*reg_data) + json_size + 1 > *total_size) {
488 void *new_ptr =
489 loader_instance_heap_realloc(inst, *reg_data, *total_size, *total_size * 2, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
490 if (NULL == new_ptr) {
491 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
492 "loaderAddJsonEntry: Failed to reallocate space for registry value of size %d for key %s", *total_size * 2,
493 json_path);
494 *result = VK_ERROR_OUT_OF_HOST_MEMORY;
495 return false;
496 }
497 *reg_data = new_ptr;
498 *total_size *= 2;
499 }
500
501 for (char *curr_filename = json_path; curr_filename[0] != '\0'; curr_filename += strlen(curr_filename) + 1) {
502 if (strlen(*reg_data) == 0) {
503 (void)snprintf(*reg_data, json_size + 1, "%s", curr_filename);
504 } else {
505 (void)snprintf(*reg_data + strlen(*reg_data), json_size + 2, "%c%s", PATH_SEPARATOR, curr_filename);
506 }
507 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "%s: Located json file \"%s\" from PnP registry: %s", __FUNCTION__,
508 curr_filename, key_name);
509
510 if (key_type == REG_SZ) {
511 break;
512 }
513 }
514 return true;
515}
516
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200517// Find the list of registry files (names VulkanDriverName/VulkanDriverNameWow) in hkr.
518//
519// This function looks for filename in given device handle, filename is then added to return list
520// function return true if filename was appended to reg_data list
521// If error occures result is updated with failure reason
Lenny Komowf7c09382017-08-31 16:35:08 -0600522bool 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 +0200523{
524 HKEY hkrKey = INVALID_HANDLE_VALUE;
Lenny Komowf7c09382017-08-31 16:35:08 -0600525 DWORD requiredSize, data_type;
526 char *manifest_path = NULL;
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200527 bool found = false;
528
529 if (NULL == total_size || NULL == reg_data) {
530 *result = VK_ERROR_INITIALIZATION_FAILED;
531 return false;
532 }
533
Lenny Komowf7c09382017-08-31 16:35:08 -0600534 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 +0200535 if (status != CR_SUCCESS) {
536 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komowf7c09382017-08-31 16:35:08 -0600537 "loaderGetDeviceRegistryEntry: Failed to open registry key for DeviceID(%d)", dev_id);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200538 *result = VK_ERROR_INITIALIZATION_FAILED;
539 return false;
540 }
541
542 // query value
543 LSTATUS ret = RegQueryValueEx(
544 hkrKey,
Lenny Komowf7c09382017-08-31 16:35:08 -0600545 value_name,
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200546 NULL,
547 NULL,
548 NULL,
549 &requiredSize);
550
551 if (ret != ERROR_SUCCESS) {
Lenny Komowf7c09382017-08-31 16:35:08 -0600552 if (ret == ERROR_FILE_NOT_FOUND) {
553 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
554 "loaderGetDeviceRegistryEntry: Device ID(%d) Does not contain a value for \"%s\"", dev_id, value_name);
555 } else {
556 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
557 "loaderGetDeviceRegistryEntry: DeviceID(%d) Failed to obtain %s size", dev_id, value_name);
558 }
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200559 goto out;
560 }
561
Lenny Komowf7c09382017-08-31 16:35:08 -0600562 manifest_path = loader_instance_heap_alloc(inst, requiredSize, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
563 if (manifest_path == NULL) {
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200564 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
565 "loaderGetDeviceRegistryEntry: Failed to allocate space for DriverName.");
566 *result = VK_ERROR_OUT_OF_HOST_MEMORY;
567 goto out;
568 }
569
570 ret = RegQueryValueEx(
571 hkrKey,
Lenny Komowf7c09382017-08-31 16:35:08 -0600572 value_name,
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200573 NULL,
Lenny Komowf7c09382017-08-31 16:35:08 -0600574 &data_type,
Jamie Madilla11ae0b2017-11-08 14:48:32 -0500575 (BYTE *)manifest_path,
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200576 &requiredSize
577 );
578
579 if (ret != ERROR_SUCCESS) {
580 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Lenny Komowf7c09382017-08-31 16:35:08 -0600581 "loaderGetDeviceRegistryEntry: DeviceID(%d) Failed to obtain %s", value_name);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200582
583 *result = VK_ERROR_INITIALIZATION_FAILED;
584 goto out;
585 }
586
Lenny Komowf7c09382017-08-31 16:35:08 -0600587 if (data_type != REG_SZ && data_type != REG_MULTI_SZ) {
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200588 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Lenny Komowf7c09382017-08-31 16:35:08 -0600589 "loaderGetDeviceRegistryEntry: Invalid %s data type. Expected REG_SZ or REG_MULTI_SZ.", value_name);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200590 *result = VK_ERROR_INITIALIZATION_FAILED;
591 goto out;
592 }
593
Norbert Garnys7dc9a592018-02-13 16:32:03 +0100594 found = loaderAddJsonEntry(inst, reg_data, total_size, value_name, data_type, manifest_path, requiredSize, result);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200595
596out:
Lenny Komowf7c09382017-08-31 16:35:08 -0600597 if (manifest_path != NULL) {
598 loader_instance_heap_free(inst, manifest_path);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200599 }
600 RegCloseKey(hkrKey);
601 return found;
602}
603
604// Find the list of registry files (names VulkanDriverName/VulkanDriverNameWow) in hkr .
605//
606// This function looks for display devices and childish software components
607// for a list of files which are added to a returned list (function return
608// value).
609// Function return is a string with a ';' separated list of filenames.
610// Function return is NULL if no valid name/value pairs are found in the key,
611// or the key is not found.
612//
613// *reg_data contains a string list of filenames as pointer.
614// When done using the returned string list, the caller should free the pointer.
Lenny Komowf7c09382017-08-31 16:35:08 -0600615VkResult loaderGetDeviceRegistryFiles(const struct loader_instance *inst, char **reg_data, PDWORD reg_data_size, LPCTSTR value_name) {
Slawomir Cyganad34df22018-01-25 13:51:17 +0100616 static const wchar_t *softwareComponentGUID = L"{5c4c3332-344d-483c-8739-259e934c9cc8}";
617 static const wchar_t *displayGUID = L"{4d36e968-e325-11ce-bfc1-08002be10318}";
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200618 const ULONG flags = CM_GETIDLIST_FILTER_CLASS | CM_GETIDLIST_FILTER_PRESENT;
Slawomir Cyganad34df22018-01-25 13:51:17 +0100619
620 wchar_t childGuid[MAX_GUID_STRING_LEN + 2]; // +2 for brackets {}
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200621 ULONG childGuidSize = sizeof(childGuid);
622
623 DEVINST devID = 0, childID = 0;
Slawomir Cygana589d422018-01-25 13:48:54 +0100624 wchar_t *pDeviceNames = NULL;
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200625 ULONG deviceNamesSize = 0;
626 VkResult result = VK_SUCCESS;
627 bool found = false;
628
629 if (NULL == reg_data) {
630 result = VK_ERROR_INITIALIZATION_FAILED;
631 return result;
632 }
633
634 // if after obtaining the DeviceNameSize, new device is added start over
635 do {
Slawomir Cygana589d422018-01-25 13:48:54 +0100636 CM_Get_Device_ID_List_SizeW(&deviceNamesSize, displayGUID, flags);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200637
638 if (pDeviceNames != NULL) {
639 loader_instance_heap_free(inst, pDeviceNames);
640 }
641
Slawomir Cygana589d422018-01-25 13:48:54 +0100642 pDeviceNames = loader_instance_heap_alloc(inst, deviceNamesSize * sizeof(wchar_t), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200643 if (pDeviceNames == NULL) {
644 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
645 "loaderGetDeviceRegistryFiles: Failed to allocate space for display device names.");
646 result = VK_ERROR_OUT_OF_HOST_MEMORY;
Slawomir Cygan018bfd52017-08-25 10:54:03 +0200647 return result;
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200648 }
Slawomir Cygana589d422018-01-25 13:48:54 +0100649 } while (CM_Get_Device_ID_ListW(displayGUID, pDeviceNames, deviceNamesSize, flags) == CR_BUFFER_SMALL);
650
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200651 if (pDeviceNames) {
Slawomir Cygana589d422018-01-25 13:48:54 +0100652 for (wchar_t *deviceName = pDeviceNames; *deviceName; deviceName += wcslen(deviceName) + 1) {
653 CONFIGRET status = CM_Locate_DevNodeW(&devID, deviceName, CM_LOCATE_DEVNODE_NORMAL);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200654 if (CR_SUCCESS != status) {
Norbert Garnys7dc9a592018-02-13 16:32:03 +0100655 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, "loaderGetDeviceRegistryFiles: failed to open DevNode %s",
656 deviceName);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200657 continue;
658 }
659 ULONG ulStatus, ulProblem;
660 status = CM_Get_DevNode_Status(&ulStatus, &ulProblem, devID, 0);
661
662 if (CR_SUCCESS != status)
663 {
Norbert Garnys7dc9a592018-02-13 16:32:03 +0100664 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, "loaderGetDeviceRegistryFiles: failed to probe device status %s",
665 deviceName);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200666 continue;
667 }
668 if ((ulStatus & DN_HAS_PROBLEM) && (ulProblem == CM_PROB_NEED_RESTART || ulProblem == DN_NEED_RESTART))
669 {
Lenny Komowe17a12a2017-08-10 09:25:49 -0600670 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Norbert Garnys7dc9a592018-02-13 16:32:03 +0100671 "loaderGetDeviceRegistryFiles: device %s is pending reboot, skipping ...", deviceName);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200672 continue;
673 }
674
Norbert Garnys7dc9a592018-02-13 16:32:03 +0100675 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "loaderGetDeviceRegistryFiles: opening device %s", deviceName);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200676
Lenny Komowf7c09382017-08-31 16:35:08 -0600677 if (loaderGetDeviceRegistryEntry(inst, reg_data, reg_data_size, devID, value_name, &result)) {
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200678 found = true;
679 continue;
680 }
Igor Ostrowski21532732017-10-06 18:26:23 +0200681 else if (result == VK_ERROR_OUT_OF_HOST_MEMORY) {
682 break;
683 }
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200684
685 status = CM_Get_Child(&childID, devID, 0);
686 if (status != CR_SUCCESS) {
Lenny Komowe17a12a2017-08-10 09:25:49 -0600687 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Norbert Garnys7dc9a592018-02-13 16:32:03 +0100688 "loaderGetDeviceRegistryFiles: unable to open child-device error:%d", status);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200689 continue;
690 }
691
692 do {
Slawomir Cygana589d422018-01-25 13:48:54 +0100693 wchar_t buffer[MAX_DEVICE_ID_LEN];
694 CM_Get_Device_IDW(childID, buffer, MAX_DEVICE_ID_LEN, 0);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200695
Lenny Komowe17a12a2017-08-10 09:25:49 -0600696 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Norbert Garnys7dc9a592018-02-13 16:32:03 +0100697 "loaderGetDeviceRegistryFiles: Opening child device %d - %s", childID, buffer);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200698
Slawomir Cygana589d422018-01-25 13:48:54 +0100699 status = CM_Get_DevNode_Registry_PropertyW(childID, CM_DRP_CLASSGUID, NULL, &childGuid, &childGuidSize, 0);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200700 if (status != CR_SUCCESS) {
701 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Norbert Garnys7dc9a592018-02-13 16:32:03 +0100702 "loaderGetDeviceRegistryFiles: unable to obtain GUID for:%d error:%d", childID, status);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200703
704 result = VK_ERROR_INITIALIZATION_FAILED;
705 continue;
706 }
707
Slawomir Cygana589d422018-01-25 13:48:54 +0100708 if (wcscmp(childGuid, softwareComponentGUID) != 0) {
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200709 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
Norbert Garnys7dc9a592018-02-13 16:32:03 +0100710 "loaderGetDeviceRegistryFiles: GUID for %d is not SoftwareComponent skipping", childID);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200711 continue;
712 }
713
Lenny Komowf7c09382017-08-31 16:35:08 -0600714 if (loaderGetDeviceRegistryEntry(inst, reg_data, reg_data_size, childID, value_name, &result)) {
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200715 found = true;
716 break; // check next-display-device
717 }
718
719 } while (CM_Get_Sibling(&childID, childID, 0) == CR_SUCCESS);
720 }
721
722 loader_instance_heap_free(inst, pDeviceNames);
723 }
724
725 if (!found && result != VK_ERROR_OUT_OF_HOST_MEMORY) {
726 result = VK_ERROR_INITIALIZATION_FAILED;
727 }
728
729 return result;
730}
731
Tony Barbourea968902015-07-29 14:26:21 -0600732static char *loader_get_next_path(char *path);
Mark Young2c84c0c2017-01-13 10:27:03 -0700733
734// Find the list of registry files (names within a key) in key "location".
735//
736// This function looks in the registry (hive = DEFAULT_VK_REGISTRY_HIVE) key as
737// given in "location"
738// for a list or name/values which are added to a returned list (function return
739// value).
740// The DWORD values within the key must be 0 or they are skipped.
741// Function return is a string with a ';' separated list of filenames.
742// Function return is NULL if no valid name/value pairs are found in the key,
743// or the key is not found.
744//
745// *reg_data contains a string list of filenames as pointer.
746// When done using the returned string list, the caller should free the pointer.
Slawomir Cygan8f9f2552017-08-09 11:36:52 +0200747VkResult 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 -0700748 LONG rtn_value;
Lenny Komowda849dc2017-03-01 17:22:29 -0700749 HKEY hive = DEFAULT_VK_REGISTRY_HIVE, key;
Piers Daniell524ec732015-11-05 16:58:26 -0700750 DWORD access_flags;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700751 char name[2048];
Tony Barbourea968902015-07-29 14:26:21 -0600752 char *loc = location;
753 char *next;
Lenny Komowda849dc2017-03-01 17:22:29 -0700754 DWORD idx;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700755 DWORD name_size = sizeof(name);
756 DWORD value;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700757 DWORD value_size = sizeof(value);
Mark Young2c84c0c2017-01-13 10:27:03 -0700758 VkResult result = VK_SUCCESS;
759 bool found = false;
760
761 if (NULL == reg_data) {
762 result = VK_ERROR_INITIALIZATION_FAILED;
763 goto out;
764 }
Tony Barbourea968902015-07-29 14:26:21 -0600765
Jon Ashburn23d36b12016-02-02 17:47:28 -0700766 while (*loc) {
Tony Barbourea968902015-07-29 14:26:21 -0600767 next = loader_get_next_path(loc);
Piers Daniell524ec732015-11-05 16:58:26 -0700768 access_flags = KEY_QUERY_VALUE;
Tony Barbourea968902015-07-29 14:26:21 -0600769 rtn_value = RegOpenKeyEx(hive, loc, 0, access_flags, &key);
Lenny Komowda849dc2017-03-01 17:22:29 -0700770 if (ERROR_SUCCESS == rtn_value) {
771 idx = 0;
772 while ((rtn_value = RegEnumValue(key, idx++, name, &name_size, NULL, NULL, (LPBYTE)&value, &value_size)) ==
773 ERROR_SUCCESS) {
774 if (value_size == sizeof(value) && value == 0) {
775 if (NULL == *reg_data) {
Slawomir Cygan8f9f2552017-08-09 11:36:52 +0200776 *reg_data = loader_instance_heap_alloc(inst, *reg_data_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Lenny Komowda849dc2017-03-01 17:22:29 -0700777 if (NULL == *reg_data) {
778 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngbb3a29c2017-05-19 12:29:43 -0600779 "loaderGetRegistryFiles: Failed to allocate space for registry data for key %s", name);
Slawomir Cygane5830322018-01-16 17:17:07 +0100780 RegCloseKey(key);
Lenny Komowda849dc2017-03-01 17:22:29 -0700781 result = VK_ERROR_OUT_OF_HOST_MEMORY;
782 goto out;
783 }
784 *reg_data[0] = '\0';
Slawomir Cygan8f9f2552017-08-09 11:36:52 +0200785 } else if (strlen(*reg_data) + name_size + 1 > *reg_data_size) {
786 void *new_ptr = loader_instance_heap_realloc(inst, *reg_data, *reg_data_size, *reg_data_size * 2,
Mark Youngbb3a29c2017-05-19 12:29:43 -0600787 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
788 if (NULL == new_ptr) {
789 loader_log(
790 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
791 "loaderGetRegistryFiles: Failed to reallocate space for registry value of size %d for key %s",
Slawomir Cygan8f9f2552017-08-09 11:36:52 +0200792 *reg_data_size * 2, name);
Slawomir Cygane5830322018-01-16 17:17:07 +0100793 RegCloseKey(key);
Lenny Komowda849dc2017-03-01 17:22:29 -0700794 result = VK_ERROR_OUT_OF_HOST_MEMORY;
795 goto out;
796 }
Mark Youngbb3a29c2017-05-19 12:29:43 -0600797 *reg_data = new_ptr;
Slawomir Cygan8f9f2552017-08-09 11:36:52 +0200798 *reg_data_size *= 2;
Lenny Komowda849dc2017-03-01 17:22:29 -0700799 }
Mark Youngf2079b92017-05-02 10:49:46 -0600800 loader_log(
801 inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Located json file \"%s\" from registry \"%s\\%s\"", name,
802 hive == DEFAULT_VK_REGISTRY_HIVE ? DEFAULT_VK_REGISTRY_HIVE_STR : SECONDARY_VK_REGISTRY_HIVE_STR, location);
Lenny Komowda849dc2017-03-01 17:22:29 -0700803 if (strlen(*reg_data) == 0) {
Norbert Garnys7dc9a592018-02-13 16:32:03 +0100804 // The list is emtpy. Add the first entry.
Lenny Komowda849dc2017-03-01 17:22:29 -0700805 (void)snprintf(*reg_data, name_size + 1, "%s", name);
Norbert Garnys7dc9a592018-02-13 16:32:03 +0100806 found = true;
Lenny Komowda849dc2017-03-01 17:22:29 -0700807 } else {
Norbert Garnys7dc9a592018-02-13 16:32:03 +0100808 // At this point the reg_data variable contains other JSON paths, likely from the PNP/device section
809 // of the registry that we want to have precendence over this non-device specific section of the registry.
810 // To make sure we avoid enumerating old JSON files/drivers that might be present in the non-device specific
811 // area of the registry when a newer device specific JSON file is present, do a check before adding.
812 // Find the file name, without path, of the JSON file found in the non-device specific registry location.
813 // If the same JSON file name is already found in the list, don't add it again.
814 bool foundDuplicate = false;
815 char *pLastSlashName = strrchr(name, '\\');
816 if (pLastSlashName != NULL) {
817 char *foundMatch = strstr(*reg_data, pLastSlashName + 1);
818 if (foundMatch != NULL) {
819 foundDuplicate = true;
820 }
821 }
822
823 if (foundDuplicate == false) {
824 // Add the new entry to the list.
825 (void)snprintf(*reg_data + strlen(*reg_data), name_size + 2, "%c%s", PATH_SEPARATOR, name);
826 found = true;
827 } else {
828 loader_log(
829 inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
830 "Skipping adding of json file \"%s\" from registry \"%s\\%s\" to the list due to duplication", name,
831 hive == DEFAULT_VK_REGISTRY_HIVE ? DEFAULT_VK_REGISTRY_HIVE_STR : SECONDARY_VK_REGISTRY_HIVE_STR,
832 location);
833 }
Lenny Komowda849dc2017-03-01 17:22:29 -0700834 }
Lenny Komowda849dc2017-03-01 17:22:29 -0700835 }
836 name_size = 2048;
837 }
Slawomir Cygane5830322018-01-16 17:17:07 +0100838 RegCloseKey(key);
Jon Ashburnffad94d2015-06-30 14:46:22 -0700839 }
Tony Barbourea968902015-07-29 14:26:21 -0600840
Lenny Komowda849dc2017-03-01 17:22:29 -0700841 // Advance the location - if the next location is in the secondary hive, then reset the locations and advance the hive
842 if (use_secondary_hive && (hive == DEFAULT_VK_REGISTRY_HIVE) && (*next == '\0')) {
843 loc = location;
844 hive = SECONDARY_VK_REGISTRY_HIVE;
845 } else {
846 loc = next;
Tony Barbourea968902015-07-29 14:26:21 -0600847 }
Jon Ashburnffad94d2015-06-30 14:46:22 -0700848 }
Tony Barbourea968902015-07-29 14:26:21 -0600849
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200850 if (!found && result != VK_ERROR_OUT_OF_HOST_MEMORY) {
Mark Young2c84c0c2017-01-13 10:27:03 -0700851 result = VK_ERROR_INITIALIZATION_FAILED;
852 }
853
854out:
855
856 return result;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700857}
858
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700859#endif // WIN32
Ian Elliott4470a302015-02-17 10:33:47 -0700860
Mark Young0f183a82017-02-28 09:58:04 -0700861// Combine path elements, separating each element with the platform-specific
862// directory separator, and save the combined string to a destination buffer,
Mark Youngdee312c2017-03-08 13:38:35 -0700863// not exceeding the given length. Path elements are given as variable args,
Mark Young0f183a82017-02-28 09:58:04 -0700864// with a NULL element terminating the list.
865//
866// \returns the total length of the combined string, not including an ASCII
867// NUL termination character. This length may exceed the available storage:
868// in this case, the written string will be truncated to avoid a buffer
869// overrun, and the return value will greater than or equal to the storage
870// size. A NULL argument may be provided as the destination buffer in order
871// to determine the required string length without actually writing a string.
Jon Ashburn23d36b12016-02-02 17:47:28 -0700872static size_t loader_platform_combine_path(char *dest, size_t len, ...) {
Courtney Goeltzenleuchter0ef13a02015-12-16 16:19:46 -0700873 size_t required_len = 0;
Daniel Dadap00b4aba2015-09-30 11:50:51 -0500874 va_list ap;
875 const char *component;
876
877 va_start(ap, len);
878
Jon Ashburn23d36b12016-02-02 17:47:28 -0700879 while ((component = va_arg(ap, const char *))) {
Daniel Dadap00b4aba2015-09-30 11:50:51 -0500880 if (required_len > 0) {
881 // This path element is not the first non-empty element; prepend
882 // a directory separator if space allows
883 if (dest && required_len + 1 < len) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700884 (void)snprintf(dest + required_len, len - required_len, "%c", DIRECTORY_SYMBOL);
Daniel Dadap00b4aba2015-09-30 11:50:51 -0500885 }
886 required_len++;
887 }
888
889 if (dest && required_len < len) {
890 strncpy(dest + required_len, component, len - required_len);
891 }
892 required_len += strlen(component);
893 }
894
895 va_end(ap);
896
897 // strncpy(3) won't add a NUL terminating byte in the event of truncation.
898 if (dest && required_len >= len) {
899 dest[len - 1] = '\0';
900 }
901
902 return required_len;
903}
904
Mark Young0f183a82017-02-28 09:58:04 -0700905// Given string of three part form "maj.min.pat" convert to a vulkan version number.
Mark Young60861ac2016-09-02 11:39:26 -0600906static uint32_t loader_make_version(char *vers_str) {
Jon Ashburn23d36b12016-02-02 17:47:28 -0700907 uint32_t vers = 0, major = 0, minor = 0, patch = 0;
Mark Young60861ac2016-09-02 11:39:26 -0600908 char *vers_tok;
Jon Ashburnc7237a72015-08-03 09:08:46 -0600909
Mark Young60861ac2016-09-02 11:39:26 -0600910 if (!vers_str) {
Jon Ashburnc7237a72015-08-03 09:08:46 -0600911 return vers;
Jon Ashburnc7237a72015-08-03 09:08:46 -0600912 }
Mark Young60861ac2016-09-02 11:39:26 -0600913
914 vers_tok = strtok(vers_str, ".\"\n\r");
915 if (NULL != vers_tok) {
916 major = (uint16_t)atoi(vers_tok);
917 vers_tok = strtok(NULL, ".\"\n\r");
918 if (NULL != vers_tok) {
919 minor = (uint16_t)atoi(vers_tok);
920 vers_tok = strtok(NULL, ".\"\n\r");
921 if (NULL != vers_tok) {
922 patch = (uint16_t)atoi(vers_tok);
923 }
924 }
925 }
Jon Ashburnc7237a72015-08-03 09:08:46 -0600926
927 return VK_MAKE_VERSION(major, minor, patch);
Jon Ashburnc7237a72015-08-03 09:08:46 -0600928}
929
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700930bool compare_vk_extension_properties(const VkExtensionProperties *op1, const VkExtensionProperties *op2) {
Chia-I Wu3432a0c2015-10-27 18:04:07 +0800931 return strcmp(op1->extensionName, op2->extensionName) == 0 ? true : false;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600932}
933
Mark Young0f183a82017-02-28 09:58:04 -0700934// Search the given ext_array for an extension matching the given vk_ext_prop
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700935bool has_vk_extension_property_array(const VkExtensionProperties *vk_ext_prop, const uint32_t count,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700936 const VkExtensionProperties *ext_array) {
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600937 for (uint32_t i = 0; i < count; i++) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700938 if (compare_vk_extension_properties(vk_ext_prop, &ext_array[i])) return true;
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600939 }
940 return false;
941}
942
Mark Young0f183a82017-02-28 09:58:04 -0700943// Search the given ext_list for an extension matching the given vk_ext_prop
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700944bool has_vk_extension_property(const VkExtensionProperties *vk_ext_prop, const struct loader_extension_list *ext_list) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600945 for (uint32_t i = 0; i < ext_list->count; i++) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700946 if (compare_vk_extension_properties(&ext_list->list[i], vk_ext_prop)) return true;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600947 }
948 return false;
949}
950
Mark Young0f183a82017-02-28 09:58:04 -0700951// Search the given ext_list for a device extension matching the given ext_prop
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700952bool has_vk_dev_ext_property(const VkExtensionProperties *ext_prop, const struct loader_device_extension_list *ext_list) {
Jon Ashburnb8726962016-04-08 15:03:35 -0600953 for (uint32_t i = 0; i < ext_list->count; i++) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700954 if (compare_vk_extension_properties(&ext_list->list[i].props, ext_prop)) return true;
Jon Ashburnb8726962016-04-08 15:03:35 -0600955 }
956 return false;
957}
958
Mark Young0f183a82017-02-28 09:58:04 -0700959// Search the given layer list for a layer matching the given layer name
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700960static 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 -0600961 for (uint32_t i = 0; i < layer_list->count; i++) {
962 const VkLayerProperties *item = &layer_list->list[i].info;
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700963 if (strcmp(name, item->layerName) == 0) return &layer_list->list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600964 }
965 return NULL;
966}
967
Mark Young0f183a82017-02-28 09:58:04 -0700968// Get the next unused layer property in the list. Init the property to zero.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700969static struct loader_layer_properties *loader_get_next_layer_property(const struct loader_instance *inst,
970 struct loader_layer_list *layer_list) {
Jon Ashburne13ecc92015-08-03 17:19:30 -0600971 if (layer_list->capacity == 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700972 layer_list->list =
973 loader_instance_heap_alloc(inst, sizeof(struct loader_layer_properties) * 64, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburne13ecc92015-08-03 17:19:30 -0600974 if (layer_list->list == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700975 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
976 "loader_get_next_layer_property: Out of memory can "
977 "not add any layer properties to list");
Jon Ashburne13ecc92015-08-03 17:19:30 -0600978 return NULL;
979 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700980 memset(layer_list->list, 0, sizeof(struct loader_layer_properties) * 64);
Jon Ashburne13ecc92015-08-03 17:19:30 -0600981 layer_list->capacity = sizeof(struct loader_layer_properties) * 64;
982 }
983
Mark Young0f183a82017-02-28 09:58:04 -0700984 // Ensure enough room to add an entry
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700985 if ((layer_list->count + 1) * sizeof(struct loader_layer_properties) > layer_list->capacity) {
Mark Youngbb3a29c2017-05-19 12:29:43 -0600986 void *new_ptr = loader_instance_heap_realloc(inst, layer_list->list, layer_list->capacity, layer_list->capacity * 2,
987 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
988 if (NULL == new_ptr) {
989 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 -0600990 return NULL;
Jon Ashburne13ecc92015-08-03 17:19:30 -0600991 }
Mark Youngbb3a29c2017-05-19 12:29:43 -0600992 layer_list->list = new_ptr;
Jon Ashburne13ecc92015-08-03 17:19:30 -0600993 layer_list->capacity *= 2;
994 }
995
996 layer_list->count++;
997 return &(layer_list->list[layer_list->count - 1]);
998}
999
Mark Youngdee312c2017-03-08 13:38:35 -07001000// Remove all layer properties entries from the list
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001001void loader_delete_layer_properties(const struct loader_instance *inst, struct loader_layer_list *layer_list) {
Cort Stratton6974a132017-11-28 12:11:05 -08001002 uint32_t i, j, k;
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001003 struct loader_device_extension_list *dev_ext_list;
Cort Stratton6974a132017-11-28 12:11:05 -08001004 struct loader_dev_ext_props *ext_props;
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001005 if (!layer_list) return;
Jon Ashburnb82c1852015-08-11 14:49:54 -06001006
Jon Ashburne13ecc92015-08-03 17:19:30 -06001007 for (i = 0; i < layer_list->count; i++) {
Mark Youngf2079b92017-05-02 10:49:46 -06001008 if (NULL != layer_list->list[i].component_layer_names) {
1009 loader_instance_heap_free(inst, layer_list->list[i].component_layer_names);
1010 layer_list->list[i].component_layer_names = NULL;
1011 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001012 loader_destroy_generic_list(inst, (struct loader_generic_list *)&layer_list->list[i].instance_extension_list);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001013 dev_ext_list = &layer_list->list[i].device_extension_list;
Cort Stratton6974a132017-11-28 12:11:05 -08001014 if (dev_ext_list->capacity > 0 && NULL != dev_ext_list->list) {
1015 for (j = 0; j < dev_ext_list->count; j++) {
1016 ext_props = &dev_ext_list->list[j];
1017 if (ext_props->entrypoint_count > 0) {
1018 for (k = 0; k < ext_props->entrypoint_count; k++) {
1019 loader_instance_heap_free(inst, ext_props->entrypoints[k]);
1020 }
1021 loader_instance_heap_free(inst, ext_props->entrypoints);
1022 }
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001023 }
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001024 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001025 loader_destroy_generic_list(inst, (struct loader_generic_list *)dev_ext_list);
Jon Ashburne13ecc92015-08-03 17:19:30 -06001026 }
1027 layer_list->count = 0;
1028
Jon Ashburnb82c1852015-08-11 14:49:54 -06001029 if (layer_list->capacity > 0) {
1030 layer_list->capacity = 0;
Mark Young0ad83132016-06-30 13:02:42 -06001031 loader_instance_heap_free(inst, layer_list->list);
Jon Ashburnb82c1852015-08-11 14:49:54 -06001032 }
Jon Ashburne13ecc92015-08-03 17:19:30 -06001033}
1034
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001035static VkResult loader_add_instance_extensions(const struct loader_instance *inst,
1036 const PFN_vkEnumerateInstanceExtensionProperties fp_get_props, const char *lib_name,
1037 struct loader_extension_list *ext_list) {
Courtney Goeltzenleuchter36eeb742015-12-21 16:41:47 -07001038 uint32_t i, count = 0;
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001039 VkExtensionProperties *ext_props;
Mark Young3a587792016-08-19 15:25:08 -06001040 VkResult res = VK_SUCCESS;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001041
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -06001042 if (!fp_get_props) {
Mark Young0f183a82017-02-28 09:58:04 -07001043 // No EnumerateInstanceExtensionProperties defined
Mark Young3a587792016-08-19 15:25:08 -06001044 goto out;
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -06001045 }
1046
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001047 res = fp_get_props(NULL, &count, NULL);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001048 if (res != VK_SUCCESS) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001049 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1050 "loader_add_instance_extensions: Error getting Instance "
1051 "extension count from %s",
Mark Youngb6399312017-01-10 14:22:15 -07001052 lib_name);
Mark Young3a587792016-08-19 15:25:08 -06001053 goto out;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001054 }
Jon Ashburn953bb3c2015-06-10 16:11:42 -06001055
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -06001056 if (count == 0) {
Mark Young0f183a82017-02-28 09:58:04 -07001057 // No ExtensionProperties to report
Mark Young3a587792016-08-19 15:25:08 -06001058 goto out;
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -06001059 }
1060
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001061 ext_props = loader_stack_alloc(count * sizeof(VkExtensionProperties));
Mark Young39389872017-01-19 21:10:49 -07001062 if (NULL == ext_props) {
1063 res = VK_ERROR_OUT_OF_HOST_MEMORY;
1064 goto out;
1065 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001066
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001067 res = fp_get_props(NULL, &count, ext_props);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001068 if (res != VK_SUCCESS) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001069 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1070 "loader_add_instance_extensions: Error getting Instance "
1071 "extensions from %s",
Mark Youngb6399312017-01-10 14:22:15 -07001072 lib_name);
Mark Young3a587792016-08-19 15:25:08 -06001073 goto out;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001074 }
Tony Barbour59a47322015-06-24 16:06:58 -06001075
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001076 for (i = 0; i < count; i++) {
Courtney Goeltzenleuchter53043732015-07-12 13:20:05 -06001077 char spec_version[64];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001078
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001079 bool ext_unsupported = wsi_unsupported_instance_extension(&ext_props[i]);
Jon Ashburn6fa520f2016-03-25 12:49:35 -06001080 if (!ext_unsupported) {
Mark Young02df1a82017-04-18 19:52:18 -06001081 (void)snprintf(spec_version, sizeof(spec_version), "%d.%d.%d", VK_VERSION_MAJOR(ext_props[i].specVersion),
1082 VK_VERSION_MINOR(ext_props[i].specVersion), VK_VERSION_PATCH(ext_props[i].specVersion));
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001083 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Instance Extension: %s (%s) version %s", ext_props[i].extensionName,
1084 lib_name, spec_version);
Mark Young6267ae62017-01-12 12:27:19 -07001085
Mark Young3a587792016-08-19 15:25:08 -06001086 res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
1087 if (res != VK_SUCCESS) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001088 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1089 "loader_add_instance_extensions: Failed to add %s "
1090 "to Instance extension list",
Mark Young3a587792016-08-19 15:25:08 -06001091 lib_name);
1092 goto out;
1093 }
Jon Ashburn6fa520f2016-03-25 12:49:35 -06001094 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001095 }
Mark Young6267ae62017-01-12 12:27:19 -07001096
Mark Young3a587792016-08-19 15:25:08 -06001097out:
1098 return res;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001099}
1100
Mark Young0f183a82017-02-28 09:58:04 -07001101// Initialize ext_list with the physical device extensions.
1102// The extension properties are passed as inputs in count and ext_props.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001103static VkResult loader_init_device_extensions(const struct loader_instance *inst, struct loader_physical_device_term *phys_dev_term,
1104 uint32_t count, VkExtensionProperties *ext_props,
1105 struct loader_extension_list *ext_list) {
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001106 VkResult res;
1107 uint32_t i;
1108
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001109 res = loader_init_generic_list(inst, (struct loader_generic_list *)ext_list, sizeof(VkExtensionProperties));
Mark Young3a587792016-08-19 15:25:08 -06001110 if (VK_SUCCESS != res) {
1111 return res;
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001112 }
1113
1114 for (i = 0; i < count; i++) {
1115 char spec_version[64];
Mark Young02df1a82017-04-18 19:52:18 -06001116 (void)snprintf(spec_version, sizeof(spec_version), "%d.%d.%d", VK_VERSION_MAJOR(ext_props[i].specVersion),
1117 VK_VERSION_MINOR(ext_props[i].specVersion), VK_VERSION_PATCH(ext_props[i].specVersion));
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001118 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Device Extension: %s (%s) version %s", ext_props[i].extensionName,
1119 phys_dev_term->this_icd_term->scanned_icd->lib_name, spec_version);
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001120 res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001121 if (res != VK_SUCCESS) return res;
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001122 }
1123
1124 return VK_SUCCESS;
1125}
1126
Jon Ashburn1530c342016-02-26 13:14:27 -07001127VkResult loader_add_device_extensions(const struct loader_instance *inst,
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001128 PFN_vkEnumerateDeviceExtensionProperties fpEnumerateDeviceExtensionProperties,
1129 VkPhysicalDevice physical_device, const char *lib_name,
Jon Ashburn1530c342016-02-26 13:14:27 -07001130 struct loader_extension_list *ext_list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001131 uint32_t i, count;
1132 VkResult res;
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001133 VkExtensionProperties *ext_props;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001134
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001135 res = fpEnumerateDeviceExtensionProperties(physical_device, NULL, &count, NULL);
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001136 if (res == VK_SUCCESS && count > 0) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001137 ext_props = loader_stack_alloc(count * sizeof(VkExtensionProperties));
Mark Young9a3ddd42016-10-21 16:25:47 -06001138 if (!ext_props) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001139 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1140 "loader_add_device_extensions: Failed to allocate space"
1141 " for device extension properties.");
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001142 return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young9a3ddd42016-10-21 16:25:47 -06001143 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001144 res = fpEnumerateDeviceExtensionProperties(physical_device, NULL, &count, ext_props);
Mark Young9a3ddd42016-10-21 16:25:47 -06001145 if (res != VK_SUCCESS) {
Jon Ashburn24cd4be2015-11-01 14:04:06 -07001146 return res;
Mark Young9a3ddd42016-10-21 16:25:47 -06001147 }
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001148 for (i = 0; i < count; i++) {
1149 char spec_version[64];
Mark Young02df1a82017-04-18 19:52:18 -06001150 (void)snprintf(spec_version, sizeof(spec_version), "%d.%d.%d", VK_VERSION_MAJOR(ext_props[i].specVersion),
1151 VK_VERSION_MINOR(ext_props[i].specVersion), VK_VERSION_PATCH(ext_props[i].specVersion));
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001152 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Device Extension: %s (%s) version %s", ext_props[i].extensionName,
1153 lib_name, spec_version);
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001154 res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
Mark Youngb6399312017-01-10 14:22:15 -07001155 if (res != VK_SUCCESS) {
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001156 return res;
Mark Youngb6399312017-01-10 14:22:15 -07001157 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001158 }
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001159 } else {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001160 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1161 "loader_add_device_extensions: Error getting physical "
1162 "device extension info count from library %s",
Jon Ashburn23d36b12016-02-02 17:47:28 -07001163 lib_name);
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001164 return res;
1165 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001166
Jon Ashburn24cd4be2015-11-01 14:04:06 -07001167 return VK_SUCCESS;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001168}
1169
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001170VkResult 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 -06001171 size_t capacity = 32 * element_size;
1172 list_info->count = 0;
1173 list_info->capacity = 0;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001174 list_info->list = loader_instance_heap_alloc(inst, capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburn6e6a2162015-12-10 08:51:10 -07001175 if (list_info->list == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001176 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1177 "loader_init_generic_list: Failed to allocate space "
1178 "for generic list");
Mark Young3a587792016-08-19 15:25:08 -06001179 return VK_ERROR_OUT_OF_HOST_MEMORY;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001180 }
Mark Young84ba0482016-09-02 11:45:00 -06001181 memset(list_info->list, 0, capacity);
1182 list_info->capacity = capacity;
Mark Young3a587792016-08-19 15:25:08 -06001183 return VK_SUCCESS;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001184}
1185
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001186void loader_destroy_generic_list(const struct loader_instance *inst, struct loader_generic_list *list) {
Mark Young0ad83132016-06-30 13:02:42 -06001187 loader_instance_heap_free(inst, list->list);
Jon Ashburn6e6a2162015-12-10 08:51:10 -07001188 list->count = 0;
1189 list->capacity = 0;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001190}
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001191
Mark Young0f183a82017-02-28 09:58:04 -07001192// Append non-duplicate extension properties defined in props to the given ext_list.
1193// Return - Vk_SUCCESS on success
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001194VkResult loader_add_to_ext_list(const struct loader_instance *inst, struct loader_extension_list *ext_list,
1195 uint32_t prop_list_count, const VkExtensionProperties *props) {
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001196 uint32_t i;
1197 const VkExtensionProperties *cur_ext;
1198
1199 if (ext_list->list == NULL || ext_list->capacity == 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001200 VkResult res = loader_init_generic_list(inst, (struct loader_generic_list *)ext_list, sizeof(VkExtensionProperties));
Mark Young3a587792016-08-19 15:25:08 -06001201 if (VK_SUCCESS != res) {
1202 return res;
1203 }
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001204 }
1205
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001206 for (i = 0; i < prop_list_count; i++) {
1207 cur_ext = &props[i];
1208
1209 // look for duplicates
1210 if (has_vk_extension_property(cur_ext, ext_list)) {
1211 continue;
1212 }
1213
1214 // add to list at end
1215 // check for enough capacity
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001216 if (ext_list->count * sizeof(VkExtensionProperties) >= 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);
1219 if (new_ptr == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001220 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1221 "loader_add_to_ext_list: Failed to reallocate "
1222 "space for extension list");
Jon Ashburn24cd4be2015-11-01 14:04:06 -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 Ashburn24cd4be2015-11-01 14:04:06 -07001226
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001227 // double capacity
1228 ext_list->capacity *= 2;
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001229 }
1230
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001231 memcpy(&ext_list->list[ext_list->count], cur_ext, sizeof(VkExtensionProperties));
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001232 ext_list->count++;
1233 }
Jon Ashburn24cd4be2015-11-01 14:04:06 -07001234 return VK_SUCCESS;
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001235}
1236
Mark Youngdee312c2017-03-08 13:38:35 -07001237// Append one extension property defined in props with entrypoints defined in entries to the given
Mark Young0f183a82017-02-28 09:58:04 -07001238// ext_list. Do not append if a duplicate.
1239// Return - Vk_SUCCESS on success
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001240VkResult loader_add_to_dev_ext_list(const struct loader_instance *inst, struct loader_device_extension_list *ext_list,
1241 const VkExtensionProperties *props, uint32_t entry_count, char **entrys) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001242 uint32_t idx;
1243 if (ext_list->list == NULL || ext_list->capacity == 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001244 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 -06001245 if (VK_SUCCESS != res) {
1246 return res;
1247 }
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001248 }
1249
Jon Ashburnb8726962016-04-08 15:03:35 -06001250 // look for duplicates
1251 if (has_vk_dev_ext_property(props, ext_list)) {
1252 return VK_SUCCESS;
1253 }
1254
Jon Ashburn23d36b12016-02-02 17:47:28 -07001255 idx = ext_list->count;
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001256 // add to list at end
1257 // check for enough capacity
Jon Ashburn23d36b12016-02-02 17:47:28 -07001258 if (idx * sizeof(struct loader_dev_ext_props) >= ext_list->capacity) {
Mark Youngbb3a29c2017-05-19 12:29:43 -06001259 void *new_ptr = loader_instance_heap_realloc(inst, ext_list->list, ext_list->capacity, ext_list->capacity * 2,
1260 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001261
Mark Youngbb3a29c2017-05-19 12:29:43 -06001262 if (NULL == new_ptr) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001263 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngbb3a29c2017-05-19 12:29:43 -06001264 "loader_add_to_dev_ext_list: Failed to reallocate space for device extension list");
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001265 return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Youngb6399312017-01-10 14:22:15 -07001266 }
Mark Youngbb3a29c2017-05-19 12:29:43 -06001267 ext_list->list = new_ptr;
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001268
1269 // double capacity
1270 ext_list->capacity *= 2;
1271 }
1272
Gabríel Arthúr Pétursson71510142017-06-03 01:38:49 +00001273 memcpy(&ext_list->list[idx].props, props, sizeof(*props));
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001274 ext_list->list[idx].entrypoint_count = entry_count;
Mark Young3f7a3b32017-06-26 14:03:08 -06001275 if (entry_count == 0) {
1276 ext_list->list[idx].entrypoints = NULL;
1277 } else {
1278 ext_list->list[idx].entrypoints =
1279 loader_instance_heap_alloc(inst, sizeof(char *) * entry_count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1280 if (ext_list->list[idx].entrypoints == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001281 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1282 "loader_add_to_dev_ext_list: Failed to allocate space "
Mark Young3f7a3b32017-06-26 14:03:08 -06001283 "for device extension entrypoint list in list %d",
1284 idx);
1285 ext_list->list[idx].entrypoint_count = 0;
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001286 return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young0ad83132016-06-30 13:02:42 -06001287 }
Mark Young3f7a3b32017-06-26 14:03:08 -06001288 for (uint32_t i = 0; i < entry_count; i++) {
1289 ext_list->list[idx].entrypoints[i] =
1290 loader_instance_heap_alloc(inst, strlen(entrys[i]) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1291 if (ext_list->list[idx].entrypoints[i] == NULL) {
1292 for (uint32_t j = 0; j < i; j++) {
1293 loader_instance_heap_free(inst, ext_list->list[idx].entrypoints[j]);
1294 }
1295 loader_instance_heap_free(inst, ext_list->list[idx].entrypoints);
1296 ext_list->list[idx].entrypoint_count = 0;
1297 ext_list->list[idx].entrypoints = NULL;
1298 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1299 "loader_add_to_dev_ext_list: Failed to allocate space "
1300 "for device extension entrypoint %d name",
1301 i);
1302 return VK_ERROR_OUT_OF_HOST_MEMORY;
1303 }
1304 strcpy(ext_list->list[idx].entrypoints[i], entrys[i]);
1305 }
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001306 }
1307 ext_list->count++;
1308
1309 return VK_SUCCESS;
1310}
1311
Mark Youngf2079b92017-05-02 10:49:46 -06001312// Prototype of loader_add_meta_layer function since we use it in the loader_add_implicit_layer, but can also
1313// call loader_add_implicit_layer from loader_add_meta_layer.
1314bool loader_add_meta_layer(const struct loader_instance *inst, const struct loader_layer_properties *prop,
Mark Young283fe1c2017-05-04 12:16:35 -06001315 struct loader_layer_list *target_list, struct loader_layer_list *expanded_target_list,
1316 const struct loader_layer_list *source_list);
1317
1318// Search the given layer list for a list matching the given VkLayerProperties
1319bool has_vk_layer_property(const VkLayerProperties *vk_layer_prop, const struct loader_layer_list *list) {
1320 for (uint32_t i = 0; i < list->count; i++) {
1321 if (strcmp(vk_layer_prop->layerName, list->list[i].info.layerName) == 0) return true;
1322 }
1323 return false;
1324}
1325
1326// Search the given layer list for a layer matching the given name
1327bool has_layer_name(const char *name, const struct loader_layer_list *list) {
1328 for (uint32_t i = 0; i < list->count; i++) {
1329 if (strcmp(name, list->list[i].info.layerName) == 0) return true;
1330 }
1331 return false;
1332}
Mark Youngf2079b92017-05-02 10:49:46 -06001333
Mark Young0f183a82017-02-28 09:58:04 -07001334// Search the given search_list for any layers in the props list. Add these to the
1335// output layer_list. Don't add duplicates to the output layer_list.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001336static 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 -06001337 struct loader_layer_list *expanded_output_list, uint32_t name_count,
1338 const char *const *names, const struct loader_layer_list *source_list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001339 struct loader_layer_properties *layer_prop;
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06001340 VkResult err = VK_SUCCESS;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001341
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001342 for (uint32_t i = 0; i < name_count; i++) {
Mark Young283fe1c2017-05-04 12:16:35 -06001343 const char *source_name = names[i];
1344 layer_prop = loader_get_layer_property(source_name, source_list);
Mark Youngf2079b92017-05-02 10:49:46 -06001345 if (NULL == layer_prop) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001346 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1347 "loader_add_layer_names_to_list: Unable to find layer"
1348 " %s",
Mark Young283fe1c2017-05-04 12:16:35 -06001349 source_name);
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06001350 err = VK_ERROR_LAYER_NOT_PRESENT;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001351 continue;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001352 }
1353
Mark Youngf2079b92017-05-02 10:49:46 -06001354 // If not a meta-layer, simply add it.
1355 if (0 == (layer_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
Mark Young283fe1c2017-05-04 12:16:35 -06001356 if (!has_vk_layer_property(&layer_prop->info, output_list)) {
1357 loader_add_to_layer_list(inst, output_list, 1, layer_prop);
1358 }
1359 if (!has_vk_layer_property(&layer_prop->info, expanded_output_list)) {
1360 loader_add_to_layer_list(inst, expanded_output_list, 1, layer_prop);
1361 }
Mark Youngf2079b92017-05-02 10:49:46 -06001362 } else {
Mark Young283fe1c2017-05-04 12:16:35 -06001363 if (!has_vk_layer_property(&layer_prop->info, output_list) ||
1364 !has_vk_layer_property(&layer_prop->info, expanded_output_list)) {
1365 loader_add_meta_layer(inst, layer_prop, output_list, expanded_output_list, source_list);
Mark Youngf2079b92017-05-02 10:49:46 -06001366 }
1367 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001368 }
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06001369
1370 return err;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001371}
1372
Mark Young0f183a82017-02-28 09:58:04 -07001373// Manage lists of VkLayerProperties
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001374static bool loader_init_layer_list(const struct loader_instance *inst, struct loader_layer_list *list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001375 list->capacity = 32 * sizeof(struct loader_layer_properties);
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001376 list->list = loader_instance_heap_alloc(inst, list->capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001377 if (list->list == NULL) {
1378 return false;
1379 }
1380 memset(list->list, 0, list->capacity);
1381 list->count = 0;
1382 return true;
1383}
1384
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001385void loader_destroy_layer_list(const struct loader_instance *inst, struct loader_device *device,
Jon Ashburn23d36b12016-02-02 17:47:28 -07001386 struct loader_layer_list *layer_list) {
Mark Young0ad83132016-06-30 13:02:42 -06001387 if (device) {
1388 loader_device_heap_free(device, layer_list->list);
1389 } else {
1390 loader_instance_heap_free(inst, layer_list->list);
1391 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001392 layer_list->count = 0;
1393 layer_list->capacity = 0;
1394}
1395
Mark Young0f183a82017-02-28 09:58:04 -07001396// Append non-duplicate layer properties defined in prop_list to the given layer_info list
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001397VkResult 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 -06001398 const struct loader_layer_properties *props) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001399 uint32_t i;
Lenny Komow397f9d42017-10-25 15:26:15 -06001400 uint16_t layer_api_major_version;
1401 uint16_t layer_api_minor_version;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001402 struct loader_layer_properties *layer;
1403
1404 if (list->list == NULL || list->capacity == 0) {
Jon Ashburne39a4f82015-08-28 13:38:21 -06001405 loader_init_layer_list(inst, list);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001406 }
1407
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001408 if (list->list == NULL) return VK_SUCCESS;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001409
1410 for (i = 0; i < prop_list_count; i++) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001411 layer = (struct loader_layer_properties *)&props[i];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001412
Mark Youngf2079b92017-05-02 10:49:46 -06001413 // Look for duplicates, and skip
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001414 if (has_vk_layer_property(&layer->info, list)) {
1415 continue;
1416 }
1417
Mark Youngf2079b92017-05-02 10:49:46 -06001418 // Check for enough capacity
1419 if (((list->count + 1) * sizeof(struct loader_layer_properties)) >= list->capacity) {
1420 size_t new_capacity = list->capacity * 2;
Mark Youngbb3a29c2017-05-19 12:29:43 -06001421 void *new_ptr =
Mark Youngf2079b92017-05-02 10:49:46 -06001422 loader_instance_heap_realloc(inst, list->list, list->capacity, new_capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Youngbb3a29c2017-05-19 12:29:43 -06001423 if (NULL == new_ptr) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001424 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngbb3a29c2017-05-19 12:29:43 -06001425 "loader_add_to_layer_list: Realloc failed for when attempting to add new layer");
Mark Young0ad83132016-06-30 13:02:42 -06001426 return VK_ERROR_OUT_OF_HOST_MEMORY;
1427 }
Mark Youngbb3a29c2017-05-19 12:29:43 -06001428 list->list = new_ptr;
Mark Youngf2079b92017-05-02 10:49:46 -06001429 list->capacity = new_capacity;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001430 }
1431
Lenny Komow397f9d42017-10-25 15:26:15 -06001432 // Verify that the layer api version is at least that of the application's request, if not, throw a warning since
1433 // undefined behavior could occur.
1434 layer_api_major_version = VK_VERSION_MAJOR(props[i].info.specVersion);
1435 layer_api_minor_version = VK_VERSION_MINOR(props[i].info.specVersion);
1436 if (inst->app_api_major_version > layer_api_major_version ||
1437 (inst->app_api_major_version == layer_api_major_version && inst->app_api_minor_version > layer_api_minor_version)) {
1438 loader_log(
1439 inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
1440 "loader_add_to_layer_list: Explicit layer %s is using an old API version %d.%d versus application requested %d.%d",
1441 props[i].info.layerName, layer_api_major_version, layer_api_minor_version, inst->app_api_major_version,- inst->app_api_minor_version);
1442 }
1443
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001444 memcpy(&list->list[list->count], layer, sizeof(struct loader_layer_properties));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001445 list->count++;
1446 }
Mark Young0ad83132016-06-30 13:02:42 -06001447
1448 return VK_SUCCESS;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001449}
1450
Mark Youngf2079b92017-05-02 10:49:46 -06001451// Check the individual implicit layer for the enable/disable environment variable settings. Only add it after
1452// every check has passed indicating it should be used.
1453static void loader_add_implicit_layer(const struct loader_instance *inst, const struct loader_layer_properties *prop,
Mark Young283fe1c2017-05-04 12:16:35 -06001454 struct loader_layer_list *target_list, struct loader_layer_list *expanded_target_list,
1455 const struct loader_layer_list *source_list) {
Jean-Francois Roybd7ceab2017-07-06 14:10:13 -07001456 bool enable = loader_is_implicit_layer_enabled(inst, prop);
Lenny Komow397f9d42017-10-25 15:26:15 -06001457
1458 // If the implicit layer is supposed to be enable, make sure the layer supports at least the same API version
1459 // that the application is asking (i.e. layer's API >= app's API). If it's not, disable this layer.
1460 if (enable) {
1461 uint16_t layer_api_major_version = VK_VERSION_MAJOR(prop->info.specVersion);
1462 uint16_t layer_api_minor_version = VK_VERSION_MINOR(prop->info.specVersion);
1463 if (inst->app_api_major_version > layer_api_major_version ||
1464 (inst->app_api_major_version == layer_api_major_version && inst->app_api_minor_version > layer_api_minor_version)) {
1465 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
1466 "loader_add_implicit_layer: Disabling implicit layer %s for using an old API version %d.%d versus "
1467 "application requested %d.%d",
1468 prop->info.layerName, layer_api_major_version, layer_api_minor_version, inst->app_api_major_version,
1469 inst->app_api_minor_version);
1470 enable = false;
1471 }
1472 }
1473
Mark Youngf2079b92017-05-02 10:49:46 -06001474 if (enable) {
Mark Youngf2079b92017-05-02 10:49:46 -06001475 if (0 == (prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
Mark Youngc8b807a2017-07-14 17:11:31 -06001476 if (NULL != target_list && !has_vk_layer_property(&prop->info, target_list)) {
Mark Young283fe1c2017-05-04 12:16:35 -06001477 loader_add_to_layer_list(inst, target_list, 1, prop);
1478 }
1479 if (NULL != expanded_target_list && !has_vk_layer_property(&prop->info, expanded_target_list)) {
1480 loader_add_to_layer_list(inst, expanded_target_list, 1, prop);
1481 }
Mark Youngf2079b92017-05-02 10:49:46 -06001482 } else {
Mark Young283fe1c2017-05-04 12:16:35 -06001483 if (!has_vk_layer_property(&prop->info, target_list) ||
1484 (NULL != expanded_target_list && !has_vk_layer_property(&prop->info, expanded_target_list))) {
1485 loader_add_meta_layer(inst, prop, target_list, expanded_target_list, source_list);
1486 }
Mark Youngf2079b92017-05-02 10:49:46 -06001487 }
1488 }
1489}
1490
1491// Add the component layers of a meta-layer to the active list of layers
1492bool loader_add_meta_layer(const struct loader_instance *inst, const struct loader_layer_properties *prop,
Mark Young283fe1c2017-05-04 12:16:35 -06001493 struct loader_layer_list *target_list, struct loader_layer_list *expanded_target_list,
1494 const struct loader_layer_list *source_list) {
Mark Youngf2079b92017-05-02 10:49:46 -06001495 bool found = true;
1496
1497 // We need to add all the individual component layers
1498 for (uint32_t comp_layer = 0; comp_layer < prop->num_component_layers; comp_layer++) {
1499 bool found_comp = false;
1500 const struct loader_layer_properties *search_prop =
1501 loader_get_layer_property(prop->component_layer_names[comp_layer], source_list);
1502 if (search_prop != NULL) {
1503 found_comp = true;
Mark Young283fe1c2017-05-04 12:16:35 -06001504
1505 // If the component layer is itself an implicit layer, we need to do the implicit layer enable
1506 // checks
Mark Youngf2079b92017-05-02 10:49:46 -06001507 if (0 == (search_prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER)) {
Mark Young283fe1c2017-05-04 12:16:35 -06001508 loader_add_implicit_layer(inst, search_prop, target_list, expanded_target_list, source_list);
Mark Youngf2079b92017-05-02 10:49:46 -06001509 } else {
Mark Young283fe1c2017-05-04 12:16:35 -06001510 if (NULL != expanded_target_list && !has_vk_layer_property(&search_prop->info, expanded_target_list)) {
1511 loader_add_to_layer_list(inst, expanded_target_list, 1, search_prop);
1512 }
Mark Youngf2079b92017-05-02 10:49:46 -06001513 }
1514 }
1515 if (!found_comp) {
1516 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
1517 "loader_add_meta_layer: Failed to find layer name %s component layer "
1518 "%s to activate",
1519 search_prop->info.layerName, prop->component_layer_names[comp_layer]);
1520 found = false;
1521 }
1522 }
Mark Youngc8b807a2017-07-14 17:11:31 -06001523
1524 // Add this layer to the overall target list (not the expanded one)
1525 if (found && !has_vk_layer_property(&prop->info, target_list)) {
1526 loader_add_to_layer_list(inst, target_list, 1, prop);
1527 }
1528
Mark Youngf2079b92017-05-02 10:49:46 -06001529 return found;
1530}
1531
1532// Search the source_list for any layer with a name that matches the given name and a type
1533// that matches the given type. Add all matching layers to the target_list.
1534// Do not add if found loader_layer_properties is already on the target_list.
1535void 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 -06001536 const struct loader_layer_list *source_list, struct loader_layer_list *target_list,
1537 struct loader_layer_list *expanded_target_list) {
Jon Ashburn56151d62015-10-05 09:03:21 -06001538 bool found = false;
Mark Youngf2079b92017-05-02 10:49:46 -06001539 for (uint32_t i = 0; i < source_list->count; i++) {
1540 struct loader_layer_properties *source_prop = &source_list->list[i];
1541 if (0 == strcmp(source_prop->info.layerName, name) && (source_prop->type_flags & type_flags) == type_flags) {
Mark Youngf2079b92017-05-02 10:49:46 -06001542 // If not a meta-layer, simply add it.
1543 if (0 == (source_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
Mark Youngc8b807a2017-07-14 17:11:31 -06001544 if (NULL != target_list && !has_vk_layer_property(&source_prop->info, target_list) &&
Mark Young283fe1c2017-05-04 12:16:35 -06001545 VK_SUCCESS == loader_add_to_layer_list(inst, target_list, 1, source_prop)) {
1546 found = true;
1547 }
Mark Youngc8b807a2017-07-14 17:11:31 -06001548 if (NULL != expanded_target_list && !has_vk_layer_property(&source_prop->info, expanded_target_list) &&
Mark Young283fe1c2017-05-04 12:16:35 -06001549 VK_SUCCESS == loader_add_to_layer_list(inst, expanded_target_list, 1, source_prop)) {
Mark Youngf2079b92017-05-02 10:49:46 -06001550 found = true;
1551 }
1552 } else {
Mark Young283fe1c2017-05-04 12:16:35 -06001553 found = loader_add_meta_layer(inst, source_prop, target_list, expanded_target_list, source_list);
Mark Young0ad83132016-06-30 13:02:42 -06001554 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001555 }
1556 }
Jon Ashburn56151d62015-10-05 09:03:21 -06001557 if (!found) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001558 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Youngf2079b92017-05-02 10:49:46 -06001559 "loader_find_layer_name_add_list: Failed to find layer name %s to activate", name);
Jon Ashburn56151d62015-10-05 09:03:21 -06001560 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001561}
1562
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001563static VkExtensionProperties *get_extension_property(const char *name, const struct loader_extension_list *list) {
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06001564 for (uint32_t i = 0; i < list->count; i++) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001565 if (strcmp(name, list->list[i].extensionName) == 0) return &list->list[i];
Jon Ashburnfc2e38c2015-04-14 09:15:32 -06001566 }
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06001567 return NULL;
Jon Ashburnfc2e38c2015-04-14 09:15:32 -06001568}
1569
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001570static VkExtensionProperties *get_dev_extension_property(const char *name, const struct loader_device_extension_list *list) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001571 for (uint32_t i = 0; i < list->count; i++) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001572 if (strcmp(name, list->list[i].props.extensionName) == 0) return &list->list[i].props;
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001573 }
1574 return NULL;
1575}
1576
Mark Young0f183a82017-02-28 09:58:04 -07001577// For Instance extensions implemented within the loader (i.e. DEBUG_REPORT
1578// the extension must provide two entry points for the loader to use:
1579// - "trampoline" entry point - this is the address returned by GetProcAddr
1580// and will always do what's necessary to support a
1581// global call.
1582// - "terminator" function - this function will be put at the end of the
1583// instance chain and will contain the necessary logic
1584// to call / process the extension for the appropriate
1585// ICDs that are available.
1586// There is no generic mechanism for including these functions, the references
1587// must be placed into the appropriate loader entry points.
1588// GetInstanceProcAddr: call extension GetInstanceProcAddr to check for GetProcAddr
1589// requests
1590// loader_coalesce_extensions(void) - add extension records to the list of global
1591// extension available to the app.
1592// instance_disp - add function pointer for terminator function
1593// to this array.
1594// The extension itself should be in a separate file that will be linked directly
1595// with the loader.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001596VkResult loader_get_icd_loader_instance_extensions(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list,
1597 struct loader_extension_list *inst_exts) {
Jon Ashburn5c6a46f2015-08-14 14:49:22 -06001598 struct loader_extension_list icd_exts;
Mark Young3a587792016-08-19 15:25:08 -06001599 VkResult res = VK_SUCCESS;
Mark Young2b2ece72017-02-10 11:19:02 -07001600 char *env_value;
1601 bool filter_extensions = true;
Mark Young3a587792016-08-19 15:25:08 -06001602
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001603 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Build ICD instance extension list");
Mark Young3a587792016-08-19 15:25:08 -06001604
Mark Young2b2ece72017-02-10 11:19:02 -07001605 // Check if a user wants to disable the instance extension filtering behavior
1606 env_value = loader_getenv("VK_LOADER_DISABLE_INST_EXT_FILTER", inst);
1607 if (NULL != env_value && atoi(env_value) != 0) {
1608 filter_extensions = false;
1609 }
1610 loader_free_getenv(env_value, inst);
1611
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001612 // traverse scanned icd list adding non-duplicate extensions to the list
Mark Young0153e0b2016-11-03 14:27:13 -06001613 for (uint32_t i = 0; i < icd_tramp_list->count; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001614 res = loader_init_generic_list(inst, (struct loader_generic_list *)&icd_exts, sizeof(VkExtensionProperties));
Mark Young3a587792016-08-19 15:25:08 -06001615 if (VK_SUCCESS != res) {
1616 goto out;
1617 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001618 res = loader_add_instance_extensions(inst, icd_tramp_list->scanned_list[i].EnumerateInstanceExtensionProperties,
1619 icd_tramp_list->scanned_list[i].lib_name, &icd_exts);
Mark Young3a587792016-08-19 15:25:08 -06001620 if (VK_SUCCESS == res) {
Mark Young2b2ece72017-02-10 11:19:02 -07001621 if (filter_extensions) {
1622 // Remove any extensions not recognized by the loader
1623 for (int32_t j = 0; j < (int32_t)icd_exts.count; j++) {
1624 // See if the extension is in the list of supported extensions
1625 bool found = false;
1626 for (uint32_t k = 0; LOADER_INSTANCE_EXTENSIONS[k] != NULL; k++) {
1627 if (strcmp(icd_exts.list[j].extensionName, LOADER_INSTANCE_EXTENSIONS[k]) == 0) {
1628 found = true;
1629 break;
1630 }
Lenny Komow4053b812016-12-29 16:27:28 -07001631 }
Lenny Komow4053b812016-12-29 16:27:28 -07001632
Mark Young2b2ece72017-02-10 11:19:02 -07001633 // If it isn't in the list, remove it
1634 if (!found) {
1635 for (uint32_t k = j + 1; k < icd_exts.count; k++) {
1636 icd_exts.list[k - 1] = icd_exts.list[k];
1637 }
1638 --icd_exts.count;
1639 --j;
Lenny Komow4053b812016-12-29 16:27:28 -07001640 }
Lenny Komow4053b812016-12-29 16:27:28 -07001641 }
1642 }
1643
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001644 res = loader_add_to_ext_list(inst, inst_exts, icd_exts.count, icd_exts.list);
Mark Young3a587792016-08-19 15:25:08 -06001645 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001646 loader_destroy_generic_list(inst, (struct loader_generic_list *)&icd_exts);
Mark Young3a587792016-08-19 15:25:08 -06001647 if (VK_SUCCESS != res) {
1648 goto out;
1649 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001650 };
1651
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001652 // Traverse loader's extensions, adding non-duplicate extensions to the list
Mark Young6ba8abe2017-11-09 10:37:04 -07001653 debug_utils_AddInstanceExtensions(inst, inst_exts);
Mark Young3a587792016-08-19 15:25:08 -06001654
1655out:
1656 return res;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001657}
1658
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001659struct 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 -06001660 *found_dev = NULL;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001661 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
Lenny Komow27167312017-03-31 13:43:35 -06001662 uint32_t index = 0;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001663 for (struct loader_icd_term *icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
1664 for (struct loader_device *dev = icd_term->logical_device_list; dev; dev = dev->next)
Mark Young65cb3662016-11-07 13:27:02 -07001665 // Value comparison of device prevents object wrapping by layers
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001666 if (loader_get_dispatch(dev->icd_device) == loader_get_dispatch(device) ||
1667 loader_get_dispatch(dev->chain_device) == loader_get_dispatch(device)) {
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001668 *found_dev = dev;
Mark Young16573c72016-06-28 10:52:43 -06001669 if (NULL != icd_index) {
1670 *icd_index = index;
1671 }
Mark Young0153e0b2016-11-03 14:27:13 -06001672 return icd_term;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001673 }
Mark Young16573c72016-06-28 10:52:43 -06001674 index++;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001675 }
1676 }
1677 return NULL;
1678}
1679
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001680void loader_destroy_logical_device(const struct loader_instance *inst, struct loader_device *dev,
Mark Young0ad83132016-06-30 13:02:42 -06001681 const VkAllocationCallbacks *pAllocator) {
1682 if (pAllocator) {
1683 dev->alloc_callbacks = *pAllocator;
1684 }
Mark Young283fe1c2017-05-04 12:16:35 -06001685 if (NULL != dev->expanded_activated_layer_list.list) {
1686 loader_deactivate_layers(inst, dev, &dev->expanded_activated_layer_list);
1687 }
1688 if (NULL != dev->app_activated_layer_list.list) {
1689 loader_destroy_layer_list(inst, dev, &dev->app_activated_layer_list);
Mark Young0ad83132016-06-30 13:02:42 -06001690 }
1691 loader_device_heap_free(dev, dev);
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001692}
1693
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001694struct loader_device *loader_create_logical_device(const struct loader_instance *inst, const VkAllocationCallbacks *pAllocator) {
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001695 struct loader_device *new_dev;
Mark Young0ad83132016-06-30 13:02:42 -06001696#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
1697 {
1698#else
1699 if (pAllocator) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001700 new_dev = (struct loader_device *)pAllocator->pfnAllocation(pAllocator->pUserData, sizeof(struct loader_device),
1701 sizeof(int *), VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
Mark Young0ad83132016-06-30 13:02:42 -06001702 } else {
1703#endif
1704 new_dev = (struct loader_device *)malloc(sizeof(struct loader_device));
1705 }
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001706
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001707 if (!new_dev) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001708 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1709 "loader_create_logical_device: Failed to alloc struct "
1710 "loader_device");
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001711 return NULL;
1712 }
1713
1714 memset(new_dev, 0, sizeof(struct loader_device));
Mark Young0ad83132016-06-30 13:02:42 -06001715 if (pAllocator) {
1716 new_dev->alloc_callbacks = *pAllocator;
1717 }
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001718
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001719 return new_dev;
1720}
1721
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001722void 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 -06001723 dev->next = icd_term->logical_device_list;
1724 icd_term->logical_device_list = dev;
Piers Daniell295fe402016-03-29 11:51:11 -06001725}
1726
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001727void loader_remove_logical_device(const struct loader_instance *inst, struct loader_icd_term *icd_term,
1728 struct loader_device *found_dev, const VkAllocationCallbacks *pAllocator) {
Jon Ashburn781a7ae2015-11-19 15:43:26 -07001729 struct loader_device *dev, *prev_dev;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001730
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001731 if (!icd_term || !found_dev) return;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001732
1733 prev_dev = NULL;
Mark Young0153e0b2016-11-03 14:27:13 -06001734 dev = icd_term->logical_device_list;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001735 while (dev && dev != found_dev) {
1736 prev_dev = dev;
1737 dev = dev->next;
1738 }
1739
1740 if (prev_dev)
1741 prev_dev->next = found_dev->next;
1742 else
Mark Young0153e0b2016-11-03 14:27:13 -06001743 icd_term->logical_device_list = found_dev->next;
Mark Young0ad83132016-06-30 13:02:42 -06001744 loader_destroy_logical_device(inst, found_dev, pAllocator);
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001745}
1746
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001747static void loader_icd_destroy(struct loader_instance *ptr_inst, struct loader_icd_term *icd_term,
Mark Young0ad83132016-06-30 13:02:42 -06001748 const VkAllocationCallbacks *pAllocator) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001749 ptr_inst->total_icd_count--;
Mark Young0153e0b2016-11-03 14:27:13 -06001750 for (struct loader_device *dev = icd_term->logical_device_list; dev;) {
Courtney Goeltzenleuchter1f157ac2015-06-14 19:57:15 -06001751 struct loader_device *next_dev = dev->next;
Mark Young0ad83132016-06-30 13:02:42 -06001752 loader_destroy_logical_device(ptr_inst, dev, pAllocator);
Courtney Goeltzenleuchter1f157ac2015-06-14 19:57:15 -06001753 dev = next_dev;
1754 }
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001755
Mark Young0153e0b2016-11-03 14:27:13 -06001756 loader_instance_heap_free(ptr_inst, icd_term);
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001757}
1758
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001759static struct loader_icd_term *loader_icd_create(const struct loader_instance *inst) {
Mark Young0153e0b2016-11-03 14:27:13 -06001760 struct loader_icd_term *icd_term;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001761
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001762 icd_term = loader_instance_heap_alloc(inst, sizeof(struct loader_icd_term), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0153e0b2016-11-03 14:27:13 -06001763 if (!icd_term) {
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001764 return NULL;
Mark Youngdb13a2a2016-09-06 13:53:03 -06001765 }
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001766
Mark Young0153e0b2016-11-03 14:27:13 -06001767 memset(icd_term, 0, sizeof(struct loader_icd_term));
Courtney Goeltzenleuchter55001bb2014-10-28 10:29:27 -06001768
Mark Young0153e0b2016-11-03 14:27:13 -06001769 return icd_term;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001770}
1771
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001772static 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 -06001773 struct loader_icd_term *icd_term;
Chia-I Wu13a61a52014-08-04 11:18:20 +08001774
Mark Young0153e0b2016-11-03 14:27:13 -06001775 icd_term = loader_icd_create(ptr_inst);
1776 if (!icd_term) {
Chia-I Wu13a61a52014-08-04 11:18:20 +08001777 return NULL;
Mark Youngdb13a2a2016-09-06 13:53:03 -06001778 }
Chia-I Wu13a61a52014-08-04 11:18:20 +08001779
Mark Young0153e0b2016-11-03 14:27:13 -06001780 icd_term->scanned_icd = scanned_icd;
1781 icd_term->this_instance = ptr_inst;
Jon Ashburn3d002332015-08-20 16:35:30 -06001782
Mark Young0f183a82017-02-28 09:58:04 -07001783 // Prepend to the list
Mark Young0153e0b2016-11-03 14:27:13 -06001784 icd_term->next = ptr_inst->icd_terms;
1785 ptr_inst->icd_terms = icd_term;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001786 ptr_inst->total_icd_count++;
Chia-I Wu13a61a52014-08-04 11:18:20 +08001787
Mark Young0153e0b2016-11-03 14:27:13 -06001788 return icd_term;
Chia-I Wu13a61a52014-08-04 11:18:20 +08001789}
Mark Young0153e0b2016-11-03 14:27:13 -06001790
Mark Young0f183a82017-02-28 09:58:04 -07001791// Determine the ICD interface version to use.
1792// @param icd
1793// @param pVersion Output parameter indicating which version to use or 0 if
1794// the negotiation API is not supported by the ICD
1795// @return bool indicating true if the selected interface version is supported
1796// by the loader, false indicates the version is not supported
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001797bool loader_get_icd_interface_version(PFN_vkNegotiateLoaderICDInterfaceVersion fp_negotiate_icd_version, uint32_t *pVersion) {
Jon Ashburn17b4c862016-04-25 11:09:37 -06001798 if (fp_negotiate_icd_version == NULL) {
1799 // ICD does not support the negotiation API, it supports version 0 or 1
1800 // calling code must determine if it is version 0 or 1
1801 *pVersion = 0;
1802 } else {
1803 // ICD supports the negotiation API, so call it with the loader's
1804 // latest version supported
1805 *pVersion = CURRENT_LOADER_ICD_INTERFACE_VERSION;
1806 VkResult result = fp_negotiate_icd_version(pVersion);
1807
1808 if (result == VK_ERROR_INCOMPATIBLE_DRIVER) {
1809 // ICD no longer supports the loader's latest interface version so
1810 // fail loading the ICD
1811 return false;
1812 }
1813 }
1814
1815#if MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION > 0
1816 if (*pVersion < MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION) {
1817 // Loader no longer supports the ICD's latest interface version so fail
1818 // loading the ICD
1819 return false;
1820 }
1821#endif
1822 return true;
1823}
Chia-I Wu13a61a52014-08-04 11:18:20 +08001824
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001825void loader_scanned_icd_clear(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list) {
Mark Youngf2079b92017-05-02 10:49:46 -06001826 if (0 != icd_tramp_list->capacity) {
1827 for (uint32_t i = 0; i < icd_tramp_list->count; i++) {
1828 loader_platform_close_library(icd_tramp_list->scanned_list[i].handle);
1829 loader_instance_heap_free(inst, icd_tramp_list->scanned_list[i].lib_name);
1830 }
1831 loader_instance_heap_free(inst, icd_tramp_list->scanned_list);
1832 icd_tramp_list->capacity = 0;
1833 icd_tramp_list->count = 0;
1834 icd_tramp_list->scanned_list = NULL;
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001835 }
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001836}
1837
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001838static 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 -06001839 VkResult err = VK_SUCCESS;
Mark Young0153e0b2016-11-03 14:27:13 -06001840 loader_scanned_icd_clear(inst, icd_tramp_list);
1841 icd_tramp_list->capacity = 8 * sizeof(struct loader_scanned_icd);
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001842 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 -06001843 if (NULL == icd_tramp_list->scanned_list) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001844 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1845 "loader_scanned_icd_init: Realloc failed for layer list when "
1846 "attempting to add new layer");
Mark Young0ad83132016-06-30 13:02:42 -06001847 err = VK_ERROR_OUT_OF_HOST_MEMORY;
1848 }
1849 return err;
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001850}
1851
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001852static VkResult loader_scanned_icd_add(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list,
1853 const char *filename, uint32_t api_version) {
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001854 loader_platform_dl_handle handle;
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06001855 PFN_vkCreateInstance fp_create_inst;
Jon Ashburnfd4d09d2016-01-07 09:44:27 -07001856 PFN_vkEnumerateInstanceExtensionProperties fp_get_inst_ext_props;
Jon Ashburnc624c882015-07-16 10:17:29 -06001857 PFN_vkGetInstanceProcAddr fp_get_proc_addr;
Mark Young39389872017-01-19 21:10:49 -07001858 PFN_GetPhysicalDeviceProcAddr fp_get_phys_dev_proc_addr = NULL;
Jon Ashburn17b4c862016-04-25 11:09:37 -06001859 PFN_vkNegotiateLoaderICDInterfaceVersion fp_negotiate_icd_version;
Mark Young0153e0b2016-11-03 14:27:13 -06001860 struct loader_scanned_icd *new_scanned_icd;
Jon Ashburn17b4c862016-04-25 11:09:37 -06001861 uint32_t interface_vers;
Mark Young3a587792016-08-19 15:25:08 -06001862 VkResult res = VK_SUCCESS;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001863
Mark Young0f183a82017-02-28 09:58:04 -07001864 // TODO implement smarter opening/closing of libraries. For now this
1865 // function leaves libraries open and the scanned_icd_clear closes them
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001866 handle = loader_platform_open_library(filename);
Mark Youngb6399312017-01-10 14:22:15 -07001867 if (NULL == handle) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001868 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, loader_platform_open_library_error(filename));
Mark Young3a587792016-08-19 15:25:08 -06001869 goto out;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001870 }
1871
Jon Ashburn17b4c862016-04-25 11:09:37 -06001872 // Get and settle on an ICD interface version
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001873 fp_negotiate_icd_version = loader_platform_get_proc_address(handle, "vk_icdNegotiateLoaderICDInterfaceVersion");
Jon Ashburn17b4c862016-04-25 11:09:37 -06001874
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001875 if (!loader_get_icd_interface_version(fp_negotiate_icd_version, &interface_vers)) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001876 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1877 "loader_scanned_icd_add: ICD %s doesn't support interface"
1878 " version compatible with loader, skip this ICD.",
Mark Young0ad83132016-06-30 13:02:42 -06001879 filename);
Mark Young3a587792016-08-19 15:25:08 -06001880 goto out;
Jon Ashburn17b4c862016-04-25 11:09:37 -06001881 }
1882
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001883 fp_get_proc_addr = loader_platform_get_proc_address(handle, "vk_icdGetInstanceProcAddr");
Mark Youngb6399312017-01-10 14:22:15 -07001884 if (NULL == fp_get_proc_addr) {
Jon Ashburn17b4c862016-04-25 11:09:37 -06001885 assert(interface_vers == 0);
1886 // Use deprecated interface from version 0
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001887 fp_get_proc_addr = loader_platform_get_proc_address(handle, "vkGetInstanceProcAddr");
Mark Youngb6399312017-01-10 14:22:15 -07001888 if (NULL == fp_get_proc_addr) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001889 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngdee312c2017-03-08 13:38:35 -07001890 "loader_scanned_icd_add: Attempt to retrieve either "
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001891 "\'vkGetInstanceProcAddr\' or "
1892 "\'vk_icdGetInstanceProcAddr\' from ICD %s failed.",
Mark Youngb6399312017-01-10 14:22:15 -07001893 filename);
Mark Young3a587792016-08-19 15:25:08 -06001894 goto out;
Jon Ashburnfd4d09d2016-01-07 09:44:27 -07001895 } else {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001896 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
1897 "loader_scanned_icd_add: Using deprecated ICD "
1898 "interface of \'vkGetInstanceProcAddr\' instead of "
1899 "\'vk_icdGetInstanceProcAddr\' for ICD %s",
Mark Young0ad83132016-06-30 13:02:42 -06001900 filename);
Jon Ashburnfd4d09d2016-01-07 09:44:27 -07001901 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001902 fp_create_inst = loader_platform_get_proc_address(handle, "vkCreateInstance");
Mark Youngb6399312017-01-10 14:22:15 -07001903 if (NULL == fp_create_inst) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001904 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1905 "loader_scanned_icd_add: Failed querying "
1906 "\'vkCreateInstance\' via dlsym/loadlibrary for "
1907 "ICD %s",
Mark Young0ad83132016-06-30 13:02:42 -06001908 filename);
Mark Young3a587792016-08-19 15:25:08 -06001909 goto out;
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001910 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001911 fp_get_inst_ext_props = loader_platform_get_proc_address(handle, "vkEnumerateInstanceExtensionProperties");
Mark Youngb6399312017-01-10 14:22:15 -07001912 if (NULL == fp_get_inst_ext_props) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001913 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1914 "loader_scanned_icd_add: Could not get \'vkEnumerate"
1915 "InstanceExtensionProperties\' via dlsym/loadlibrary "
1916 "for ICD %s",
Mark Young0ad83132016-06-30 13:02:42 -06001917 filename);
Mark Young3a587792016-08-19 15:25:08 -06001918 goto out;
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001919 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07001920 } else {
Jon Ashburn17b4c862016-04-25 11:09:37 -06001921 // Use newer interface version 1 or later
Mark Young39389872017-01-19 21:10:49 -07001922 if (interface_vers == 0) {
Jon Ashburn17b4c862016-04-25 11:09:37 -06001923 interface_vers = 1;
Mark Young39389872017-01-19 21:10:49 -07001924 }
Jon Ashburn17b4c862016-04-25 11:09:37 -06001925
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001926 fp_create_inst = (PFN_vkCreateInstance)fp_get_proc_addr(NULL, "vkCreateInstance");
Mark Youngb6399312017-01-10 14:22:15 -07001927 if (NULL == fp_create_inst) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001928 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1929 "loader_scanned_icd_add: Could not get "
1930 "\'vkCreateInstance\' via \'vk_icdGetInstanceProcAddr\'"
1931 " for ICD %s",
Mark Young0ad83132016-06-30 13:02:42 -06001932 filename);
Mark Young3a587792016-08-19 15:25:08 -06001933 goto out;
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001934 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07001935 fp_get_inst_ext_props =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001936 (PFN_vkEnumerateInstanceExtensionProperties)fp_get_proc_addr(NULL, "vkEnumerateInstanceExtensionProperties");
Mark Youngb6399312017-01-10 14:22:15 -07001937 if (NULL == fp_get_inst_ext_props) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001938 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1939 "loader_scanned_icd_add: Could not get \'vkEnumerate"
1940 "InstanceExtensionProperties\' via "
1941 "\'vk_icdGetInstanceProcAddr\' for ICD %s",
Mark Young0ad83132016-06-30 13:02:42 -06001942 filename);
Mark Young3a587792016-08-19 15:25:08 -06001943 goto out;
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001944 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001945 fp_get_phys_dev_proc_addr = loader_platform_get_proc_address(handle, "vk_icdGetPhysicalDeviceProcAddr");
Jon Ashburnfd4d09d2016-01-07 09:44:27 -07001946 }
Jon Ashburn46d1f582015-01-28 11:01:35 -07001947
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001948 // check for enough capacity
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001949 if ((icd_tramp_list->count * sizeof(struct loader_scanned_icd)) >= icd_tramp_list->capacity) {
Mark Youngbb3a29c2017-05-19 12:29:43 -06001950 void *new_ptr = loader_instance_heap_realloc(inst, icd_tramp_list->scanned_list, icd_tramp_list->capacity,
1951 icd_tramp_list->capacity * 2, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1952 if (NULL == new_ptr) {
Mark Young3a587792016-08-19 15:25:08 -06001953 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001954 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngbb3a29c2017-05-19 12:29:43 -06001955 "loader_scanned_icd_add: Realloc failed on icd library list for ICD %s", filename);
Mark Young3a587792016-08-19 15:25:08 -06001956 goto out;
Mark Young0ad83132016-06-30 13:02:42 -06001957 }
Mark Youngbb3a29c2017-05-19 12:29:43 -06001958 icd_tramp_list->scanned_list = new_ptr;
1959
Jon Ashburn23d36b12016-02-02 17:47:28 -07001960 // double capacity
Mark Young0153e0b2016-11-03 14:27:13 -06001961 icd_tramp_list->capacity *= 2;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001962 }
1963
Mark Young39389872017-01-19 21:10:49 -07001964 new_scanned_icd = &(icd_tramp_list->scanned_list[icd_tramp_list->count]);
Mark Young0153e0b2016-11-03 14:27:13 -06001965 new_scanned_icd->handle = handle;
1966 new_scanned_icd->api_version = api_version;
1967 new_scanned_icd->GetInstanceProcAddr = fp_get_proc_addr;
Mark Young39389872017-01-19 21:10:49 -07001968 new_scanned_icd->GetPhysicalDeviceProcAddr = fp_get_phys_dev_proc_addr;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001969 new_scanned_icd->EnumerateInstanceExtensionProperties = fp_get_inst_ext_props;
Mark Young0153e0b2016-11-03 14:27:13 -06001970 new_scanned_icd->CreateInstance = fp_create_inst;
1971 new_scanned_icd->interface_version = interface_vers;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001972
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001973 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 -06001974 if (NULL == new_scanned_icd->lib_name) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001975 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 -06001976 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young3a587792016-08-19 15:25:08 -06001977 goto out;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001978 }
Mark Young0153e0b2016-11-03 14:27:13 -06001979 strcpy(new_scanned_icd->lib_name, filename);
1980 icd_tramp_list->count++;
Mark Young3a587792016-08-19 15:25:08 -06001981
1982out:
1983
1984 return res;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001985}
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001986
Jon Ashburn23d36b12016-02-02 17:47:28 -07001987static void loader_debug_init(void) {
Mark Young0ad83132016-06-30 13:02:42 -06001988 char *env, *orig;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001989
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001990 if (g_loader_debug > 0) return;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001991
1992 g_loader_debug = 0;
1993
Mark Young0f183a82017-02-28 09:58:04 -07001994 // Parse comma-separated debug options
Mark Young0ad83132016-06-30 13:02:42 -06001995 orig = env = loader_getenv("VK_LOADER_DEBUG", NULL);
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001996 while (env) {
Mark Young0ad83132016-06-30 13:02:42 -06001997 char *p = strchr(env, ',');
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001998 size_t len;
1999
2000 if (p)
2001 len = p - env;
2002 else
2003 len = strlen(env);
2004
2005 if (len > 0) {
Michael Worcester25c73e72015-12-10 18:06:24 +00002006 if (strncmp(env, "all", len) == 0) {
2007 g_loader_debug = ~0u;
2008 g_loader_log_msgs = ~0u;
2009 } else if (strncmp(env, "warn", len) == 0) {
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06002010 g_loader_debug |= LOADER_WARN_BIT;
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07002011 g_loader_log_msgs |= VK_DEBUG_REPORT_WARNING_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06002012 } else if (strncmp(env, "info", len) == 0) {
2013 g_loader_debug |= LOADER_INFO_BIT;
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07002014 g_loader_log_msgs |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06002015 } else if (strncmp(env, "perf", len) == 0) {
2016 g_loader_debug |= LOADER_PERF_BIT;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002017 g_loader_log_msgs |= VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06002018 } else if (strncmp(env, "error", len) == 0) {
2019 g_loader_debug |= LOADER_ERROR_BIT;
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07002020 g_loader_log_msgs |= VK_DEBUG_REPORT_ERROR_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06002021 } else if (strncmp(env, "debug", len) == 0) {
2022 g_loader_debug |= LOADER_DEBUG_BIT;
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07002023 g_loader_log_msgs |= VK_DEBUG_REPORT_DEBUG_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06002024 }
2025 }
2026
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002027 if (!p) break;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06002028
2029 env = p + 1;
2030 }
Jon Ashburn38a497f2016-01-04 14:01:38 -07002031
Mark Young0ad83132016-06-30 13:02:42 -06002032 loader_free_getenv(orig, NULL);
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06002033}
2034
Jon Ashburn23d36b12016-02-02 17:47:28 -07002035void loader_initialize(void) {
Jon Ashburn6461ef22015-09-22 13:11:00 -06002036 // initialize mutexs
Jon Ashburn8810c5f2015-08-18 18:04:47 -06002037 loader_platform_thread_create_mutex(&loader_lock);
Jon Ashburn6461ef22015-09-22 13:11:00 -06002038 loader_platform_thread_create_mutex(&loader_json_lock);
Jon Ashburn8810c5f2015-08-18 18:04:47 -06002039
2040 // initialize logging
2041 loader_debug_init();
Jon Ashburn87d6aa92015-08-28 15:19:27 -06002042
2043 // initial cJSON to use alloc callbacks
2044 cJSON_Hooks alloc_fns = {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002045 .malloc_fn = loader_instance_tls_heap_alloc, .free_fn = loader_instance_tls_heap_free,
Jon Ashburn87d6aa92015-08-28 15:19:27 -06002046 };
2047 cJSON_InitHooks(&alloc_fns);
Jon Ashburn8810c5f2015-08-18 18:04:47 -06002048}
2049
Jon Ashburn2077e382015-06-29 11:25:34 -06002050struct loader_manifest_files {
2051 uint32_t count;
2052 char **filename_list;
2053};
2054
Lenny Komow158e9d92018-01-15 15:43:36 -07002055void loader_release() {
2056 // release mutexs
2057 loader_platform_thread_delete_mutex(&loader_lock);
2058 loader_platform_thread_delete_mutex(&loader_json_lock);
2059}
2060
Mark Young0f183a82017-02-28 09:58:04 -07002061// Get next file or dirname given a string list or registry key path
2062//
2063// \returns
2064// A pointer to first char in the next path.
2065// The next path (or NULL) in the list is returned in next_path.
2066// Note: input string is modified in some cases. PASS IN A COPY!
Jon Ashburn23d36b12016-02-02 17:47:28 -07002067static char *loader_get_next_path(char *path) {
Jon Ashburn2077e382015-06-29 11:25:34 -06002068 uint32_t len;
2069 char *next;
2070
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002071 if (path == NULL) return NULL;
Frank Henigman57173102016-11-24 22:15:20 -05002072 next = strchr(path, PATH_SEPARATOR);
Jon Ashburn2077e382015-06-29 11:25:34 -06002073 if (next == NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07002074 len = (uint32_t)strlen(path);
Jon Ashburn2077e382015-06-29 11:25:34 -06002075 next = path + len;
Jon Ashburn23d36b12016-02-02 17:47:28 -07002076 } else {
Jon Ashburn2077e382015-06-29 11:25:34 -06002077 *next = '\0';
2078 next++;
2079 }
2080
2081 return next;
2082}
2083
Mark Young0f183a82017-02-28 09:58:04 -07002084// Given a path which is absolute or relative, expand the path if relative or
2085// leave the path unmodified if absolute. The base path to prepend to relative
2086// paths is given in rel_base.
2087//
2088// @return - A string in out_fullpath of the full absolute path
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002089static 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 -06002090 if (loader_platform_is_path_absolute(path)) {
Daniel Dadap00b4aba2015-09-30 11:50:51 -05002091 // do not prepend a base to an absolute path
2092 rel_base = "";
Jon Ashburn15315172015-07-07 15:06:25 -06002093 }
Daniel Dadap00b4aba2015-09-30 11:50:51 -05002094
2095 loader_platform_combine_path(out_fullpath, out_size, rel_base, path, NULL);
Jon Ashburn15315172015-07-07 15:06:25 -06002096}
2097
Mark Young0f183a82017-02-28 09:58:04 -07002098// Given a filename (file) and a list of paths (dir), try to find an existing
2099// file in the paths. If filename already is a path then no searching in the given paths.
2100//
2101// @return - A string in out_fullpath of either the full path or file.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002102static void loader_get_fullpath(const char *file, const char *dirs, size_t out_size, char *out_fullpath) {
Daniel Dadap00b4aba2015-09-30 11:50:51 -05002103 if (!loader_platform_is_path(file) && *dirs) {
2104 char *dirs_copy, *dir, *next_dir;
2105
2106 dirs_copy = loader_stack_alloc(strlen(dirs) + 1);
2107 strcpy(dirs_copy, dirs);
2108
Jon Ashburn23d36b12016-02-02 17:47:28 -07002109 // find if file exists after prepending paths in given list
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002110 for (dir = dirs_copy; *dir && (next_dir = loader_get_next_path(dir)); dir = next_dir) {
2111 loader_platform_combine_path(out_fullpath, out_size, dir, file, NULL);
Jon Ashburn2077e382015-06-29 11:25:34 -06002112 if (loader_platform_file_exists(out_fullpath)) {
2113 return;
2114 }
Jon Ashburn2077e382015-06-29 11:25:34 -06002115 }
2116 }
Daniel Dadap00b4aba2015-09-30 11:50:51 -05002117
Karl Schultze2ef9e62017-01-13 14:01:35 -07002118 (void)snprintf(out_fullpath, out_size, "%s", file);
Jon Ashburn2077e382015-06-29 11:25:34 -06002119}
2120
Mark Young0f183a82017-02-28 09:58:04 -07002121// Read a JSON file into a buffer.
2122//
2123// @return - A pointer to a cJSON object representing the JSON parse tree.
2124// This returned buffer should be freed by caller.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002125static VkResult loader_get_json(const struct loader_instance *inst, const char *filename, cJSON **json) {
Mark Young3a587792016-08-19 15:25:08 -06002126 FILE *file = NULL;
Jon Ashburn2077e382015-06-29 11:25:34 -06002127 char *json_buf;
Mark Young93ecb1d2016-01-13 13:47:16 -07002128 size_t len;
Mark Young3a587792016-08-19 15:25:08 -06002129 VkResult res = VK_SUCCESS;
2130
2131 if (NULL == json) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002132 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, "loader_get_json: Received invalid JSON file");
Mark Young3a587792016-08-19 15:25:08 -06002133 res = VK_ERROR_INITIALIZATION_FAILED;
2134 goto out;
2135 }
2136
2137 *json = NULL;
2138
Jon Ashburn23d36b12016-02-02 17:47:28 -07002139 file = fopen(filename, "rb");
Jon Ashburnaa4ea472015-08-27 08:30:50 -06002140 if (!file) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002141 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 -07002142 res = VK_ERROR_INITIALIZATION_FAILED;
Mark Young3a587792016-08-19 15:25:08 -06002143 goto out;
Jon Ashburnaa4ea472015-08-27 08:30:50 -06002144 }
Jon Ashburn2077e382015-06-29 11:25:34 -06002145 fseek(file, 0, SEEK_END);
2146 len = ftell(file);
2147 fseek(file, 0, SEEK_SET);
Jon Ashburn23d36b12016-02-02 17:47:28 -07002148 json_buf = (char *)loader_stack_alloc(len + 1);
Jon Ashburn2077e382015-06-29 11:25:34 -06002149 if (json_buf == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002150 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2151 "loader_get_json: Failed to allocate space for "
2152 "JSON file %s buffer of length %d",
Mark Youngb6399312017-01-10 14:22:15 -07002153 filename, len);
2154 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young3a587792016-08-19 15:25:08 -06002155 goto out;
Jon Ashburn2077e382015-06-29 11:25:34 -06002156 }
2157 if (fread(json_buf, sizeof(char), len, file) != len) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002158 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 -07002159 res = VK_ERROR_INITIALIZATION_FAILED;
Mark Young3a587792016-08-19 15:25:08 -06002160 goto out;
Jon Ashburn2077e382015-06-29 11:25:34 -06002161 }
Jon Ashburn2077e382015-06-29 11:25:34 -06002162 json_buf[len] = '\0';
2163
Mark Young0f183a82017-02-28 09:58:04 -07002164 // Parse text from file
Mark Young3a587792016-08-19 15:25:08 -06002165 *json = cJSON_Parse(json_buf);
2166 if (*json == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002167 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2168 "loader_get_json: Failed to parse JSON file %s, "
2169 "this is usually because something ran out of "
2170 "memory.",
Mark Youngb6399312017-01-10 14:22:15 -07002171 filename);
2172 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young3a587792016-08-19 15:25:08 -06002173 goto out;
2174 }
2175
2176out:
2177 if (NULL != file) {
2178 fclose(file);
2179 }
2180
2181 return res;
Jon Ashburn2077e382015-06-29 11:25:34 -06002182}
2183
Mark Young0f183a82017-02-28 09:58:04 -07002184// Do a deep copy of the loader_layer_properties structure.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002185VkResult loader_copy_layer_properties(const struct loader_instance *inst, struct loader_layer_properties *dst,
Mark Young0ad83132016-06-30 13:02:42 -06002186 struct loader_layer_properties *src) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07002187 uint32_t cnt, i;
Jon Ashburn23d36b12016-02-02 17:47:28 -07002188 memcpy(dst, src, sizeof(*src));
Mark Youngb6399312017-01-10 14:22:15 -07002189 dst->instance_extension_list.list = loader_instance_heap_alloc(
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002190 inst, sizeof(VkExtensionProperties) * src->instance_extension_list.count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0ad83132016-06-30 13:02:42 -06002191 if (NULL == dst->instance_extension_list.list) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002192 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2193 "loader_copy_layer_properties: Failed to allocate space "
2194 "for instance extension list of size %d.",
Mark Youngb6399312017-01-10 14:22:15 -07002195 src->instance_extension_list.count);
Mark Young0ad83132016-06-30 13:02:42 -06002196 return VK_ERROR_OUT_OF_HOST_MEMORY;
2197 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002198 dst->instance_extension_list.capacity = sizeof(VkExtensionProperties) * src->instance_extension_list.count;
2199 memcpy(dst->instance_extension_list.list, src->instance_extension_list.list, dst->instance_extension_list.capacity);
Mark Youngb6399312017-01-10 14:22:15 -07002200 dst->device_extension_list.list = loader_instance_heap_alloc(
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002201 inst, sizeof(struct loader_dev_ext_props) * src->device_extension_list.count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0ad83132016-06-30 13:02:42 -06002202 if (NULL == dst->device_extension_list.list) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002203 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2204 "loader_copy_layer_properties: Failed to allocate space "
2205 "for device extension list of size %d.",
Mark Youngb6399312017-01-10 14:22:15 -07002206 src->device_extension_list.count);
Mark Young0ad83132016-06-30 13:02:42 -06002207 return VK_ERROR_OUT_OF_HOST_MEMORY;
2208 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002209 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 -07002210
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002211 dst->device_extension_list.capacity = sizeof(struct loader_dev_ext_props) * src->device_extension_list.count;
2212 memcpy(dst->device_extension_list.list, src->device_extension_list.list, dst->device_extension_list.capacity);
2213 if (src->device_extension_list.count > 0 && src->device_extension_list.list->entrypoint_count > 0) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07002214 cnt = src->device_extension_list.list->entrypoint_count;
Mark Young0ad83132016-06-30 13:02:42 -06002215 dst->device_extension_list.list->entrypoints =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002216 loader_instance_heap_alloc(inst, sizeof(char *) * cnt, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0ad83132016-06-30 13:02:42 -06002217 if (NULL == dst->device_extension_list.list->entrypoints) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002218 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2219 "loader_copy_layer_properties: Failed to allocate space "
2220 "for device extension entrypoint list of size %d.",
Mark Youngb6399312017-01-10 14:22:15 -07002221 cnt);
Mark Young0ad83132016-06-30 13:02:42 -06002222 return VK_ERROR_OUT_OF_HOST_MEMORY;
2223 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002224 memset(dst->device_extension_list.list->entrypoints, 0, sizeof(char *) * cnt);
Mark Young0ad83132016-06-30 13:02:42 -06002225
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07002226 for (i = 0; i < cnt; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002227 dst->device_extension_list.list->entrypoints[i] = loader_instance_heap_alloc(
2228 inst, strlen(src->device_extension_list.list->entrypoints[i]) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0ad83132016-06-30 13:02:42 -06002229 if (NULL == dst->device_extension_list.list->entrypoints[i]) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002230 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2231 "loader_copy_layer_properties: Failed to "
2232 "allocate space for device extension entrypoint "
2233 "%d name of length",
Mark Youngb6399312017-01-10 14:22:15 -07002234 i);
Mark Young0ad83132016-06-30 13:02:42 -06002235 return VK_ERROR_OUT_OF_HOST_MEMORY;
2236 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002237 strcpy(dst->device_extension_list.list->entrypoints[i], src->device_extension_list.list->entrypoints[i]);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07002238 }
2239 }
Mark Young0ad83132016-06-30 13:02:42 -06002240
2241 return VK_SUCCESS;
Jon Ashburn3d002332015-08-20 16:35:30 -06002242}
2243
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002244static bool loader_find_layer_name_list(const char *name, const struct loader_layer_list *layer_list) {
Mark Youngf2079b92017-05-02 10:49:46 -06002245 if (NULL == layer_list) {
2246 return false;
2247 }
2248 for (uint32_t j = 0; j < layer_list->count; j++) {
2249 if (!strcmp(name, layer_list->list[j].info.layerName)) {
2250 return true;
2251 }
2252 }
Jon Ashburn86a527a2016-02-10 20:59:26 -07002253 return false;
2254}
2255
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002256bool 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 -07002257 if (!layer_list) return false;
Jon Ashburn86a527a2016-02-10 20:59:26 -07002258 for (uint32_t j = 0; j < layer_count; j++)
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002259 if (!strcmp(name, layer_list[j])) return true;
Jon Ashburn86a527a2016-02-10 20:59:26 -07002260 return false;
2261}
2262
Mark Youngf2079b92017-05-02 10:49:46 -06002263const char *std_validation_str = "VK_LAYER_LUNARG_standard_validation";
Jon Ashburn86a527a2016-02-10 20:59:26 -07002264
Mark Youngf2079b92017-05-02 10:49:46 -06002265// Adds the legacy VK_LAYER_LUNARG_standard_validation as a meta-layer if it
2266// fails to find it in the list already. This is usually an indication that a
2267// newer loader is being used with an older layer set.
2268static bool loader_add_legacy_std_val_layer(const struct loader_instance *inst, struct loader_layer_list *layer_instance_list) {
2269 uint32_t i;
2270 bool success = true;
2271 struct loader_layer_properties *props = loader_get_next_layer_property(inst, layer_instance_list);
2272 const char std_validation_names[6][VK_MAX_EXTENSION_NAME_SIZE] = {
Mark Youngc8b807a2017-07-14 17:11:31 -06002273 "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", "VK_LAYER_LUNARG_object_tracker",
2274 "VK_LAYER_LUNARG_core_validation", "VK_LAYER_GOOGLE_unique_objects"};
Mark Youngf2079b92017-05-02 10:49:46 -06002275 uint32_t layer_count = sizeof(std_validation_names) / sizeof(std_validation_names[0]);
2276
2277 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
2278 "Adding VK_LAYER_LUNARG_standard_validation using the loader legacy path. This is"
2279 " not an error.");
2280
2281 if (NULL == props) {
2282 goto out;
Jon Ashburn491cd042016-05-16 14:01:18 -06002283 }
Jon Ashburn71483442016-02-11 18:59:43 -07002284
Jon Ashburn491cd042016-05-16 14:01:18 -06002285 memset(props, 0, sizeof(struct loader_layer_properties));
Mark Youngf2079b92017-05-02 10:49:46 -06002286 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 -07002287 strncpy(props->info.description, "LunarG Standard Validation Layer", sizeof(props->info.description));
Jon Ashburn491cd042016-05-16 14:01:18 -06002288 props->info.implementationVersion = 1;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002289 strncpy(props->info.layerName, std_validation_str, sizeof(props->info.layerName));
Jon Ashburn491cd042016-05-16 14:01:18 -06002290 props->info.specVersion = VK_MAKE_VERSION(1, 0, VK_HEADER_VERSION);
Jon Ashburn491cd042016-05-16 14:01:18 -06002291
Mark Youngf2079b92017-05-02 10:49:46 -06002292 props->component_layer_names =
2293 loader_instance_heap_alloc(inst, sizeof(char[MAX_STRING_SIZE]) * layer_count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2294 if (NULL == props->component_layer_names) {
2295 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2296 "Failed to allocate space for legacy VK_LAYER_LUNARG_standard_validation"
2297 " meta-layer component_layers information.");
2298 success = false;
2299 goto out;
2300 }
Jon Ashburn491cd042016-05-16 14:01:18 -06002301 for (i = 0; i < layer_count; i++) {
Mark Youngf2079b92017-05-02 10:49:46 -06002302 strncpy(props->component_layer_names[i], std_validation_names[i], MAX_STRING_SIZE - 1);
2303 props->component_layer_names[i][MAX_STRING_SIZE - 1] = '\0';
Jon Ashburn86a527a2016-02-10 20:59:26 -07002304 }
Jon Ashburn491cd042016-05-16 14:01:18 -06002305
Mark Youngf2079b92017-05-02 10:49:46 -06002306out:
2307
2308 if (!success && NULL != props && NULL != props->component_layer_names) {
2309 loader_instance_heap_free(inst, props->component_layer_names);
2310 props->component_layer_names = NULL;
2311 }
2312
2313 return success;
2314}
2315
2316// Verify that all component layers in a meta-layer are valid.
2317static bool verify_meta_layer_comp_layers(const struct loader_instance *inst, struct loader_layer_properties *prop,
2318 struct loader_layer_list *instance_layers) {
2319 bool success = true;
Mark Youngc82a0622017-05-05 11:17:17 -06002320 const uint32_t expected_major = VK_VERSION_MAJOR(prop->info.specVersion);
2321 const uint32_t expected_minor = VK_VERSION_MINOR(prop->info.specVersion);
Mark Youngf2079b92017-05-02 10:49:46 -06002322
2323 for (uint32_t comp_layer = 0; comp_layer < prop->num_component_layers; comp_layer++) {
2324 if (!loader_find_layer_name_list(prop->component_layer_names[comp_layer], instance_layers)) {
2325 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2326 "Meta-layer %s can't find component layer %s at index %d."
2327 " Skipping this layer.",
2328 prop->info.layerName, prop->component_layer_names[comp_layer], comp_layer);
2329 success = false;
2330 break;
2331 } else {
2332 struct loader_layer_properties *comp_prop =
2333 loader_get_layer_property(prop->component_layer_names[comp_layer], instance_layers);
2334 if (comp_prop == NULL) {
2335 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2336 "Meta-layer %s can't find property for component layer %s at index %d."
2337 " Skipping this layer.",
2338 prop->info.layerName, prop->component_layer_names[comp_layer], comp_layer);
2339 success = false;
2340 break;
2341 }
2342
2343 // Check the version of each layer, they need to at least match MAJOR and MINOR
Mark Youngc82a0622017-05-05 11:17:17 -06002344 uint32_t cur_major = VK_VERSION_MAJOR(comp_prop->info.specVersion);
2345 uint32_t cur_minor = VK_VERSION_MINOR(comp_prop->info.specVersion);
2346 if (cur_major != expected_major || cur_minor != expected_minor) {
2347 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2348 "Meta-layer uses API version %d.%d, but component layer %d uses API "
2349 "version %d.%d. Skipping this layer.",
2350 expected_major, expected_minor, comp_layer, cur_major, cur_minor);
2351 success = false;
2352 break;
Mark Youngf2079b92017-05-02 10:49:46 -06002353 }
2354
2355 // Make sure the layer isn't using it's own name
2356 if (!strcmp(prop->info.layerName, prop->component_layer_names[comp_layer])) {
2357 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2358 "Meta-layer %s lists itself in its component layer list at index %d."
2359 " Skipping this layer.",
2360 prop->info.layerName, comp_layer);
2361 success = false;
2362 break;
2363 }
2364 if (comp_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) {
2365 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
2366 "verify_meta_layer_comp_layers: Adding meta-layer %s which also contains meta-layer %s",
2367 prop->info.layerName, comp_prop->info.layerName);
2368
2369 // Make sure if the layer is using a meta-layer in its component list that we also verify that.
2370 if (!verify_meta_layer_comp_layers(inst, comp_prop, instance_layers)) {
2371 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2372 "Meta-layer %s component layer %s can not find all component layers."
2373 " Skipping this layer.",
2374 prop->info.layerName, prop->component_layer_names[comp_layer]);
2375 success = false;
2376 break;
2377 }
2378 }
2379
2380 // Add any instance and device extensions from component layers to this layer
2381 // list, so that anyone querying extensions will only need to look at the meta-layer
2382 for (uint32_t ext = 0; ext < comp_prop->instance_extension_list.count; ext++) {
2383 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Meta-layer %s component layer %s adding instance extension %s",
2384 prop->info.layerName, prop->component_layer_names[comp_layer],
2385 comp_prop->instance_extension_list.list[ext].extensionName);
2386 if (!has_vk_extension_property(&comp_prop->instance_extension_list.list[ext], &prop->instance_extension_list)) {
2387 loader_add_to_ext_list(inst, &prop->instance_extension_list, 1, &comp_prop->instance_extension_list.list[ext]);
2388 }
2389 }
2390
2391 for (uint32_t ext = 0; ext < comp_prop->device_extension_list.count; ext++) {
2392 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Meta-layer %s component layer %s adding device extension %s",
2393 prop->info.layerName, prop->component_layer_names[comp_layer],
2394 comp_prop->device_extension_list.list[ext].props.extensionName);
2395 if (!has_vk_dev_ext_property(&comp_prop->device_extension_list.list[ext].props, &prop->device_extension_list)) {
2396 loader_add_to_dev_ext_list(inst, &prop->device_extension_list,
2397 &comp_prop->device_extension_list.list[ext].props, 0, NULL);
2398 }
2399 }
Mark Young0ad83132016-06-30 13:02:42 -06002400 }
Mark Youngf2079b92017-05-02 10:49:46 -06002401 }
2402 if (success) {
2403 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Meta-layer %s all %d component layers appear to be valid.",
2404 prop->info.layerName, prop->num_component_layers);
2405 }
2406 return success;
2407}
2408
2409// Verify that all meta-layers in a layer list are valid.
2410static void verify_all_meta_layers(const struct loader_instance *inst, struct loader_layer_list *instance_layers) {
Mark Young697317f2017-05-09 10:31:12 -06002411 for (int32_t i = 0; i < (int32_t)instance_layers->count; i++) {
Mark Youngf2079b92017-05-02 10:49:46 -06002412 struct loader_layer_properties *prop = &instance_layers->list[i];
2413
2414 // If this is a meta-layer, make sure it is valid
2415 if ((prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) && !verify_meta_layer_comp_layers(inst, prop, instance_layers)) {
2416 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
2417 "Removing meta-layer %s from instance layer list since it appears invalid.", prop->info.layerName);
2418
2419 // Delete the component layers
Mark Youngf2079b92017-05-02 10:49:46 -06002420 loader_instance_heap_free(inst, prop->component_layer_names);
Mark Youngf2079b92017-05-02 10:49:46 -06002421
Mark Young70ede4c2017-05-09 15:23:33 -06002422 // Remove the current invalid meta-layer from the layer list. Use memmove since we are
2423 // overlapping the source and destination addresses.
2424 memmove(&instance_layers->list[i], &instance_layers->list[i + 1],
2425 sizeof(struct loader_layer_properties) * (instance_layers->count - 1 - i));
Mark Youngf2079b92017-05-02 10:49:46 -06002426
Mark Young70ede4c2017-05-09 15:23:33 -06002427 // Decrement the count (because we now have one less) and decrement the loop index since we need to
2428 // re-check this index.
2429 instance_layers->count--;
Mark Young697317f2017-05-09 10:31:12 -06002430 i--;
Mark Youngf2079b92017-05-02 10:49:46 -06002431 }
Jon Ashburn491cd042016-05-16 14:01:18 -06002432 }
Jon Ashburn86a527a2016-02-10 20:59:26 -07002433}
2434
Mark Young39389872017-01-19 21:10:49 -07002435// This structure is used to store the json file version
Mark Youngdee312c2017-03-08 13:38:35 -07002436// in a more manageable way.
Mark Young39389872017-01-19 21:10:49 -07002437typedef struct {
2438 uint16_t major;
2439 uint16_t minor;
2440 uint16_t patch;
2441} layer_json_version;
2442
Lenny Komow3cf3ac72017-12-19 16:38:37 -07002443static inline bool is_valid_layer_json_version(const layer_json_version *layer_json) {
2444 // Supported versions are: 1.0.0, 1.0.1, 1.1.0, 1.1.1, and 1.1.2.
2445 if ((layer_json->major == 1 && layer_json->minor == 1 && layer_json->patch < 3) ||
2446 (layer_json->major == 1 && layer_json->minor == 0 && layer_json->patch < 2)) {
2447 return true;
2448 }
2449 return false;
2450}
2451
2452static inline bool layer_json_supports_layers_tag(const layer_json_version *layer_json) {
2453 // Supported versions started in 1.0.1, so anything newer
2454 if ((layer_json->major > 1 || layer_json->minor > 0 || layer_json->patch > 1)) {
2455 return true;
2456 }
2457 return false;
2458}
2459
2460static inline bool layer_json_supports_pre_instance_tag(const layer_json_version *layer_json) {
2461 // Supported versions started in 1.1.2, so anything newer
2462 return layer_json->major > 1 || layer_json->minor > 1 || (layer_json->minor == 1 && layer_json->patch > 1);
2463}
2464
Mark Youngf2079b92017-05-02 10:49:46 -06002465static VkResult loader_read_json_layer(const struct loader_instance *inst, struct loader_layer_list *layer_instance_list,
2466 cJSON *layer_node, layer_json_version version, cJSON *item, cJSON *disable_environment,
2467 bool is_implicit, char *filename) {
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002468 char *temp;
Mark Youngf2079b92017-05-02 10:49:46 -06002469 char *name, *type, *library_path_str, *api_version;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002470 char *implementation_version, *description;
Mark Youngf2079b92017-05-02 10:49:46 -06002471 cJSON *ext_item, *library_path, *component_layers;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002472 VkExtensionProperties ext_prop;
Mark Youngf2079b92017-05-02 10:49:46 -06002473 VkResult result = VK_ERROR_INITIALIZATION_FAILED;
2474 struct loader_layer_properties *props = NULL;
2475 int i, j;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002476
Mark Young0f183a82017-02-28 09:58:04 -07002477// The following are required in the "layer" object:
2478// (required) "name"
2479// (required) "type"
Nekotekinad431e132017-06-11 13:13:07 +03002480// (required) "library_path"
2481// (required) "api_version"
2482// (required) "implementation_version"
2483// (required) "description"
2484// (required for implicit layers) "disable_environment"
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002485#define GET_JSON_OBJECT(node, var) \
2486 { \
2487 var = cJSON_GetObjectItem(node, #var); \
2488 if (var == NULL) { \
2489 layer_node = layer_node->next; \
2490 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, \
2491 "Didn't find required layer object %s in manifest " \
2492 "JSON file, skipping this layer", \
2493 #var); \
Mark Youngf2079b92017-05-02 10:49:46 -06002494 goto out; \
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002495 } \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002496 }
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002497#define GET_JSON_ITEM(node, var) \
2498 { \
2499 item = cJSON_GetObjectItem(node, #var); \
2500 if (item == NULL) { \
2501 layer_node = layer_node->next; \
2502 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, \
2503 "Didn't find required layer value %s in manifest JSON " \
2504 "file, skipping this layer", \
2505 #var); \
Mark Youngf2079b92017-05-02 10:49:46 -06002506 goto out; \
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002507 } \
2508 temp = cJSON_Print(item); \
2509 if (temp == NULL) { \
2510 layer_node = layer_node->next; \
2511 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, \
2512 "Problem accessing layer value %s in manifest JSON " \
2513 "file, skipping this layer", \
2514 #var); \
Mark Youngf2079b92017-05-02 10:49:46 -06002515 result = VK_ERROR_OUT_OF_HOST_MEMORY; \
2516 goto out; \
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002517 } \
2518 temp[strlen(temp) - 1] = '\0'; \
2519 var = loader_stack_alloc(strlen(temp) + 1); \
2520 strcpy(var, &temp[1]); \
2521 cJSON_Free(temp); \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002522 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002523 GET_JSON_ITEM(layer_node, name)
2524 GET_JSON_ITEM(layer_node, type)
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002525 GET_JSON_ITEM(layer_node, api_version)
2526 GET_JSON_ITEM(layer_node, implementation_version)
2527 GET_JSON_ITEM(layer_node, description)
Mark Youngf2079b92017-05-02 10:49:46 -06002528
2529 // Add list entry
2530 if (!strcmp(type, "DEVICE")) {
2531 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, "Device layers are deprecated skipping this layer");
2532 layer_node = layer_node->next;
2533 goto out;
2534 }
2535
2536 // Allow either GLOBAL or INSTANCE type interchangeably to handle
2537 // layers that must work with older loaders
2538 if (!strcmp(type, "INSTANCE") || !strcmp(type, "GLOBAL")) {
2539 if (layer_instance_list == NULL) {
2540 layer_node = layer_node->next;
2541 goto out;
2542 }
2543 props = loader_get_next_layer_property(inst, layer_instance_list);
2544 if (NULL == props) {
2545 // Error already triggered in loader_get_next_layer_property.
2546 result = VK_ERROR_OUT_OF_HOST_MEMORY;
2547 goto out;
2548 }
2549 props->type_flags = VK_LAYER_TYPE_FLAG_INSTANCE_LAYER;
2550 if (!is_implicit) {
2551 props->type_flags |= VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER;
2552 }
2553 } else {
2554 layer_node = layer_node->next;
2555 goto out;
2556 }
2557
2558 // Library path no longer required unless component_layers is also not defined
2559 library_path = cJSON_GetObjectItem(layer_node, "library_path");
2560 component_layers = cJSON_GetObjectItem(layer_node, "component_layers");
2561 if (NULL != library_path) {
2562 if (NULL != component_layers) {
2563 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2564 "Indicating meta-layer-specific component_layers, but also "
2565 "defining layer library path. Both are not compatible, so "
2566 "skipping this layer");
2567 goto out;
2568 }
2569 props->num_component_layers = 0;
2570 props->component_layer_names = NULL;
2571
2572 temp = cJSON_Print(library_path);
2573 if (NULL == temp) {
2574 layer_node = layer_node->next;
2575 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2576 "Problem accessing layer value library_path in manifest JSON "
2577 "file, skipping this layer");
2578 result = VK_ERROR_OUT_OF_HOST_MEMORY;
2579 goto out;
2580 }
2581 temp[strlen(temp) - 1] = '\0';
2582 library_path_str = loader_stack_alloc(strlen(temp) + 1);
2583 strcpy(library_path_str, &temp[1]);
2584 cJSON_Free(temp);
2585
2586 char *fullpath = props->lib_name;
2587 char *rel_base;
2588 if (NULL != library_path_str) {
2589 if (loader_platform_is_path(library_path_str)) {
2590 // A relative or absolute path
2591 char *name_copy = loader_stack_alloc(strlen(filename) + 1);
2592 strcpy(name_copy, filename);
2593 rel_base = loader_platform_dirname(name_copy);
2594 loader_expand_path(library_path_str, rel_base, MAX_STRING_SIZE, fullpath);
2595 } else {
2596 // A filename which is assumed in a system directory
2597 loader_get_fullpath(library_path_str, DEFAULT_VK_LAYERS_PATH, MAX_STRING_SIZE, fullpath);
2598 }
2599 }
2600 } else if (NULL != component_layers) {
2601 if (version.major == 1 && (version.minor < 1 || version.patch < 1)) {
2602 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2603 "Indicating meta-layer-specific component_layers, but using older "
2604 "JSON file version.");
2605 }
2606 int count = cJSON_GetArraySize(component_layers);
2607 props->num_component_layers = count;
2608
2609 // Allocate buffer for layer names
2610 props->component_layer_names =
2611 loader_instance_heap_alloc(inst, sizeof(char[MAX_STRING_SIZE]) * count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2612 if (NULL == props->component_layer_names) {
2613 result = VK_ERROR_OUT_OF_HOST_MEMORY;
2614 goto out;
2615 }
2616
2617 // Copy the component layers into the array
2618 for (i = 0; i < count; i++) {
2619 cJSON *comp_layer = cJSON_GetArrayItem(component_layers, i);
2620 if (NULL != comp_layer) {
2621 temp = cJSON_Print(comp_layer);
2622 if (NULL == temp) {
2623 result = VK_ERROR_OUT_OF_HOST_MEMORY;
2624 goto out;
2625 }
2626 temp[strlen(temp) - 1] = '\0';
2627 strncpy(props->component_layer_names[i], temp + 1, MAX_STRING_SIZE - 1);
2628 props->component_layer_names[i][MAX_STRING_SIZE - 1] = '\0';
2629 cJSON_Free(temp);
2630 }
2631 }
2632
2633 // This is now, officially, a meta-layer
2634 props->type_flags |= VK_LAYER_TYPE_FLAG_META_LAYER;
2635 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Encountered meta-layer %s", name);
2636
2637 // Make sure we set up other things so we head down the correct branches below
2638 library_path_str = NULL;
2639 } else {
2640 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2641 "Layer missing both library_path and component_layers fields. One or the "
2642 "other MUST be defined. Skipping this layer");
2643 goto out;
2644 }
2645
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002646 if (is_implicit) {
2647 GET_JSON_OBJECT(layer_node, disable_environment)
2648 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002649#undef GET_JSON_ITEM
2650#undef GET_JSON_OBJECT
2651
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002652 strncpy(props->info.layerName, name, sizeof(props->info.layerName));
2653 props->info.layerName[sizeof(props->info.layerName) - 1] = '\0';
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002654 props->info.specVersion = loader_make_version(api_version);
2655 props->info.implementationVersion = atoi(implementation_version);
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002656 strncpy((char *)props->info.description, description, sizeof(props->info.description));
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002657 props->info.description[sizeof(props->info.description) - 1] = '\0';
2658 if (is_implicit) {
2659 if (!disable_environment || !disable_environment->child) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002660 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2661 "Didn't find required layer child value disable_environment"
2662 "in manifest JSON file, skipping this layer");
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002663 layer_node = layer_node->next;
Mark Youngf2079b92017-05-02 10:49:46 -06002664 goto out;
Jon Ashburnfb8ac012015-08-12 16:39:32 -06002665 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002666 strncpy(props->disable_env_var.name, disable_environment->child->string, sizeof(props->disable_env_var.name));
2667 props->disable_env_var.name[sizeof(props->disable_env_var.name) - 1] = '\0';
2668 strncpy(props->disable_env_var.value, disable_environment->child->valuestring, sizeof(props->disable_env_var.value));
2669 props->disable_env_var.value[sizeof(props->disable_env_var.value) - 1] = '\0';
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002670 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002671
Mark Young0f183a82017-02-28 09:58:04 -07002672// Now get all optional items and objects and put in list:
2673// functions
2674// instance_extensions
2675// device_extensions
2676// enable_environment (implicit layers only)
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002677#define GET_JSON_OBJECT(node, var) \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002678 { var = cJSON_GetObjectItem(node, #var); }
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002679#define GET_JSON_ITEM(node, var) \
2680 { \
2681 item = cJSON_GetObjectItem(node, #var); \
2682 if (item != NULL) { \
2683 temp = cJSON_Print(item); \
2684 if (temp != NULL) { \
2685 temp[strlen(temp) - 1] = '\0'; \
2686 var = loader_stack_alloc(strlen(temp) + 1); \
2687 strcpy(var, &temp[1]); \
2688 cJSON_Free(temp); \
Mark Youngf2079b92017-05-02 10:49:46 -06002689 } else { \
2690 result = VK_ERROR_OUT_OF_HOST_MEMORY; \
2691 goto out; \
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002692 } \
2693 } \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002694 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002695
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002696 cJSON *instance_extensions, *device_extensions, *functions, *enable_environment;
Mark Young39389872017-01-19 21:10:49 -07002697 cJSON *entrypoints = NULL;
2698 char *vkGetInstanceProcAddr = NULL;
2699 char *vkGetDeviceProcAddr = NULL;
2700 char *vkNegotiateLoaderLayerInterfaceVersion = NULL;
2701 char *spec_version = NULL;
2702 char **entry_array = NULL;
Jon Ashburn075ce432015-12-17 17:38:24 -07002703
Mark Young39389872017-01-19 21:10:49 -07002704 // Layer interface functions
2705 // vkGetInstanceProcAddr
2706 // vkGetDeviceProcAddr
2707 // vkNegotiateLoaderLayerInterfaceVersion (starting with JSON file 1.1.0)
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002708 GET_JSON_OBJECT(layer_node, functions)
2709 if (functions != NULL) {
Mark Young39389872017-01-19 21:10:49 -07002710 if (version.major > 1 || version.minor >= 1) {
2711 GET_JSON_ITEM(functions, vkNegotiateLoaderLayerInterfaceVersion)
2712 if (vkNegotiateLoaderLayerInterfaceVersion != NULL)
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002713 strncpy(props->functions.str_negotiate_interface, vkNegotiateLoaderLayerInterfaceVersion,
Mark Young39389872017-01-19 21:10:49 -07002714 sizeof(props->functions.str_negotiate_interface));
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002715 props->functions.str_negotiate_interface[sizeof(props->functions.str_negotiate_interface) - 1] = '\0';
Mark Young39389872017-01-19 21:10:49 -07002716 } else {
2717 props->functions.str_negotiate_interface[0] = '\0';
2718 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002719 GET_JSON_ITEM(functions, vkGetInstanceProcAddr)
2720 GET_JSON_ITEM(functions, vkGetDeviceProcAddr)
Mark Young39389872017-01-19 21:10:49 -07002721 if (vkGetInstanceProcAddr != NULL) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002722 strncpy(props->functions.str_gipa, vkGetInstanceProcAddr, sizeof(props->functions.str_gipa));
Mark Young39389872017-01-19 21:10:49 -07002723 if (version.major > 1 || version.minor >= 1) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002724 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2725 "Indicating layer-specific vkGetInstanceProcAddr "
2726 "function is deprecated starting with JSON file "
2727 "version 1.1.0. Instead, use the new "
2728 "vkNegotiateLayerInterfaceVersion function to "
2729 "return the GetInstanceProcAddr function for this"
2730 "layer");
Mark Young39389872017-01-19 21:10:49 -07002731 }
2732 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002733 props->functions.str_gipa[sizeof(props->functions.str_gipa) - 1] = '\0';
Mark Young39389872017-01-19 21:10:49 -07002734 if (vkGetDeviceProcAddr != NULL) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002735 strncpy(props->functions.str_gdpa, vkGetDeviceProcAddr, sizeof(props->functions.str_gdpa));
Mark Young39389872017-01-19 21:10:49 -07002736 if (version.major > 1 || version.minor >= 1) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002737 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2738 "Indicating layer-specific vkGetDeviceProcAddr "
2739 "function is deprecated starting with JSON file "
2740 "version 1.1.0. Instead, use the new "
2741 "vkNegotiateLayerInterfaceVersion function to "
2742 "return the GetDeviceProcAddr function for this"
2743 "layer");
Mark Young39389872017-01-19 21:10:49 -07002744 }
2745 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002746 props->functions.str_gdpa[sizeof(props->functions.str_gdpa) - 1] = '\0';
2747 }
Mark Young39389872017-01-19 21:10:49 -07002748
2749 // instance_extensions
2750 // array of {
2751 // name
2752 // spec_version
2753 // }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002754 GET_JSON_OBJECT(layer_node, instance_extensions)
2755 if (instance_extensions != NULL) {
2756 int count = cJSON_GetArraySize(instance_extensions);
2757 for (i = 0; i < count; i++) {
2758 ext_item = cJSON_GetArrayItem(instance_extensions, i);
2759 GET_JSON_ITEM(ext_item, name)
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002760 if (name != NULL) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002761 strncpy(ext_prop.extensionName, name, sizeof(ext_prop.extensionName));
2762 ext_prop.extensionName[sizeof(ext_prop.extensionName) - 1] = '\0';
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002763 }
Mark Young0ad83132016-06-30 13:02:42 -06002764 GET_JSON_ITEM(ext_item, spec_version)
2765 if (NULL != spec_version) {
2766 ext_prop.specVersion = atoi(spec_version);
2767 } else {
2768 ext_prop.specVersion = 0;
2769 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002770 bool ext_unsupported = wsi_unsupported_instance_extension(&ext_prop);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002771 if (!ext_unsupported) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002772 loader_add_to_ext_list(inst, &props->instance_extension_list, 1, &ext_prop);
Jon Ashburn075ce432015-12-17 17:38:24 -07002773 }
Jon Ashburnfb8ac012015-08-12 16:39:32 -06002774 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002775 }
Mark Young39389872017-01-19 21:10:49 -07002776
2777 // device_extensions
2778 // array of {
2779 // name
2780 // spec_version
2781 // entrypoints
2782 // }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002783 GET_JSON_OBJECT(layer_node, device_extensions)
2784 if (device_extensions != NULL) {
2785 int count = cJSON_GetArraySize(device_extensions);
2786 for (i = 0; i < count; i++) {
2787 ext_item = cJSON_GetArrayItem(device_extensions, i);
2788 GET_JSON_ITEM(ext_item, name)
2789 GET_JSON_ITEM(ext_item, spec_version)
2790 if (name != NULL) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002791 strncpy(ext_prop.extensionName, name, sizeof(ext_prop.extensionName));
2792 ext_prop.extensionName[sizeof(ext_prop.extensionName) - 1] = '\0';
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002793 }
Mark Young0ad83132016-06-30 13:02:42 -06002794 if (NULL != spec_version) {
2795 ext_prop.specVersion = atoi(spec_version);
2796 } else {
2797 ext_prop.specVersion = 0;
2798 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002799 // entrypoints = cJSON_GetObjectItem(ext_item, "entrypoints");
2800 GET_JSON_OBJECT(ext_item, entrypoints)
2801 int entry_count;
2802 if (entrypoints == NULL) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002803 loader_add_to_dev_ext_list(inst, &props->device_extension_list, &ext_prop, 0, NULL);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002804 continue;
2805 }
2806 entry_count = cJSON_GetArraySize(entrypoints);
Mark Young0ad83132016-06-30 13:02:42 -06002807 if (entry_count) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002808 entry_array = (char **)loader_stack_alloc(sizeof(char *) * entry_count);
Mark Young0ad83132016-06-30 13:02:42 -06002809 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002810 for (j = 0; j < entry_count; j++) {
2811 ext_item = cJSON_GetArrayItem(entrypoints, j);
2812 if (ext_item != NULL) {
2813 temp = cJSON_Print(ext_item);
Mark Young0ad83132016-06-30 13:02:42 -06002814 if (NULL == temp) {
2815 entry_array[j] = NULL;
Mark Youngf2079b92017-05-02 10:49:46 -06002816 result = VK_ERROR_OUT_OF_HOST_MEMORY;
2817 goto out;
Mark Young0ad83132016-06-30 13:02:42 -06002818 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002819 temp[strlen(temp) - 1] = '\0';
2820 entry_array[j] = loader_stack_alloc(strlen(temp) + 1);
2821 strcpy(entry_array[j], &temp[1]);
Mark Young0ad83132016-06-30 13:02:42 -06002822 cJSON_Free(temp);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002823 }
2824 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002825 loader_add_to_dev_ext_list(inst, &props->device_extension_list, &ext_prop, entry_count, entry_array);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002826 }
2827 }
2828 if (is_implicit) {
2829 GET_JSON_OBJECT(layer_node, enable_environment)
2830
2831 // enable_environment is optional
2832 if (enable_environment) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002833 strncpy(props->enable_env_var.name, enable_environment->child->string, sizeof(props->enable_env_var.name));
2834 props->enable_env_var.name[sizeof(props->enable_env_var.name) - 1] = '\0';
2835 strncpy(props->enable_env_var.value, enable_environment->child->valuestring, sizeof(props->enable_env_var.value));
2836 props->enable_env_var.value[sizeof(props->enable_env_var.value) - 1] = '\0';
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002837 }
2838 }
Mark Youngf2079b92017-05-02 10:49:46 -06002839
Lenny Komow3cf3ac72017-12-19 16:38:37 -07002840 // Read in the pre-instance stuff
2841 cJSON *pre_instance = cJSON_GetObjectItem(layer_node, "pre_instance_functions");
2842 if (pre_instance) {
2843 if (!layer_json_supports_pre_instance_tag(&version)) {
2844 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2845 "Found pre_instance_functions section in layer from \"%s\". "
2846 "This section is only valid in manifest version 1.1.2 or later. The section will be ignored",
2847 filename);
2848 } else if (!is_implicit) {
2849 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2850 "Found pre_instance_functions section in explicit layer from "
2851 "\"%s\". This section is only valid in implicit layers. The section will be ignored",
2852 filename);
2853 } else {
2854 cJSON *inst_ext_json = cJSON_GetObjectItem(pre_instance, "vkEnumerateInstanceExtensionProperties");
2855 if (inst_ext_json) {
2856 char *inst_ext_name = cJSON_Print(inst_ext_json);
2857 size_t len = strlen(inst_ext_name) >= MAX_STRING_SIZE ? MAX_STRING_SIZE - 3 : strlen(inst_ext_name) - 2;
2858 strncpy(props->pre_instance_functions.enumerate_instance_extension_properties, inst_ext_name + 1, len);
2859 props->pre_instance_functions.enumerate_instance_extension_properties[len] = '\0';
2860 cJSON_Free(inst_ext_name);
2861 }
2862
2863 cJSON *inst_layer_json = cJSON_GetObjectItem(pre_instance, "vkEnumerateInstanceLayerProperties");
2864 if (inst_layer_json) {
2865 char *inst_layer_name = cJSON_Print(inst_layer_json);
2866 size_t len = strlen(inst_layer_name) >= MAX_STRING_SIZE ? MAX_STRING_SIZE - 3 : strlen(inst_layer_name) - 2;
2867 strncpy(props->pre_instance_functions.enumerate_instance_layer_properties, inst_layer_name + 1, len);
2868 props->pre_instance_functions.enumerate_instance_layer_properties[len] = '\0';
2869 cJSON_Free(inst_layer_name);
2870 }
Lenny Komow16586112018-02-13 15:58:47 -07002871
2872 cJSON *inst_version_json = cJSON_GetObjectItem(pre_instance, "vkEnumerateInstanceVersion");
2873 if (inst_version_json) {
2874 char *inst_version_name = cJSON_Print(inst_version_json);
2875 size_t len = strlen(inst_version_name) >= MAX_STRING_SIZE ? MAX_STRING_SIZE - 3 : strlen(inst_version_name) - 2;
2876 strncpy(props->pre_instance_functions.enumerate_instance_version, inst_version_name + 1, len);
2877 props->pre_instance_functions.enumerate_instance_version[len] = '\0';
2878 cJSON_Free(inst_version_name);
2879 }
Lenny Komow3cf3ac72017-12-19 16:38:37 -07002880 }
2881 }
2882
Mark Youngf2079b92017-05-02 10:49:46 -06002883 result = VK_SUCCESS;
2884
2885out:
2886
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002887#undef GET_JSON_ITEM
2888#undef GET_JSON_OBJECT
Mark Youngf2079b92017-05-02 10:49:46 -06002889
2890 if (VK_SUCCESS != result && NULL != props) {
2891 props->num_component_layers = 0;
2892 if (NULL != props->component_layer_names) {
2893 loader_instance_heap_free(inst, props->component_layer_names);
2894 }
2895 props->component_layer_names = NULL;
2896 }
2897
2898 return result;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002899}
2900
Mark Young0f183a82017-02-28 09:58:04 -07002901// Given a cJSON struct (json) of the top level JSON object from layer manifest
2902// file, add entry to the layer_list. Fill out the layer_properties in this list
2903// entry from the input cJSON object.
2904//
2905// \returns
2906// void
2907// layer_list has a new entry and initialized accordingly.
2908// If the json input object does not have all the required fields no entry
2909// is added to the list.
Mark Youngf2079b92017-05-02 10:49:46 -06002910static VkResult loader_add_layer_properties(const struct loader_instance *inst, struct loader_layer_list *layer_instance_list,
2911 cJSON *json, bool is_implicit, char *filename) {
Mark Young39389872017-01-19 21:10:49 -07002912 // The following Fields in layer manifest file that are required:
Nekotekinad431e132017-06-11 13:13:07 +03002913 // - "file_format_version"
Mark Young39389872017-01-19 21:10:49 -07002914 // - If more than one "layer" object are used, then the "layers" array is
Mark Youngdee312c2017-03-08 13:38:35 -07002915 // required
Mark Youngf2079b92017-05-02 10:49:46 -06002916 VkResult result = VK_ERROR_INITIALIZATION_FAILED;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002917 cJSON *item, *layers_node, *layer_node;
Mike Stroyan81908212017-03-14 13:09:12 -06002918 layer_json_version json_version = {0, 0, 0};
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002919 char *vers_tok;
2920 cJSON *disable_environment = NULL;
2921 item = cJSON_GetObjectItem(json, "file_format_version");
2922 if (item == NULL) {
Mark Youngf2079b92017-05-02 10:49:46 -06002923 goto out;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002924 }
2925 char *file_vers = cJSON_PrintUnformatted(item);
Mark Young0ad83132016-06-30 13:02:42 -06002926 if (NULL == file_vers) {
Mark Youngf2079b92017-05-02 10:49:46 -06002927 goto out;
Mark Young0ad83132016-06-30 13:02:42 -06002928 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002929 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 -06002930 // Get the major/minor/and patch as integers for easier comparison
2931 vers_tok = strtok(file_vers, ".\"\n\r");
2932 if (NULL != vers_tok) {
Mark Young39389872017-01-19 21:10:49 -07002933 json_version.major = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002934 vers_tok = strtok(NULL, ".\"\n\r");
2935 if (NULL != vers_tok) {
Mark Young39389872017-01-19 21:10:49 -07002936 json_version.minor = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002937 vers_tok = strtok(NULL, ".\"\n\r");
2938 if (NULL != vers_tok) {
Mark Young39389872017-01-19 21:10:49 -07002939 json_version.patch = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002940 }
2941 }
2942 }
Mark Young39389872017-01-19 21:10:49 -07002943
2944 if (!is_valid_layer_json_version(&json_version)) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002945 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2946 "loader_add_layer_properties: %s invalid layer "
Mark Youngf2079b92017-05-02 10:49:46 -06002947 "manifest file version %d.%d.%d. May cause errors.",
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002948 filename, json_version.major, json_version.minor, json_version.patch);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002949 }
Mark Young0ad83132016-06-30 13:02:42 -06002950 cJSON_Free(file_vers);
Mark Young39389872017-01-19 21:10:49 -07002951
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002952 // If "layers" is present, read in the array of layer objects
2953 layers_node = cJSON_GetObjectItem(json, "layers");
2954 if (layers_node != NULL) {
2955 int numItems = cJSON_GetArraySize(layers_node);
Mark Young39389872017-01-19 21:10:49 -07002956 if (!layer_json_supports_layers_tag(&json_version)) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002957 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2958 "loader_add_layer_properties: \'layers\' tag not "
2959 "supported until file version 1.0.1, but %s is "
2960 "reporting version %s",
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002961 filename, file_vers);
2962 }
2963 for (int curLayer = 0; curLayer < numItems; curLayer++) {
2964 layer_node = cJSON_GetArrayItem(layers_node, curLayer);
2965 if (layer_node == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002966 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2967 "loader_add_layer_properties: Can not find "
2968 "\'layers\' array element %d object in manifest "
2969 "JSON file %s. Skipping this file",
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002970 curLayer, filename);
Mark Youngf2079b92017-05-02 10:49:46 -06002971 goto out;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002972 }
Mark Youngf2079b92017-05-02 10:49:46 -06002973 result = loader_read_json_layer(inst, layer_instance_list, layer_node, json_version, item, disable_environment,
2974 is_implicit, filename);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002975 }
2976 } else {
2977 // Otherwise, try to read in individual layers
2978 layer_node = cJSON_GetObjectItem(json, "layer");
2979 if (layer_node == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002980 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2981 "loader_add_layer_properties: Can not find \'layer\' "
2982 "object in manifest JSON file %s. Skipping this file.",
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002983 filename);
Mark Youngf2079b92017-05-02 10:49:46 -06002984 goto out;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002985 }
2986 // Loop through all "layer" objects in the file to get a count of them
2987 // first.
2988 uint16_t layer_count = 0;
2989 cJSON *tempNode = layer_node;
2990 do {
2991 tempNode = tempNode->next;
2992 layer_count++;
2993 } while (tempNode != NULL);
Mark Young39389872017-01-19 21:10:49 -07002994
2995 // Throw a warning if we encounter multiple "layer" objects in file
2996 // versions newer than 1.0.0. Having multiple objects with the same
2997 // name at the same level is actually a JSON standard violation.
2998 if (layer_count > 1 && layer_json_supports_layers_tag(&json_version)) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002999 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3000 "loader_add_layer_properties: Multiple \'layer\' nodes"
3001 " are deprecated starting in file version \"1.0.1\". "
3002 "Please use \'layers\' : [] array instead in %s.",
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003003 filename);
3004 } else {
3005 do {
Mark Youngf2079b92017-05-02 10:49:46 -06003006 result = loader_read_json_layer(inst, layer_instance_list, layer_node, json_version, item, disable_environment,
3007 is_implicit, filename);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003008 layer_node = layer_node->next;
3009 } while (layer_node != NULL);
3010 }
3011 }
Mark Youngf2079b92017-05-02 10:49:46 -06003012
3013out:
3014
3015 return result;
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003016}
3017
Mark Young0f183a82017-02-28 09:58:04 -07003018// Find the Vulkan library manifest files.
3019//
3020// This function scans the "location" or "env_override" directories/files
3021// for a list of JSON manifest files. If env_override is non-NULL
3022// and has a valid value. Then the location is ignored. Otherwise
3023// location is used to look for manifest files. The location
3024// is interpreted as Registry path on Windows and a directory path(s)
3025// on Linux. "home_location" is an additional directory in the users home
3026// directory to look at. It is expanded into the dir path
3027// $XDG_DATA_HOME/home_location or $HOME/.local/share/home_location depending
3028// on environment variables. This "home_location" is only used on Linux.
3029//
3030// \returns
3031// VKResult
3032// A string list of manifest files to be opened in out_files param.
3033// List has a pointer to string for each manifest filename.
3034// When done using the list in out_files, pointers should be freed.
3035// Location or override string lists can be either files or directories as
Mark Youngf2079b92017-05-02 10:49:46 -06003036// follows:
Mark Young0f183a82017-02-28 09:58:04 -07003037// | location | override
3038// --------------------------------
3039// Win ICD | files | files
3040// Win Layer | files | dirs
3041// Linux ICD | dirs | files
3042// Linux Layer| dirs | dirs
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003043static 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 -06003044 bool is_layer, bool warn_if_not_present, const char *location,
3045 const char *relative_location, struct loader_manifest_files *out_files) {
Mark Youngbb3a29c2017-05-19 12:29:43 -06003046 const char *override = NULL;
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05003047 char *override_getenv = NULL;
Mark Young0ad83132016-06-30 13:02:42 -06003048 char *loc, *orig_loc = NULL;
3049 char *reg = NULL;
Jon Ashburn2077e382015-06-29 11:25:34 -06003050 char *file, *next_file, *name;
3051 size_t alloced_count = 64;
3052 char full_path[2048];
3053 DIR *sysdir = NULL;
Jon Ashburnffad94d2015-06-30 14:46:22 -07003054 bool list_is_dirs = false;
Jon Ashburn2077e382015-06-29 11:25:34 -06003055 struct dirent *dent;
Mark Young0ad83132016-06-30 13:02:42 -06003056 VkResult res = VK_SUCCESS;
Jon Ashburn2077e382015-06-29 11:25:34 -06003057
3058 out_files->count = 0;
3059 out_files->filename_list = NULL;
3060
Jamie Madill00c3c912016-04-06 18:26:46 -04003061 if (source_override != NULL) {
3062 override = source_override;
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05003063 } else if (env_override != NULL) {
Johannes van Waveren9bd805012015-10-28 11:45:00 -05003064#if !defined(_WIN32)
Jon Ashburncc407a22016-04-15 09:25:03 -06003065 if (geteuid() != getuid() || getegid() != getgid()) {
Mark Young0f183a82017-02-28 09:58:04 -07003066 // Don't allow setuid apps to use the env var:
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05003067 env_override = NULL;
Jon Ashburn2077e382015-06-29 11:25:34 -06003068 }
3069#endif
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05003070 if (env_override != NULL) {
Mark Youngd8c6b692017-03-09 11:39:41 -07003071 override = override_getenv = loader_secure_getenv(env_override, inst);
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05003072 }
Jon Ashburn2077e382015-06-29 11:25:34 -06003073 }
Jon Ashburnb6822212016-02-16 15:34:16 -07003074#if !defined(_WIN32)
Benjamin Saunders31a48012017-01-29 14:49:54 -08003075 if (relative_location == NULL) {
Jon Ashburnb6822212016-02-16 15:34:16 -07003076#else
Benjamin Saunders31a48012017-01-29 14:49:54 -08003077 relative_location = NULL;
Jon Ashburn2077e382015-06-29 11:25:34 -06003078 if (location == NULL) {
Jon Ashburnb6822212016-02-16 15:34:16 -07003079#endif
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003080 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3081 "loader_get_manifest_files: Can not get manifest files with "
3082 "NULL location, env_override=%s",
Mark Youngb6399312017-01-10 14:22:15 -07003083 (env_override != NULL) ? env_override : "");
Mark Young0ad83132016-06-30 13:02:42 -06003084 res = VK_ERROR_INITIALIZATION_FAILED;
3085 goto out;
Jon Ashburn2077e382015-06-29 11:25:34 -06003086 }
3087
Johannes van Waveren9bd805012015-10-28 11:45:00 -05003088#if defined(_WIN32)
Jon Ashburnffad94d2015-06-30 14:46:22 -07003089 list_is_dirs = (is_layer && override != NULL) ? true : false;
Johannes van Waveren9bd805012015-10-28 11:45:00 -05003090#else
3091 list_is_dirs = (override == NULL || is_layer) ? true : false;
Jon Ashburnffad94d2015-06-30 14:46:22 -07003092#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06003093 // Make a copy of the input we are using so it is not modified
Jon Ashburnffad94d2015-06-30 14:46:22 -07003094 // Also handle getting the location(s) from registry on Windows
3095 if (override == NULL) {
Benjamin Saunders31a48012017-01-29 14:49:54 -08003096 size_t loc_size = 0;
3097#if !defined(_WIN32)
Mark Youngd8c6b692017-03-09 11:39:41 -07003098 const char *xdgconfdirs = loader_secure_getenv("XDG_CONFIG_DIRS", inst);
3099 const char *xdgdatadirs = loader_secure_getenv("XDG_DATA_DIRS", inst);
Mark Youngf2079b92017-05-02 10:49:46 -06003100 if (xdgconfdirs == NULL || xdgconfdirs[0] == '\0') xdgconfdirs = FALLBACK_CONFIG_DIRS;
3101 if (xdgdatadirs == NULL || xdgdatadirs[0] == '\0') xdgdatadirs = FALLBACK_DATA_DIRS;
Benjamin Saunders31a48012017-01-29 14:49:54 -08003102 const size_t rel_size = strlen(relative_location);
3103 // Leave space for trailing separators
Mark Youngf2079b92017-05-02 10:49:46 -06003104 loc_size += strlen(xdgconfdirs) + strlen(xdgdatadirs) + 2 * rel_size + 2;
Benjamin Saunders31a48012017-01-29 14:49:54 -08003105 for (const char *x = xdgconfdirs; *x; ++x)
3106 if (*x == PATH_SEPARATOR) loc_size += rel_size;
3107 for (const char *x = xdgdatadirs; *x; ++x)
3108 if (*x == PATH_SEPARATOR) loc_size += rel_size;
3109 loc_size += strlen(SYSCONFDIR) + rel_size + 1;
3110#if defined(EXTRASYSCONFDIR)
3111 loc_size += strlen(EXTRASYSCONFDIR) + rel_size + 1;
3112#endif
Karl Schultz2e5ed332017-12-12 10:33:01 -05003113#if defined(__APPLE__)
3114 // For bundle path
3115 loc_size += MAXPATHLEN;
3116#endif
Benjamin Saunders31a48012017-01-29 14:49:54 -08003117#else
3118 loc_size += strlen(location) + 1;
3119#endif
3120 loc = loader_stack_alloc(loc_size);
Jon Ashburnffad94d2015-06-30 14:46:22 -07003121 if (loc == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003122 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3123 "loader_get_manifest_files: Failed to allocate "
3124 "%d bytes for manifest file location.",
Benjamin Saunders31a48012017-01-29 14:49:54 -08003125 loc_size);
Mark Young0ad83132016-06-30 13:02:42 -06003126 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3127 goto out;
Jon Ashburnffad94d2015-06-30 14:46:22 -07003128 }
Benjamin Saunders31a48012017-01-29 14:49:54 -08003129 char *loc_write = loc;
3130#if !defined(_WIN32)
3131 const char *loc_read;
Karl Schultz52f5daa2017-02-12 12:34:03 -07003132 size_t start, stop;
Benjamin Saunders31a48012017-01-29 14:49:54 -08003133
Karl Schultz2e5ed332017-12-12 10:33:01 -05003134#if defined(__APPLE__)
3135 // Add the bundle's Resources dir to the beginning of the search path.
3136 // Looks for manifests in the bundle first, before any system directories.
3137 CFBundleRef main_bundle = CFBundleGetMainBundle();
3138 if (NULL != main_bundle) {
3139 CFURLRef ref = CFBundleCopyResourcesDirectoryURL(main_bundle);
3140 if (NULL != ref) {
3141 if (CFURLGetFileSystemRepresentation(ref, TRUE, (UInt8 *)loc_write, loc_size)) {
3142 loc_write += strlen(loc_write);
3143 memcpy(loc_write, relative_location, rel_size);
3144 loc_write += rel_size;
3145 *loc_write++ = PATH_SEPARATOR;
3146 }
3147 CFRelease(ref);
3148 }
3149 }
3150#endif
Benjamin Saunders31a48012017-01-29 14:49:54 -08003151 loc_read = &xdgconfdirs[0];
Karl Schultz52f5daa2017-02-12 12:34:03 -07003152 start = 0;
3153 while (loc_read[start] != '\0') {
3154 while (loc_read[start] == PATH_SEPARATOR) {
3155 start++;
3156 }
3157 stop = start;
3158 while (loc_read[stop] != PATH_SEPARATOR && loc_read[stop] != '\0') {
3159 stop++;
3160 }
3161 const size_t s = stop - start;
3162 if (s) {
3163 memcpy(loc_write, &loc_read[start], s);
Benjamin Saunders31a48012017-01-29 14:49:54 -08003164 loc_write += s;
3165 memcpy(loc_write, relative_location, rel_size);
3166 loc_write += rel_size;
3167 *loc_write++ = PATH_SEPARATOR;
Karl Schultz52f5daa2017-02-12 12:34:03 -07003168 start = stop;
Benjamin Saunders31a48012017-01-29 14:49:54 -08003169 }
3170 }
3171
3172 memcpy(loc_write, SYSCONFDIR, strlen(SYSCONFDIR));
3173 loc_write += strlen(SYSCONFDIR);
3174 memcpy(loc_write, relative_location, rel_size);
3175 loc_write += rel_size;
3176 *loc_write++ = PATH_SEPARATOR;
3177
3178#if defined(EXTRASYSCONFDIR)
3179 memcpy(loc_write, EXTRASYSCONFDIR, strlen(EXTRASYSCONFDIR));
3180 loc_write += strlen(EXTRASYSCONFDIR);
3181 memcpy(loc_write, relative_location, rel_size);
3182 loc_write += rel_size;
3183 *loc_write++ = PATH_SEPARATOR;
3184#endif
3185
3186 loc_read = &xdgdatadirs[0];
Karl Schultz52f5daa2017-02-12 12:34:03 -07003187 start = 0;
3188 while (loc_read[start] != '\0') {
3189 while (loc_read[start] == PATH_SEPARATOR) {
3190 start++;
3191 }
3192 stop = start;
3193 while (loc_read[stop] != PATH_SEPARATOR && loc_read[stop] != '\0') {
3194 stop++;
3195 }
3196 const size_t s = stop - start;
3197 if (s) {
3198 memcpy(loc_write, &loc_read[start], s);
Benjamin Saunders31a48012017-01-29 14:49:54 -08003199 loc_write += s;
3200 memcpy(loc_write, relative_location, rel_size);
3201 loc_write += rel_size;
3202 *loc_write++ = PATH_SEPARATOR;
Karl Schultz52f5daa2017-02-12 12:34:03 -07003203 start = stop;
Benjamin Saunders31a48012017-01-29 14:49:54 -08003204 }
3205 }
Karl Schultz52f5daa2017-02-12 12:34:03 -07003206
Benjamin Saunders31a48012017-01-29 14:49:54 -08003207 --loc_write;
3208#else
3209 memcpy(loc_write, location, strlen(location));
3210 loc_write += strlen(location);
3211#endif
3212 assert(loc_write - loc < (ptrdiff_t)loc_size);
3213 *loc_write = '\0';
3214
Johannes van Waveren9bd805012015-10-28 11:45:00 -05003215#if defined(_WIN32)
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +02003216 VkResult regHKR_result = VK_SUCCESS;
3217
Slawomir Cygan8f9f2552017-08-09 11:36:52 +02003218 DWORD reg_size = 4096;
3219
Norbert Garnys7dc9a592018-02-13 16:32:03 +01003220 // These calls look at the PNP/Device section of the registry.
Lenny Komowf7c09382017-08-31 16:35:08 -06003221 if (!strncmp(loc, DEFAULT_VK_DRIVERS_INFO, sizeof(DEFAULT_VK_DRIVERS_INFO))) {
3222 regHKR_result = loaderGetDeviceRegistryFiles(inst, &reg, &reg_size, LoaderPnpDriverRegistry());
3223 } else if (!strncmp(loc, DEFAULT_VK_ELAYERS_INFO, sizeof(DEFAULT_VK_ELAYERS_INFO))) {
3224 regHKR_result = loaderGetDeviceRegistryFiles(inst, &reg, &reg_size, LoaderPnpELayerRegistry());
3225 } else if (!strncmp(loc, DEFAULT_VK_ILAYERS_INFO, sizeof(DEFAULT_VK_ILAYERS_INFO))) {
3226 regHKR_result = loaderGetDeviceRegistryFiles(inst, &reg, &reg_size, LoaderPnpILayerRegistry());
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +02003227 }
3228
Norbert Garnys7dc9a592018-02-13 16:32:03 +01003229 // This call looks into the Khronos non-device specific section of the registry.
Slawomir Cygan8f9f2552017-08-09 11:36:52 +02003230 VkResult reg_result = loaderGetRegistryFiles(inst, loc, is_layer, &reg, &reg_size);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +02003231
3232 if ((VK_SUCCESS != reg_result && VK_SUCCESS != regHKR_result) || NULL == reg) {
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07003233 if (!is_layer) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003234 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3235 "loader_get_manifest_files: Registry lookup failed "
3236 "to get ICD manifest files. Possibly missing Vulkan"
3237 " driver?");
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +02003238 if (VK_SUCCESS == regHKR_result || VK_ERROR_OUT_OF_HOST_MEMORY == regHKR_result) {
3239 res = regHKR_result;
3240 } else if (VK_SUCCESS == reg_result || VK_ERROR_OUT_OF_HOST_MEMORY == reg_result) {
Mark Young2c84c0c2017-01-13 10:27:03 -07003241 res = reg_result;
3242 } else {
3243 res = VK_ERROR_INCOMPATIBLE_DRIVER;
3244 }
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07003245 } else {
Mark Youngf8c20102016-11-07 16:26:17 -07003246 if (warn_if_not_present) {
Mark Young2c84c0c2017-01-13 10:27:03 -07003247 // This is only a warning for layers
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003248 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3249 "loader_get_manifest_files: Registry lookup failed "
3250 "to get layer manifest files.");
Mark Youngf8c20102016-11-07 16:26:17 -07003251 }
Mark Young2c84c0c2017-01-13 10:27:03 -07003252 if (reg_result == VK_ERROR_OUT_OF_HOST_MEMORY) {
3253 res = reg_result;
3254 } else {
3255 // Return success for now since it's not critical for layers
3256 res = VK_SUCCESS;
3257 }
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07003258 }
Mark Young0ad83132016-06-30 13:02:42 -06003259 goto out;
Jon Ashburn24265ac2015-07-31 09:33:21 -06003260 }
Mark Young0ad83132016-06-30 13:02:42 -06003261 orig_loc = loc;
3262 loc = reg;
Jon Ashburnffad94d2015-06-30 14:46:22 -07003263#endif
Jon Ashburn23d36b12016-02-02 17:47:28 -07003264 } else {
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -06003265 loc = loader_stack_alloc(strlen(override) + 1);
Jon Ashburnffad94d2015-06-30 14:46:22 -07003266 if (loc == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003267 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3268 "loader_get_manifest_files: Failed to allocate space for "
3269 "override environment variable of length %d",
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003270 strlen(override) + 1);
Mark Young0ad83132016-06-30 13:02:42 -06003271 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3272 goto out;
Jon Ashburnffad94d2015-06-30 14:46:22 -07003273 }
3274 strcpy(loc, override);
3275 }
Jon Ashburn2077e382015-06-29 11:25:34 -06003276
Liam Middlebrook9b14e892015-07-23 18:32:20 -07003277 // Print out the paths being searched if debugging is enabled
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003278 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 -07003279
Jon Ashburn2077e382015-06-29 11:25:34 -06003280 file = loc;
3281 while (*file) {
3282 next_file = loader_get_next_path(file);
Jon Ashburnffad94d2015-06-30 14:46:22 -07003283 if (list_is_dirs) {
Jon Ashburn2077e382015-06-29 11:25:34 -06003284 sysdir = opendir(file);
3285 name = NULL;
3286 if (sysdir) {
3287 dent = readdir(sysdir);
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003288 if (dent == NULL) break;
Jon Ashburn2077e382015-06-29 11:25:34 -06003289 name = &(dent->d_name[0]);
3290 loader_get_fullpath(name, file, sizeof(full_path), full_path);
3291 name = full_path;
3292 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07003293 } else {
Johannes van Waveren9bd805012015-10-28 11:45:00 -05003294#if defined(_WIN32)
3295 name = file;
3296#else
Jon Ashburnffad94d2015-06-30 14:46:22 -07003297 // only Linux has relative paths
Jon Ashburn2077e382015-06-29 11:25:34 -06003298 char *dir;
3299 // make a copy of location so it isn't modified
Jason Ekstrandcc7550e2015-10-10 08:33:37 -07003300 dir = loader_stack_alloc(strlen(loc) + 1);
Jon Ashburn2077e382015-06-29 11:25:34 -06003301 if (dir == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003302 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3303 "loader_get_manifest_files: Failed to allocate "
3304 "space for relative location path length %d",
Mark Youngb6399312017-01-10 14:22:15 -07003305 strlen(loc) + 1);
Mark Young0ad83132016-06-30 13:02:42 -06003306 goto out;
Jon Ashburn2077e382015-06-29 11:25:34 -06003307 }
Jason Ekstrandcc7550e2015-10-10 08:33:37 -07003308 strcpy(dir, loc);
Jon Ashburn2077e382015-06-29 11:25:34 -06003309
3310 loader_get_fullpath(file, dir, sizeof(full_path), full_path);
3311
3312 name = full_path;
Jon Ashburnffad94d2015-06-30 14:46:22 -07003313#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06003314 }
3315 while (name) {
Mark Young0f183a82017-02-28 09:58:04 -07003316 // Look for files ending with ".json" suffix
Jon Ashburn23d36b12016-02-02 17:47:28 -07003317 uint32_t nlen = (uint32_t)strlen(name);
3318 const char *suf = name + nlen - 5;
Lenny Komow408e0bd2017-08-09 16:01:59 -06003319
3320 // Check if the file is already present
3321 bool file_already_loaded = false;
3322 for (uint32_t i = 0; i < out_files->count; ++i) {
3323 if (!strcmp(out_files->filename_list[i], name)) {
3324 file_already_loaded = true;
3325 }
3326 }
3327
3328 if (!file_already_loaded && (nlen > 5) && !strncmp(suf, ".json", 5)) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003329 if (out_files->count == 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003330 out_files->filename_list =
3331 loader_instance_heap_alloc(inst, alloced_count * sizeof(char *), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Mark Youngbb3a29c2017-05-19 12:29:43 -06003332 if (NULL == out_files->filename_list) {
3333 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3334 "loader_get_manifest_files: Failed to allocate space for manifest file name list");
3335 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3336 goto out;
3337 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07003338 } else if (out_files->count == alloced_count) {
Mark Youngbb3a29c2017-05-19 12:29:43 -06003339 void *new_ptr =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003340 loader_instance_heap_realloc(inst, out_files->filename_list, alloced_count * sizeof(char *),
3341 alloced_count * sizeof(char *) * 2, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Mark Youngbb3a29c2017-05-19 12:29:43 -06003342 if (NULL == new_ptr) {
3343 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3344 "loader_get_manifest_files: Failed to reallocate space for manifest file name list");
3345 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3346 goto out;
3347 }
3348 out_files->filename_list = new_ptr;
Jon Ashburn23d36b12016-02-02 17:47:28 -07003349 alloced_count *= 2;
Jon Ashburn2077e382015-06-29 11:25:34 -06003350 }
Mark Young0ad83132016-06-30 13:02:42 -06003351 out_files->filename_list[out_files->count] =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003352 loader_instance_heap_alloc(inst, strlen(name) + 1, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Jon Ashburn23d36b12016-02-02 17:47:28 -07003353 if (out_files->filename_list[out_files->count] == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003354 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3355 "loader_get_manifest_files: Failed to allocate "
3356 "space for manifest file %d list",
Mark Youngb6399312017-01-10 14:22:15 -07003357 out_files->count);
Mark Young0ad83132016-06-30 13:02:42 -06003358 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3359 goto out;
Jon Ashburn23d36b12016-02-02 17:47:28 -07003360 }
3361 strcpy(out_files->filename_list[out_files->count], name);
3362 out_files->count++;
Lenny Komow408e0bd2017-08-09 16:01:59 -06003363 } else if(file_already_loaded) {
3364 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3365 "Skipping manifest file %s - The file has already been read once", name);
Jon Ashburn23d36b12016-02-02 17:47:28 -07003366 } else if (!list_is_dirs) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003367 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, "Skipping manifest file %s, file name must end in .json",
3368 name);
Jon Ashburn23d36b12016-02-02 17:47:28 -07003369 }
3370 if (list_is_dirs) {
3371 dent = readdir(sysdir);
Mark Young0ad83132016-06-30 13:02:42 -06003372 if (dent == NULL) {
Jon Ashburn2077e382015-06-29 11:25:34 -06003373 break;
Mark Young0ad83132016-06-30 13:02:42 -06003374 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07003375 name = &(dent->d_name[0]);
3376 loader_get_fullpath(name, file, sizeof(full_path), full_path);
3377 name = full_path;
3378 } else {
3379 break;
3380 }
Jon Ashburn2077e382015-06-29 11:25:34 -06003381 }
Mark Young0ad83132016-06-30 13:02:42 -06003382 if (sysdir) {
Jon Ashburn2077e382015-06-29 11:25:34 -06003383 closedir(sysdir);
Mark Young0ad83132016-06-30 13:02:42 -06003384 sysdir = NULL;
3385 }
Jon Ashburn2077e382015-06-29 11:25:34 -06003386 file = next_file;
Jon Ashburn67e262e2016-02-18 12:45:39 -07003387#if !defined(_WIN32)
Benjamin Saunders31a48012017-01-29 14:49:54 -08003388 if (relative_location != NULL && (next_file == NULL || *next_file == '\0') && override == NULL) {
Mark Youngd8c6b692017-03-09 11:39:41 -07003389 char *xdgdatahome = loader_secure_getenv("XDG_DATA_HOME", inst);
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003390 size_t len;
3391 if (xdgdatahome != NULL) {
Mark Young6ef95f42017-02-17 09:02:23 -07003392 size_t alloc_len = strlen(xdgdatahome) + 2 + strlen(relative_location);
3393 char *home_loc = loader_stack_alloc(alloc_len);
Jon Ashburn67e262e2016-02-18 12:45:39 -07003394 if (home_loc == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003395 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3396 "loader_get_manifest_files: Failed to allocate "
3397 "space for manifest file XDG Home location");
Mark Young0ad83132016-06-30 13:02:42 -06003398 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3399 goto out;
Jon Ashburn67e262e2016-02-18 12:45:39 -07003400 }
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003401 strcpy(home_loc, xdgdatahome);
Jon Ashburn67e262e2016-02-18 12:45:39 -07003402 // Add directory separator if needed
Benjamin Saunders31a48012017-01-29 14:49:54 -08003403 if (relative_location[0] != DIRECTORY_SYMBOL) {
Jon Ashburn67e262e2016-02-18 12:45:39 -07003404 len = strlen(home_loc);
3405 home_loc[len] = DIRECTORY_SYMBOL;
Jon Ashburn1530c342016-02-26 13:14:27 -07003406 home_loc[len + 1] = '\0';
Jon Ashburn67e262e2016-02-18 12:45:39 -07003407 }
Mark Young6ef95f42017-02-17 09:02:23 -07003408 strncat(home_loc, relative_location, alloc_len);
Jon Ashburn67e262e2016-02-18 12:45:39 -07003409 file = home_loc;
3410 next_file = loader_get_next_path(file);
Benjamin Saunders31a48012017-01-29 14:49:54 -08003411 relative_location = NULL;
Jon Ashburn67e262e2016-02-18 12:45:39 -07003412
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003413 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Searching the following path for manifest files: %s\n",
3414 home_loc);
Jon Ashburn67e262e2016-02-18 12:45:39 -07003415 list_is_dirs = true;
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003416
3417 } else {
Mark Youngd8c6b692017-03-09 11:39:41 -07003418 char *home = loader_secure_getenv("HOME", inst);
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003419 if (home != NULL) {
Mark Young6ef95f42017-02-17 09:02:23 -07003420 size_t alloc_len = strlen(home) + 16 + strlen(relative_location);
3421 char *home_loc = loader_stack_alloc(alloc_len);
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003422 if (home_loc == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003423 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3424 "loader_get_manifest_files: Failed to allocate "
3425 "space for manifest file Home location");
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003426 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3427 goto out;
3428 }
Mark Young6ef95f42017-02-17 09:02:23 -07003429 strncpy(home_loc, home, alloc_len);
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003430
3431 len = strlen(home);
3432 if (home[len] != DIRECTORY_SYMBOL) {
3433 home_loc[len] = DIRECTORY_SYMBOL;
3434 home_loc[len + 1] = '\0';
3435 }
Mark Young6ef95f42017-02-17 09:02:23 -07003436 strncat(home_loc, ".local/share", alloc_len);
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003437
Benjamin Saunders31a48012017-01-29 14:49:54 -08003438 if (relative_location[0] != DIRECTORY_SYMBOL) {
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003439 len = strlen(home_loc);
3440 home_loc[len] = DIRECTORY_SYMBOL;
3441 home_loc[len + 1] = '\0';
3442 }
Mark Young6ef95f42017-02-17 09:02:23 -07003443 strncat(home_loc, relative_location, alloc_len);
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003444 file = home_loc;
3445 next_file = loader_get_next_path(file);
Benjamin Saunders31a48012017-01-29 14:49:54 -08003446 relative_location = NULL;
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003447
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003448 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Searching the following path for manifest files: %s\n",
3449 home_loc);
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003450 list_is_dirs = true;
3451 } else {
3452 // without knowing HOME, we just.. give up
3453 }
Jon Ashburn67e262e2016-02-18 12:45:39 -07003454 }
3455 }
3456#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06003457 }
Mark Young0ad83132016-06-30 13:02:42 -06003458
3459out:
3460 if (VK_SUCCESS != res && NULL != out_files->filename_list) {
3461 for (uint32_t remove = 0; remove < out_files->count; remove++) {
3462 loader_instance_heap_free(inst, out_files->filename_list[remove]);
3463 }
3464 loader_instance_heap_free(inst, out_files->filename_list);
3465 out_files->count = 0;
3466 out_files->filename_list = NULL;
3467 }
3468
3469 if (NULL != sysdir) {
3470 closedir(sysdir);
3471 }
3472
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05003473 if (override_getenv != NULL) {
3474 loader_free_getenv(override_getenv, inst);
3475 }
3476
Mark Young0ad83132016-06-30 13:02:42 -06003477 if (NULL != reg && reg != orig_loc) {
3478 loader_instance_heap_free(inst, reg);
3479 }
3480 return res;
Jon Ashburn2077e382015-06-29 11:25:34 -06003481}
3482
Jon Ashburn23d36b12016-02-02 17:47:28 -07003483void loader_init_icd_lib_list() {}
Jon Ashburn8810c5f2015-08-18 18:04:47 -06003484
Jon Ashburn23d36b12016-02-02 17:47:28 -07003485void loader_destroy_icd_lib_list() {}
Mark Young0f183a82017-02-28 09:58:04 -07003486
3487// Try to find the Vulkan ICD driver(s).
3488//
3489// This function scans the default system loader path(s) or path
3490// specified by the \c VK_ICD_FILENAMES environment variable in
3491// order to find loadable VK ICDs manifest files. From these
3492// manifest files it finds the ICD libraries.
3493//
3494// \returns
3495// Vulkan result
3496// (on result == VK_SUCCESS) a list of icds that were discovered
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003497VkResult loader_icd_scan(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list) {
Jon Ashburn2077e382015-06-29 11:25:34 -06003498 char *file_str;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003499 uint16_t file_major_vers = 0;
3500 uint16_t file_minor_vers = 0;
3501 uint16_t file_patch_vers = 0;
3502 char *vers_tok;
Jon Ashburn2077e382015-06-29 11:25:34 -06003503 struct loader_manifest_files manifest_files;
Mark Young0ad83132016-06-30 13:02:42 -06003504 VkResult res = VK_SUCCESS;
3505 bool lockedMutex = false;
3506 cJSON *json = NULL;
Mark Young3a587792016-08-19 15:25:08 -06003507 uint32_t num_good_icds = 0;
Jon Ashburn2077e382015-06-29 11:25:34 -06003508
Mark Young0ad83132016-06-30 13:02:42 -06003509 memset(&manifest_files, 0, sizeof(struct loader_manifest_files));
3510
Mark Young0153e0b2016-11-03 14:27:13 -06003511 res = loader_scanned_icd_init(inst, icd_tramp_list);
Mark Young0ad83132016-06-30 13:02:42 -06003512 if (VK_SUCCESS != res) {
3513 goto out;
3514 }
3515
Jon Ashburn2077e382015-06-29 11:25:34 -06003516 // Get a list of manifest files for ICDs
Benjamin Saunders31a48012017-01-29 14:49:54 -08003517 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 -07003518 &manifest_files);
Mark Young0ad83132016-06-30 13:02:42 -06003519 if (VK_SUCCESS != res || manifest_files.count == 0) {
3520 goto out;
3521 }
Mark Youngf2079b92017-05-02 10:49:46 -06003522
Jon Ashburn6461ef22015-09-22 13:11:00 -06003523 loader_platform_thread_lock_mutex(&loader_json_lock);
Mark Young0ad83132016-06-30 13:02:42 -06003524 lockedMutex = true;
Jon Ashburn2077e382015-06-29 11:25:34 -06003525 for (uint32_t i = 0; i < manifest_files.count; i++) {
3526 file_str = manifest_files.filename_list[i];
Mark Young0ad83132016-06-30 13:02:42 -06003527 if (file_str == NULL) {
Jon Ashburn2077e382015-06-29 11:25:34 -06003528 continue;
Mark Young0ad83132016-06-30 13:02:42 -06003529 }
Jon Ashburn2077e382015-06-29 11:25:34 -06003530
Mark Youngdcd5f7e2017-04-25 10:35:54 -06003531 VkResult temp_res = loader_get_json(inst, file_str, &json);
3532 if (NULL == json || temp_res != VK_SUCCESS) {
Mark Youngd66edd52017-03-10 17:31:18 -07003533 if (NULL != json) {
3534 cJSON_Delete(json);
3535 json = NULL;
3536 }
Mark Youngdcd5f7e2017-04-25 10:35:54 -06003537 // If we haven't already found an ICD, copy this result to
3538 // the returned result.
3539 if (num_good_icds == 0) {
3540 res = temp_res;
3541 }
3542 if (temp_res == VK_ERROR_OUT_OF_HOST_MEMORY) {
Mark Youngd66edd52017-03-10 17:31:18 -07003543 break;
3544 } else {
3545 continue;
3546 }
Mark Young0ad83132016-06-30 13:02:42 -06003547 }
Mark Youngdcd5f7e2017-04-25 10:35:54 -06003548 res = temp_res;
Mark Young3a587792016-08-19 15:25:08 -06003549
Jon Ashburn005617f2015-11-17 17:35:40 -07003550 cJSON *item, *itemICD;
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003551 item = cJSON_GetObjectItem(json, "file_format_version");
Jon Ashburn6461ef22015-09-22 13:11:00 -06003552 if (item == NULL) {
Mark Young3a587792016-08-19 15:25:08 -06003553 if (num_good_icds == 0) {
3554 res = VK_ERROR_INITIALIZATION_FAILED;
3555 }
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003556 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3557 "loader_icd_scan: ICD JSON %s does not have a"
3558 " \'file_format_version\' field. Skipping ICD JSON.",
Mark Youngb6399312017-01-10 14:22:15 -07003559 file_str);
Derrick Owens62e16ef2016-09-09 15:49:07 -04003560 cJSON_Delete(json);
3561 json = NULL;
Mark Young3a587792016-08-19 15:25:08 -06003562 continue;
Jon Ashburn6461ef22015-09-22 13:11:00 -06003563 }
Mark Youngd66edd52017-03-10 17:31:18 -07003564
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003565 char *file_vers = cJSON_Print(item);
Mark Young0ad83132016-06-30 13:02:42 -06003566 if (NULL == file_vers) {
Mark Youngd66edd52017-03-10 17:31:18 -07003567 // Only reason the print can fail is if there was an allocation issue
Mark Young3a587792016-08-19 15:25:08 -06003568 if (num_good_icds == 0) {
3569 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3570 }
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003571 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3572 "loader_icd_scan: Failed retrieving ICD JSON %s"
3573 " \'file_format_version\' field. Skipping ICD JSON",
Mark Youngb6399312017-01-10 14:22:15 -07003574 file_str);
Derrick Owenscd92b8b2016-09-09 15:45:13 -04003575 cJSON_Delete(json);
3576 json = NULL;
Mark Young3a587792016-08-19 15:25:08 -06003577 continue;
Mark Young0ad83132016-06-30 13:02:42 -06003578 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003579 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 -07003580
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003581 // Get the major/minor/and patch as integers for easier comparison
3582 vers_tok = strtok(file_vers, ".\"\n\r");
3583 if (NULL != vers_tok) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04003584 file_major_vers = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003585 vers_tok = strtok(NULL, ".\"\n\r");
3586 if (NULL != vers_tok) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04003587 file_minor_vers = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003588 vers_tok = strtok(NULL, ".\"\n\r");
3589 if (NULL != vers_tok) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04003590 file_patch_vers = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003591 }
3592 }
3593 }
Mark Youngd66edd52017-03-10 17:31:18 -07003594
3595 if (file_major_vers != 1 || file_minor_vers != 0 || file_patch_vers > 1) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003596 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3597 "loader_icd_scan: Unexpected manifest file version "
3598 "(expected 1.0.0 or 1.0.1), may cause errors");
Mark Youngd66edd52017-03-10 17:31:18 -07003599 }
Mark Young0ad83132016-06-30 13:02:42 -06003600 cJSON_Free(file_vers);
Mark Youngd66edd52017-03-10 17:31:18 -07003601
Jon Ashburn005617f2015-11-17 17:35:40 -07003602 itemICD = cJSON_GetObjectItem(json, "ICD");
3603 if (itemICD != NULL) {
3604 item = cJSON_GetObjectItem(itemICD, "library_path");
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003605 if (item != NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003606 char *temp = cJSON_Print(item);
Jon Ashburn86251302015-08-25 16:48:24 -06003607 if (!temp || strlen(temp) == 0) {
Mark Young3a587792016-08-19 15:25:08 -06003608 if (num_good_icds == 0) {
3609 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3610 }
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003611 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3612 "loader_icd_scan: Failed retrieving ICD JSON %s"
3613 " \'library_path\' field. Skipping ICD JSON.",
Mark Youngb6399312017-01-10 14:22:15 -07003614 file_str);
Mark Young0ad83132016-06-30 13:02:42 -06003615 cJSON_Free(temp);
Jon Ashburn86251302015-08-25 16:48:24 -06003616 cJSON_Delete(json);
Mark Young0ad83132016-06-30 13:02:42 -06003617 json = NULL;
Jon Ashburn86251302015-08-25 16:48:24 -06003618 continue;
Jon Ashburn2077e382015-06-29 11:25:34 -06003619 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07003620 // strip out extra quotes
Jon Ashburn86251302015-08-25 16:48:24 -06003621 temp[strlen(temp) - 1] = '\0';
3622 char *library_path = loader_stack_alloc(strlen(temp) + 1);
Mark Young3a587792016-08-19 15:25:08 -06003623 if (NULL == library_path) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003624 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3625 "loader_icd_scan: Failed to allocate space for "
3626 "ICD JSON %s \'library_path\' value. Skipping "
3627 "ICD JSON.",
Mark Youngb6399312017-01-10 14:22:15 -07003628 file_str);
Mark Young3a587792016-08-19 15:25:08 -06003629 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3630 cJSON_Free(temp);
3631 cJSON_Delete(json);
3632 json = NULL;
3633 goto out;
3634 }
Jon Ashburn86251302015-08-25 16:48:24 -06003635 strcpy(library_path, &temp[1]);
Mark Young0ad83132016-06-30 13:02:42 -06003636 cJSON_Free(temp);
Mark Young3a587792016-08-19 15:25:08 -06003637 if (strlen(library_path) == 0) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003638 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3639 "loader_icd_scan: ICD JSON %s \'library_path\'"
3640 " field is empty. Skipping ICD JSON.",
Jon Ashburn23d36b12016-02-02 17:47:28 -07003641 file_str);
Jon Ashburn86251302015-08-25 16:48:24 -06003642 cJSON_Delete(json);
Mark Young0ad83132016-06-30 13:02:42 -06003643 json = NULL;
Jon Ashburn86251302015-08-25 16:48:24 -06003644 continue;
3645 }
Jamie Madill2fcbd152016-04-27 16:33:23 -04003646 char fullpath[MAX_STRING_SIZE];
Jon Ashburn86251302015-08-25 16:48:24 -06003647 // Print out the paths being searched if debugging is enabled
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003648 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Searching for ICD drivers named %s, using default dir %s",
3649 library_path, DEFAULT_VK_DRIVERS_PATH);
Daniel Dadap00b4aba2015-09-30 11:50:51 -05003650 if (loader_platform_is_path(library_path)) {
Jon Ashburn86251302015-08-25 16:48:24 -06003651 // a relative or absolute path
Daniel Dadap00b4aba2015-09-30 11:50:51 -05003652 char *name_copy = loader_stack_alloc(strlen(file_str) + 1);
3653 char *rel_base;
Jon Ashburn86251302015-08-25 16:48:24 -06003654 strcpy(name_copy, file_str);
3655 rel_base = loader_platform_dirname(name_copy);
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003656 loader_expand_path(library_path, rel_base, sizeof(fullpath), fullpath);
Daniel Dadap00b4aba2015-09-30 11:50:51 -05003657 } else {
Jamie Madill2fcbd152016-04-27 16:33:23 -04003658 // a filename which is assumed in a system directory
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003659 loader_get_fullpath(library_path, DEFAULT_VK_DRIVERS_PATH, sizeof(fullpath), fullpath);
Jon Ashburn86251302015-08-25 16:48:24 -06003660 }
Jon Ashburn005617f2015-11-17 17:35:40 -07003661
3662 uint32_t vers = 0;
3663 item = cJSON_GetObjectItem(itemICD, "api_version");
3664 if (item != NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003665 temp = cJSON_Print(item);
Mark Young0ad83132016-06-30 13:02:42 -06003666 if (NULL == temp) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003667 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3668 "loader_icd_scan: Failed retrieving ICD JSON %s"
3669 " \'api_version\' field. Skipping ICD JSON.",
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003670 file_str);
Mark Youngb6399312017-01-10 14:22:15 -07003671
Mark Young0ad83132016-06-30 13:02:42 -06003672 // Only reason the print can fail is if there was an
3673 // allocation issue
Mark Youngb6399312017-01-10 14:22:15 -07003674 if (num_good_icds == 0) {
3675 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3676 }
3677
3678 cJSON_Free(temp);
3679 cJSON_Delete(json);
3680 json = NULL;
3681 continue;
Mark Young0ad83132016-06-30 13:02:42 -06003682 }
Jon Ashburn005617f2015-11-17 17:35:40 -07003683 vers = loader_make_version(temp);
Mark Young0ad83132016-06-30 13:02:42 -06003684 cJSON_Free(temp);
Mark Youngb6399312017-01-10 14:22:15 -07003685 } else {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003686 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3687 "loader_icd_scan: ICD JSON %s does not have an"
3688 " \'api_version\' field.",
Mark Youngb6399312017-01-10 14:22:15 -07003689 file_str);
Jon Ashburn005617f2015-11-17 17:35:40 -07003690 }
Mark Youngb6399312017-01-10 14:22:15 -07003691
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003692 res = loader_scanned_icd_add(inst, icd_tramp_list, fullpath, vers);
Mark Young3a587792016-08-19 15:25:08 -06003693 if (VK_SUCCESS != res) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003694 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3695 "loader_icd_scan: Failed to add ICD JSON %s. "
3696 " Skipping ICD JSON.",
Mark Youngb6399312017-01-10 14:22:15 -07003697 fullpath);
Mark Youngd66edd52017-03-10 17:31:18 -07003698 cJSON_Delete(json);
3699 json = NULL;
Mark Youngb6399312017-01-10 14:22:15 -07003700 continue;
Mark Young3a587792016-08-19 15:25:08 -06003701 }
3702 num_good_icds++;
Mark Young0ad83132016-06-30 13:02:42 -06003703 } else {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003704 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3705 "loader_icd_scan: Failed to find \'library_path\' "
3706 "object in ICD JSON file %s. Skipping ICD JSON.",
Jon Ashburn23d36b12016-02-02 17:47:28 -07003707 file_str);
Mark Young0ad83132016-06-30 13:02:42 -06003708 }
3709 } else {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003710 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3711 "loader_icd_scan: Can not find \'ICD\' object in ICD JSON "
3712 "file %s. Skipping ICD JSON",
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003713 file_str);
Mark Young0ad83132016-06-30 13:02:42 -06003714 }
Jon Ashburn2077e382015-06-29 11:25:34 -06003715
Mark Young0ad83132016-06-30 13:02:42 -06003716 cJSON_Delete(json);
3717 json = NULL;
3718 }
3719
3720out:
Mark Youngb6399312017-01-10 14:22:15 -07003721
Mark Young0ad83132016-06-30 13:02:42 -06003722 if (NULL != json) {
Jon Ashburn2077e382015-06-29 11:25:34 -06003723 cJSON_Delete(json);
3724 }
Mark Youngd66edd52017-03-10 17:31:18 -07003725
Mark Young0ad83132016-06-30 13:02:42 -06003726 if (NULL != manifest_files.filename_list) {
3727 for (uint32_t i = 0; i < manifest_files.count; i++) {
3728 if (NULL != manifest_files.filename_list[i]) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003729 loader_instance_heap_free(inst, manifest_files.filename_list[i]);
Mark Young0ad83132016-06-30 13:02:42 -06003730 }
3731 }
3732 loader_instance_heap_free(inst, manifest_files.filename_list);
3733 }
3734 if (lockedMutex) {
3735 loader_platform_thread_unlock_mutex(&loader_json_lock);
3736 }
Mark Youngd66edd52017-03-10 17:31:18 -07003737
Mark Young0ad83132016-06-30 13:02:42 -06003738 return res;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08003739}
3740
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003741void loader_layer_scan(const struct loader_instance *inst, struct loader_layer_list *instance_layers) {
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003742 char *file_str;
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003743 struct loader_manifest_files manifest_files[2]; // [0] = explicit, [1] = implicit
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003744 cJSON *json;
Jon Ashburn075ce432015-12-17 17:38:24 -07003745 uint32_t implicit;
Mark Young0ad83132016-06-30 13:02:42 -06003746 bool lockedMutex = false;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003747
Mark Young0ad83132016-06-30 13:02:42 -06003748 memset(manifest_files, 0, sizeof(struct loader_manifest_files) * 2);
3749
3750 // Get a list of manifest files for explicit layers
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003751 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 -08003752 RELATIVE_VK_ELAYERS_INFO, &manifest_files[0])) {
Mark Young0ad83132016-06-30 13:02:42 -06003753 goto out;
3754 }
3755
3756 // Get a list of manifest files for any implicit layers
Jon Ashburn23d36b12016-02-02 17:47:28 -07003757 // Pass NULL for environment variable override - implicit layers are not
3758 // overridden by LAYERS_PATH_ENV
Benjamin Saunders31a48012017-01-29 14:49:54 -08003759 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 -07003760 &manifest_files[1])) {
Mark Young0ad83132016-06-30 13:02:42 -06003761 goto out;
3762 }
Jon Ashburn90c6a0e2015-06-04 15:30:58 -06003763
Mark Young0ad83132016-06-30 13:02:42 -06003764 // Make sure we have at least one layer, if not, go ahead and return
3765 if (manifest_files[0].count == 0 && manifest_files[1].count == 0) {
3766 goto out;
3767 }
3768
3769 // cleanup any previously scanned libraries
Jon Ashburne39a4f82015-08-28 13:38:21 -06003770 loader_delete_layer_properties(inst, instance_layers);
Jon Ashburnb2ef1372015-07-16 17:19:31 -06003771
Jon Ashburn6461ef22015-09-22 13:11:00 -06003772 loader_platform_thread_lock_mutex(&loader_json_lock);
Mark Young0ad83132016-06-30 13:02:42 -06003773 lockedMutex = true;
Jon Ashburn075ce432015-12-17 17:38:24 -07003774 for (implicit = 0; implicit < 2; implicit++) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04003775 for (uint32_t i = 0; i < manifest_files[implicit].count; i++) {
Jon Ashburn075ce432015-12-17 17:38:24 -07003776 file_str = manifest_files[implicit].filename_list[i];
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003777 if (file_str == NULL) continue;
Courtney Goeltzenleuchtera9e4af42015-06-01 14:49:17 -06003778
Jon Ashburn075ce432015-12-17 17:38:24 -07003779 // parse file into JSON struct
Mark Young3a587792016-08-19 15:25:08 -06003780 VkResult res = loader_get_json(inst, file_str, &json);
3781 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
3782 break;
3783 } else if (VK_SUCCESS != res || NULL == json) {
Jon Ashburn075ce432015-12-17 17:38:24 -07003784 continue;
3785 }
3786
Mark Youngf2079b92017-05-02 10:49:46 -06003787 VkResult local_res = loader_add_layer_properties(inst, instance_layers, json, (implicit == 1), file_str);
Jon Ashburn075ce432015-12-17 17:38:24 -07003788 cJSON_Delete(json);
Mark Youngf2079b92017-05-02 10:49:46 -06003789
Lenny Komow9a73b662018-02-13 10:30:02 -07003790 // If the error is anything other than out of memory we still want to try to load the other layers
3791 if (VK_ERROR_OUT_OF_HOST_MEMORY == local_res) {
Mark Youngf2079b92017-05-02 10:49:46 -06003792 goto out;
3793 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003794 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003795 }
Jon Ashburn86a527a2016-02-10 20:59:26 -07003796
Mark Youngf2079b92017-05-02 10:49:46 -06003797 // See if "VK_LAYER_LUNARG_standard_validation" already in list.
3798 bool found_std_val = false;
3799 for (uint32_t i = 0; i < instance_layers->count; i++) {
3800 struct loader_layer_properties *props = &instance_layers->list[i];
3801 if (strcmp(props->info.layerName, std_validation_str) == 0) {
3802 found_std_val = true;
3803 break;
3804 }
3805 }
3806
3807 // If we didn't find the VK_LAYER_LUNARG_standard_validation meta-layer in
3808 // the list, then we need to add it manually. This is likely because we're
3809 // dealing with a new loader, but an old layer folder.
3810 if (!found_std_val && !loader_add_legacy_std_val_layer(inst, instance_layers)) {
3811 goto out;
3812 }
3813
3814 // Verify any meta-layers in the list are valid and all the component layers are
3815 // actually present in the available layer list
3816 verify_all_meta_layers(inst, instance_layers);
Jon Ashburn86a527a2016-02-10 20:59:26 -07003817
Mark Young0ad83132016-06-30 13:02:42 -06003818out:
3819
3820 for (uint32_t manFile = 0; manFile < 2; manFile++) {
3821 if (NULL != manifest_files[manFile].filename_list) {
3822 for (uint32_t i = 0; i < manifest_files[manFile].count; i++) {
3823 if (NULL != manifest_files[manFile].filename_list[i]) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003824 loader_instance_heap_free(inst, manifest_files[manFile].filename_list[i]);
Mark Young0ad83132016-06-30 13:02:42 -06003825 }
3826 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003827 loader_instance_heap_free(inst, manifest_files[manFile].filename_list);
Mark Young0ad83132016-06-30 13:02:42 -06003828 }
3829 }
3830 if (lockedMutex) {
3831 loader_platform_thread_unlock_mutex(&loader_json_lock);
3832 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003833}
3834
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003835void loader_implicit_layer_scan(const struct loader_instance *inst, struct loader_layer_list *instance_layers) {
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003836 char *file_str;
3837 struct loader_manifest_files manifest_files;
3838 cJSON *json;
3839 uint32_t i;
3840
3841 // Pass NULL for environment variable override - implicit layers are not
3842 // overridden by LAYERS_PATH_ENV
Mark Youngf2079b92017-05-02 10:49:46 -06003843 VkResult res = loader_get_manifest_files(inst, NULL, NULL, true, false, DEFAULT_VK_ILAYERS_INFO, RELATIVE_VK_ILAYERS_INFO,
3844 &manifest_files);
Mark Young0ad83132016-06-30 13:02:42 -06003845 if (VK_SUCCESS != res || manifest_files.count == 0) {
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003846 return;
3847 }
3848
Mark Young0f183a82017-02-28 09:58:04 -07003849 // Cleanup any previously scanned libraries
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003850 loader_delete_layer_properties(inst, instance_layers);
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003851
3852 loader_platform_thread_lock_mutex(&loader_json_lock);
3853
3854 for (i = 0; i < manifest_files.count; i++) {
3855 file_str = manifest_files.filename_list[i];
3856 if (file_str == NULL) {
3857 continue;
3858 }
3859
3860 // parse file into JSON struct
Mark Young3a587792016-08-19 15:25:08 -06003861 res = loader_get_json(inst, file_str, &json);
3862 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
3863 break;
3864 } else if (VK_SUCCESS != res || NULL == json) {
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003865 continue;
3866 }
3867
Mark Youngf2079b92017-05-02 10:49:46 -06003868 res = loader_add_layer_properties(inst, instance_layers, json, true, file_str);
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003869
Mark Young0ad83132016-06-30 13:02:42 -06003870 loader_instance_heap_free(inst, file_str);
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003871 cJSON_Delete(json);
Mark Youngf2079b92017-05-02 10:49:46 -06003872
3873 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
3874 break;
3875 }
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003876 }
Mark Young0ad83132016-06-30 13:02:42 -06003877 loader_instance_heap_free(inst, manifest_files.filename_list);
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003878 loader_platform_thread_unlock_mutex(&loader_json_lock);
3879}
3880
Jean-Francois Roybd7ceab2017-07-06 14:10:13 -07003881// Check if an implicit layer should be enabled.
3882bool loader_is_implicit_layer_enabled(const struct loader_instance *inst, const struct loader_layer_properties *prop) {
3883 bool enable = false;
3884 char *env_value = NULL;
3885
3886 // if no enable_environment variable is specified, this implicit layer
3887 // should always be enabled. Otherwise check if the variable is set
3888 if (prop->enable_env_var.name[0] == 0) {
3889 enable = true;
3890 } else {
3891 env_value = loader_secure_getenv(prop->enable_env_var.name, inst);
3892 if (env_value && !strcmp(prop->enable_env_var.value, env_value)) enable = true;
3893 loader_free_getenv(env_value, inst);
3894 }
3895
3896 // disable_environment has priority, i.e. if both enable and disable
3897 // environment variables are set, the layer is disabled. Implicit
3898 // layers are required to have a disable_environment variables
3899 env_value = loader_secure_getenv(prop->disable_env_var.name, inst);
3900 if (env_value && !strcmp(prop->disable_env_var.value, env_value)) enable = false;
3901 loader_free_getenv(env_value, inst);
3902
3903 return enable;
3904}
3905
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003906static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpdpa_instance_internal(VkInstance inst, const char *pName) {
Mark Young39389872017-01-19 21:10:49 -07003907 // inst is not wrapped
3908 if (inst == VK_NULL_HANDLE) {
3909 return NULL;
3910 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003911 VkLayerInstanceDispatchTable *disp_table = *(VkLayerInstanceDispatchTable **)inst;
Mark Young39389872017-01-19 21:10:49 -07003912 void *addr;
3913
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003914 if (disp_table == NULL) return NULL;
Mark Young39389872017-01-19 21:10:49 -07003915
3916 bool found_name;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003917 addr = loader_lookup_instance_dispatch_table(disp_table, pName, &found_name);
Mark Young39389872017-01-19 21:10:49 -07003918 if (found_name) {
3919 return addr;
3920 }
3921
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003922 if (loader_phys_dev_ext_gpa(loader_get_instance(inst), pName, true, NULL, &addr)) return addr;
Mark Young39389872017-01-19 21:10:49 -07003923
3924 // Don't call down the chain, this would be an infinite loop
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003925 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 -07003926 return NULL;
3927}
3928
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003929static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpdpa_instance_terminator(VkInstance inst, const char *pName) {
Mark Young39389872017-01-19 21:10:49 -07003930 // inst is not wrapped
3931 if (inst == VK_NULL_HANDLE) {
3932 return NULL;
3933 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003934 VkLayerInstanceDispatchTable *disp_table = *(VkLayerInstanceDispatchTable **)inst;
Mark Young39389872017-01-19 21:10:49 -07003935 void *addr;
3936
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003937 if (disp_table == NULL) return NULL;
Mark Young39389872017-01-19 21:10:49 -07003938
3939 bool found_name;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003940 addr = loader_lookup_instance_dispatch_table(disp_table, pName, &found_name);
Mark Young39389872017-01-19 21:10:49 -07003941 if (found_name) {
3942 return addr;
3943 }
3944
3945 // Get the terminator, but don't perform checking since it should already
3946 // have been setup if we get here.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003947 if (loader_phys_dev_ext_gpa(loader_get_instance(inst), pName, false, NULL, &addr)) {
Mark Young39389872017-01-19 21:10:49 -07003948 return addr;
3949 }
3950
3951 // Don't call down the chain, this would be an infinite loop
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003952 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 -07003953 return NULL;
3954}
3955
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003956static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpa_instance_internal(VkInstance inst, const char *pName) {
Mark Young39389872017-01-19 21:10:49 -07003957 if (!strcmp(pName, "vkGetInstanceProcAddr")) {
3958 return (PFN_vkVoidFunction)loader_gpa_instance_internal;
3959 }
3960 if (!strcmp(pName, "vk_layerGetPhysicalDeviceProcAddr")) {
3961 return (PFN_vkVoidFunction)loader_gpdpa_instance_terminator;
3962 }
3963 if (!strcmp(pName, "vkCreateInstance")) {
3964 return (PFN_vkVoidFunction)terminator_CreateInstance;
3965 }
3966 if (!strcmp(pName, "vkCreateDevice")) {
3967 return (PFN_vkVoidFunction)terminator_CreateDevice;
3968 }
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003969
Jon Ashburn27cd5842015-05-12 17:26:48 -06003970 // inst is not wrapped
3971 if (inst == VK_NULL_HANDLE) {
3972 return NULL;
3973 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003974 VkLayerInstanceDispatchTable *disp_table = *(VkLayerInstanceDispatchTable **)inst;
Jon Ashburn27cd5842015-05-12 17:26:48 -06003975 void *addr;
3976
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003977 if (disp_table == NULL) return NULL;
Jon Ashburn27cd5842015-05-12 17:26:48 -06003978
Jon Ashburnc7d3e732016-03-08 09:30:30 -07003979 bool found_name;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003980 addr = loader_lookup_instance_dispatch_table(disp_table, pName, &found_name);
Jon Ashburnc7d3e732016-03-08 09:30:30 -07003981 if (found_name) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06003982 return addr;
Jon Ashburn3d526cb2015-04-13 18:10:06 -06003983 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003984
Jon Ashburnc7d3e732016-03-08 09:30:30 -07003985 // Don't call down the chain, this would be an infinite loop
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003986 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 -07003987 return NULL;
Jon Ashburn3d526cb2015-04-13 18:10:06 -06003988}
3989
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003990VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpa_device_internal(VkDevice device, const char *pName) {
Jon Ashburncc407a22016-04-15 09:25:03 -06003991 struct loader_device *dev;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003992 struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, NULL);
Mark Young16573c72016-06-28 10:52:43 -06003993
Mark Young0f183a82017-02-28 09:58:04 -07003994 // Return this function if a layer above here is asking for the vkGetDeviceProcAddr.
3995 // This is so we can properly intercept any device commands needing a terminator.
3996 if (!strcmp(pName, "vkGetDeviceProcAddr")) {
3997 return (PFN_vkVoidFunction)loader_gpa_device_internal;
3998 }
3999
Mark Young65cb3662016-11-07 13:27:02 -07004000 // NOTE: Device Funcs needing Trampoline/Terminator.
4001 // Overrides for device functions needing a trampoline and
4002 // a terminator because certain device entry-points still need to go
4003 // through a terminator before hitting the ICD. This could be for
4004 // several reasons, but the main one is currently unwrapping an
4005 // object before passing the appropriate info along to the ICD.
4006 // This is why we also have to override the direct ICD call to
4007 // vkGetDeviceProcAddr to intercept those calls.
Mark Young0f183a82017-02-28 09:58:04 -07004008 PFN_vkVoidFunction addr = get_extension_device_proc_terminator(pName);
4009 if (NULL != addr) {
4010 return addr;
Mark Young16573c72016-06-28 10:52:43 -06004011 }
4012
Mark Young0f183a82017-02-28 09:58:04 -07004013 return icd_term->dispatch.GetDeviceProcAddr(device, pName);
Piers Daniell295fe402016-03-29 11:51:11 -06004014}
4015
Mark Young0f183a82017-02-28 09:58:04 -07004016// Initialize device_ext dispatch table entry as follows:
4017// If dev == NULL find all logical devices created within this instance and
4018// init the entry (given by idx) in the ext dispatch table.
4019// If dev != NULL only initialize the entry in the given dev's dispatch table.
4020// The initialization value is gotten by calling down the device chain with
4021// GDPA.
4022// If GDPA returns NULL then don't initialize the dispatch table entry.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004023static 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 -07004024 const char *funcName)
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004025
Jon Ashburn23d36b12016-02-02 17:47:28 -07004026{
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004027 void *gdpa_value;
4028 if (dev != NULL) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004029 gdpa_value = dev->loader_dispatch.core_dispatch.GetDeviceProcAddr(dev->chain_device, funcName);
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004030 if (gdpa_value != NULL) dev->loader_dispatch.ext_dispatch.dev_ext[idx] = (PFN_vkDevExt)gdpa_value;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004031 } else {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004032 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 -06004033 struct loader_device *ldev = icd_term->logical_device_list;
Karl Schultz2558bd32016-02-24 14:39:39 -07004034 while (ldev) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004035 gdpa_value = ldev->loader_dispatch.core_dispatch.GetDeviceProcAddr(ldev->chain_device, funcName);
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004036 if (gdpa_value != NULL) ldev->loader_dispatch.ext_dispatch.dev_ext[idx] = (PFN_vkDevExt)gdpa_value;
Karl Schultz2558bd32016-02-24 14:39:39 -07004037 ldev = ldev->next;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004038 }
4039 }
4040 }
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004041}
4042
Mark Young0f183a82017-02-28 09:58:04 -07004043// Find all dev extension in the hash table and initialize the dispatch table
4044// for dev for each of those extension entrypoints found in hash table.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004045void loader_init_dispatch_dev_ext(struct loader_instance *inst, struct loader_device *dev) {
Mark Young39389872017-01-19 21:10:49 -07004046 for (uint32_t i = 0; i < MAX_NUM_UNKNOWN_EXTS; i++) {
4047 if (inst->dev_ext_disp_hash[i].func_name != NULL)
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004048 loader_init_dispatch_dev_ext_entry(inst, dev, i, inst->dev_ext_disp_hash[i].func_name);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004049 }
4050}
4051
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004052static bool loader_check_icds_for_dev_ext_address(struct loader_instance *inst, const char *funcName) {
Mark Young0153e0b2016-11-03 14:27:13 -06004053 struct loader_icd_term *icd_term;
4054 icd_term = inst->icd_terms;
4055 while (NULL != icd_term) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004056 if (icd_term->scanned_icd->GetInstanceProcAddr(icd_term->instance, funcName))
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004057 // this icd supports funcName
4058 return true;
Mark Young0153e0b2016-11-03 14:27:13 -06004059 icd_term = icd_term->next;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004060 }
4061
4062 return false;
4063}
4064
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004065static 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 -07004066 // Iterate over the layers.
Jon Ashburncc407a22016-04-15 09:25:03 -06004067 for (uint32_t layer = 0; layer < layers->count; ++layer) {
Jeremy Hayes1eb1f622016-03-03 16:03:03 -07004068 // Iterate over the extensions.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004069 const struct loader_device_extension_list *const extensions = &(layers->list[layer].device_extension_list);
4070 for (uint32_t extension = 0; extension < extensions->count; ++extension) {
Jeremy Hayes1eb1f622016-03-03 16:03:03 -07004071 // Iterate over the entry points.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004072 const struct loader_dev_ext_props *const property = &(extensions->list[extension]);
4073 for (uint32_t entry = 0; entry < property->entrypoint_count; ++entry) {
Jon Ashburncc407a22016-04-15 09:25:03 -06004074 if (strcmp(property->entrypoints[entry], funcName) == 0) {
Jeremy Hayes1eb1f622016-03-03 16:03:03 -07004075 return true;
4076 }
4077 }
4078 }
4079 }
4080
4081 return false;
4082}
4083
Jon Ashburn23d36b12016-02-02 17:47:28 -07004084static void loader_free_dev_ext_table(struct loader_instance *inst) {
Mark Young39389872017-01-19 21:10:49 -07004085 for (uint32_t i = 0; i < MAX_NUM_UNKNOWN_EXTS; i++) {
4086 loader_instance_heap_free(inst, inst->dev_ext_disp_hash[i].func_name);
4087 loader_instance_heap_free(inst, inst->dev_ext_disp_hash[i].list.index);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004088 }
Mark Young39389872017-01-19 21:10:49 -07004089 memset(inst->dev_ext_disp_hash, 0, sizeof(inst->dev_ext_disp_hash));
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004090}
4091
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004092static bool loader_add_dev_ext_table(struct loader_instance *inst, uint32_t *ptr_idx, const char *funcName) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004093 uint32_t i;
4094 uint32_t idx = *ptr_idx;
Mark Young39389872017-01-19 21:10:49 -07004095 struct loader_dispatch_hash_list *list = &inst->dev_ext_disp_hash[idx].list;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004096
Mark Young39389872017-01-19 21:10:49 -07004097 if (!inst->dev_ext_disp_hash[idx].func_name) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004098 // no entry here at this idx, so use it
4099 assert(list->capacity == 0);
Mark Young39389872017-01-19 21:10:49 -07004100 inst->dev_ext_disp_hash[idx].func_name =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004101 (char *)loader_instance_heap_alloc(inst, strlen(funcName) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young39389872017-01-19 21:10:49 -07004102 if (inst->dev_ext_disp_hash[idx].func_name == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004103 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4104 "loader_add_dev_ext_table: Failed to allocate memory "
4105 "for func_name %s",
Mark Youngb6399312017-01-10 14:22:15 -07004106 funcName);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004107 return false;
4108 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004109 strncpy(inst->dev_ext_disp_hash[idx].func_name, funcName, strlen(funcName) + 1);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004110 return true;
4111 }
4112
4113 // check for enough capacity
4114 if (list->capacity == 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004115 list->index = loader_instance_heap_alloc(inst, 8 * sizeof(*(list->index)), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004116 if (list->index == NULL) {
Mark Youngbb3a29c2017-05-19 12:29:43 -06004117 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 -07004118 funcName);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004119 return false;
4120 }
4121 list->capacity = 8 * sizeof(*(list->index));
4122 } else if (list->capacity < (list->count + 1) * sizeof(*(list->index))) {
Mark Youngbb3a29c2017-05-19 12:29:43 -06004123 void *new_ptr = loader_instance_heap_realloc(inst, list->index, list->capacity, list->capacity * 2,
4124 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
4125 if (NULL == new_ptr) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004126 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngbb3a29c2017-05-19 12:29:43 -06004127 "loader_add_dev_ext_table: Failed to reallocate memory for list index", funcName);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004128 return false;
4129 }
Mark Youngbb3a29c2017-05-19 12:29:43 -06004130 list->index = new_ptr;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004131 list->capacity *= 2;
4132 }
4133
Jon Ashburn23d36b12016-02-02 17:47:28 -07004134 // find an unused index in the hash table and use it
Mark Young39389872017-01-19 21:10:49 -07004135 i = (idx + 1) % MAX_NUM_UNKNOWN_EXTS;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004136 do {
Mark Young39389872017-01-19 21:10:49 -07004137 if (!inst->dev_ext_disp_hash[i].func_name) {
4138 assert(inst->dev_ext_disp_hash[i].list.capacity == 0);
4139 inst->dev_ext_disp_hash[i].func_name =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004140 (char *)loader_instance_heap_alloc(inst, strlen(funcName) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young39389872017-01-19 21:10:49 -07004141 if (inst->dev_ext_disp_hash[i].func_name == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004142 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4143 "loader_add_dev_ext_table: Failed to allocate memory "
4144 "for func_name %s",
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004145 funcName);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004146 return false;
4147 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004148 strncpy(inst->dev_ext_disp_hash[i].func_name, funcName, strlen(funcName) + 1);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004149 list->index[list->count] = i;
4150 list->count++;
4151 *ptr_idx = i;
4152 return true;
4153 }
Mark Young39389872017-01-19 21:10:49 -07004154 i = (i + 1) % MAX_NUM_UNKNOWN_EXTS;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004155 } while (i != idx);
4156
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004157 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4158 "loader_add_dev_ext_table: Could not insert into hash table; is "
4159 "it full?");
Mark Youngb6399312017-01-10 14:22:15 -07004160
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004161 return false;
4162}
4163
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004164static bool loader_name_in_dev_ext_table(struct loader_instance *inst, uint32_t *idx, const char *funcName) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004165 uint32_t alt_idx;
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004166 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 -07004167
4168 // funcName wasn't at the primary spot in the hash table
4169 // search the list of secondary locations (shallow search, not deep search)
Mark Young39389872017-01-19 21:10:49 -07004170 for (uint32_t i = 0; i < inst->dev_ext_disp_hash[*idx].list.count; i++) {
4171 alt_idx = inst->dev_ext_disp_hash[*idx].list.index[i];
4172 if (!strcmp(inst->dev_ext_disp_hash[*idx].func_name, funcName)) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004173 *idx = alt_idx;
4174 return true;
4175 }
4176 }
4177
4178 return false;
4179}
4180
Mark Young0f183a82017-02-28 09:58:04 -07004181// This function returns generic trampoline code address for unknown entry
4182// points.
4183// Presumably, these unknown entry points (as given by funcName) are device
4184// extension entrypoints. A hash table is used to keep a list of unknown entry
4185// points and their mapping to the device extension dispatch table
4186// (struct loader_dev_ext_dispatch_table).
4187// \returns
4188// For a given entry point string (funcName), if an existing mapping is found
4189// the
4190// trampoline address for that mapping is returned. Otherwise, this unknown
4191// entry point
4192// has not been seen yet. Next check if a layer or ICD supports it. If so then
4193// a
4194// new entry in the hash table is initialized and that trampoline address for
4195// the new entry is returned. Null is returned if the hash table is full or
4196// if no discovered layer or ICD returns a non-NULL GetProcAddr for it.
Jon Ashburn23d36b12016-02-02 17:47:28 -07004197void *loader_dev_ext_gpa(struct loader_instance *inst, const char *funcName) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004198 uint32_t idx;
4199 uint32_t seed = 0;
4200
Mark Young39389872017-01-19 21:10:49 -07004201 idx = murmurhash(funcName, strlen(funcName), seed) % MAX_NUM_UNKNOWN_EXTS;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004202
4203 if (loader_name_in_dev_ext_table(inst, &idx, funcName))
4204 // found funcName already in hash
4205 return loader_get_dev_ext_trampoline(idx);
4206
4207 // Check if funcName is supported in either ICDs or a layer library
Mark Young39389872017-01-19 21:10:49 -07004208 if (!loader_check_icds_for_dev_ext_address(inst, funcName) &&
Lenny Komowb1685e02017-08-29 16:08:39 -06004209 !loader_check_layer_list_for_dev_ext_address(&inst->app_activated_layer_list, funcName)) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004210 // if support found in layers continue on
4211 return NULL;
4212 }
4213
4214 if (loader_add_dev_ext_table(inst, &idx, funcName)) {
4215 // successfully added new table entry
Mark Youngdee312c2017-03-08 13:38:35 -07004216 // init any dev dispatch table entries as needed
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004217 loader_init_dispatch_dev_ext_entry(inst, NULL, idx, funcName);
4218 return loader_get_dev_ext_trampoline(idx);
4219 }
4220
4221 return NULL;
4222}
4223
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004224static bool loader_check_icds_for_phys_dev_ext_address(struct loader_instance *inst, const char *funcName) {
Mark Young39389872017-01-19 21:10:49 -07004225 struct loader_icd_term *icd_term;
4226 icd_term = inst->icd_terms;
4227 while (NULL != icd_term) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004228 if (icd_term->scanned_icd->interface_version >= MIN_PHYS_DEV_EXTENSION_ICD_INTERFACE_VERSION &&
4229 icd_term->scanned_icd->GetPhysicalDeviceProcAddr(icd_term->instance, funcName))
Mark Young39389872017-01-19 21:10:49 -07004230 // this icd supports funcName
4231 return true;
4232 icd_term = icd_term->next;
4233 }
4234
4235 return false;
4236}
4237
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004238static bool loader_check_layer_list_for_phys_dev_ext_address(struct loader_instance *inst, const char *funcName) {
Mark Young283fe1c2017-05-04 12:16:35 -06004239 struct loader_layer_properties *layer_prop_list = inst->expanded_activated_layer_list.list;
4240 for (uint32_t layer = 0; layer < inst->expanded_activated_layer_list.count; ++layer) {
Mark Young39389872017-01-19 21:10:49 -07004241 // If this layer supports the vk_layerGetPhysicalDeviceProcAddr, then call
4242 // it and see if it returns a valid pointer for this function name.
4243 if (layer_prop_list[layer].interface_version > 1) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004244 const struct loader_layer_functions *const functions = &(layer_prop_list[layer].functions);
Mark Young39389872017-01-19 21:10:49 -07004245 if (NULL != functions->get_physical_device_proc_addr &&
Tony Barbour55bd5392017-05-17 12:17:18 -06004246 NULL != functions->get_physical_device_proc_addr((VkInstance)inst->instance, funcName)) {
Mark Young39389872017-01-19 21:10:49 -07004247 return true;
4248 }
4249 }
4250 }
4251
4252 return false;
4253}
4254
Mark Young39389872017-01-19 21:10:49 -07004255static void loader_free_phys_dev_ext_table(struct loader_instance *inst) {
4256 for (uint32_t i = 0; i < MAX_NUM_UNKNOWN_EXTS; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004257 loader_instance_heap_free(inst, inst->phys_dev_ext_disp_hash[i].func_name);
4258 loader_instance_heap_free(inst, inst->phys_dev_ext_disp_hash[i].list.index);
Mark Young39389872017-01-19 21:10:49 -07004259 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004260 memset(inst->phys_dev_ext_disp_hash, 0, sizeof(inst->phys_dev_ext_disp_hash));
Mark Young39389872017-01-19 21:10:49 -07004261}
4262
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004263static 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 -07004264 uint32_t i;
4265 uint32_t idx = *ptr_idx;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004266 struct loader_dispatch_hash_list *list = &inst->phys_dev_ext_disp_hash[idx].list;
Mark Young39389872017-01-19 21:10:49 -07004267
4268 if (!inst->phys_dev_ext_disp_hash[idx].func_name) {
4269 // no entry here at this idx, so use it
4270 assert(list->capacity == 0);
4271 inst->phys_dev_ext_disp_hash[idx].func_name =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004272 (char *)loader_instance_heap_alloc(inst, strlen(funcName) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young39389872017-01-19 21:10:49 -07004273 if (inst->phys_dev_ext_disp_hash[idx].func_name == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004274 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4275 "loader_add_phys_dev_ext_table() can't allocate memory for "
4276 "func_name");
Mark Young39389872017-01-19 21:10:49 -07004277 return false;
4278 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004279 strncpy(inst->phys_dev_ext_disp_hash[idx].func_name, funcName, strlen(funcName) + 1);
Mark Young39389872017-01-19 21:10:49 -07004280 return true;
4281 }
4282
4283 // check for enough capacity
4284 if (list->capacity == 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004285 list->index = loader_instance_heap_alloc(inst, 8 * sizeof(*(list->index)), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young39389872017-01-19 21:10:49 -07004286 if (list->index == NULL) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004287 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 -07004288 return false;
4289 }
4290 list->capacity = 8 * sizeof(*(list->index));
4291 } else if (list->capacity < (list->count + 1) * sizeof(*(list->index))) {
Mark Youngbb3a29c2017-05-19 12:29:43 -06004292 void *new_ptr = loader_instance_heap_realloc(inst, list->index, list->capacity, list->capacity * 2,
4293 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
4294 if (NULL == new_ptr) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004295 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 -07004296 return false;
4297 }
Mark Youngbb3a29c2017-05-19 12:29:43 -06004298 list->index = new_ptr;
Mark Young39389872017-01-19 21:10:49 -07004299 list->capacity *= 2;
4300 }
4301
4302 // find an unused index in the hash table and use it
4303 i = (idx + 1) % MAX_NUM_UNKNOWN_EXTS;
4304 do {
4305 if (!inst->phys_dev_ext_disp_hash[i].func_name) {
4306 assert(inst->phys_dev_ext_disp_hash[i].list.capacity == 0);
4307 inst->phys_dev_ext_disp_hash[i].func_name =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004308 (char *)loader_instance_heap_alloc(inst, strlen(funcName) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young39389872017-01-19 21:10:49 -07004309 if (inst->phys_dev_ext_disp_hash[i].func_name == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004310 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngdee312c2017-03-08 13:38:35 -07004311 "loader_add_dev_ext_table() can't reallocate "
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004312 "func_name memory");
Mark Young39389872017-01-19 21:10:49 -07004313 return false;
4314 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004315 strncpy(inst->phys_dev_ext_disp_hash[i].func_name, funcName, strlen(funcName) + 1);
Mark Young39389872017-01-19 21:10:49 -07004316 list->index[list->count] = i;
4317 list->count++;
4318 *ptr_idx = i;
4319 return true;
4320 }
4321 i = (i + 1) % MAX_NUM_UNKNOWN_EXTS;
4322 } while (i != idx);
4323
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004324 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4325 "loader_add_phys_dev_ext_table() couldn't insert into hash table; is "
4326 "it full?");
Mark Young39389872017-01-19 21:10:49 -07004327 return false;
4328}
4329
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004330static 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 -07004331 uint32_t alt_idx;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004332 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 -07004333 return true;
4334
4335 // funcName wasn't at the primary spot in the hash table
4336 // search the list of secondary locations (shallow search, not deep search)
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004337 for (uint32_t i = 0; i < inst->phys_dev_ext_disp_hash[*idx].list.count; i++) {
Mark Young39389872017-01-19 21:10:49 -07004338 alt_idx = inst->phys_dev_ext_disp_hash[*idx].list.index[i];
4339 if (!strcmp(inst->phys_dev_ext_disp_hash[*idx].func_name, funcName)) {
4340 *idx = alt_idx;
4341 return true;
4342 }
4343 }
4344
4345 return false;
4346}
4347
4348// This function returns a generic trampoline and/or terminator function
4349// address for any unknown physical device extension commands. A hash
4350// table is used to keep a list of unknown entry points and their
4351// mapping to the physical device extension dispatch table (struct
4352// loader_phys_dev_ext_dispatch_table).
4353// For a given entry point string (funcName), if an existing mapping is
4354// found, then the trampoline address for that mapping is returned in
4355// tramp_addr (if it is not NULL) and the terminator address for that
4356// mapping is returned in term_addr (if it is not NULL). Otherwise,
4357// this unknown entry point has not been seen yet.
4358// If it has not been seen before, and perform_checking is 'true',
4359// check if a layer or and ICD supports it. If so then a new entry in
4360// the hash table is initialized and the trampoline and/or terminator
4361// addresses are returned.
4362// Null is returned if the hash table is full or if no discovered layer or
4363// ICD returns a non-NULL GetProcAddr for it.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004364bool 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 -07004365 void **term_addr) {
4366 uint32_t idx;
4367 uint32_t seed = 0;
4368 bool success = false;
4369
4370 if (inst == NULL) {
4371 goto out;
4372 }
4373
4374 if (NULL != tramp_addr) {
4375 *tramp_addr = NULL;
4376 }
4377 if (NULL != term_addr) {
4378 *term_addr = NULL;
4379 }
4380
4381 // We should always check to see if any ICD supports it.
4382 if (!loader_check_icds_for_phys_dev_ext_address(inst, funcName)) {
4383 // If we're not checking layers, or we are and it's not in a layer, just
4384 // return
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004385 if (!perform_checking || !loader_check_layer_list_for_phys_dev_ext_address(inst, funcName)) {
Mark Young39389872017-01-19 21:10:49 -07004386 goto out;
4387 }
4388 }
4389
4390 idx = murmurhash(funcName, strlen(funcName), seed) % MAX_NUM_UNKNOWN_EXTS;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004391 if (perform_checking && !loader_name_in_phys_dev_ext_table(inst, &idx, funcName)) {
Mark Young39389872017-01-19 21:10:49 -07004392 uint32_t i;
4393 bool added = false;
4394
4395 // Only need to add first one to get index in Instance. Others will use
4396 // the same index.
4397 if (!added && loader_add_phys_dev_ext_table(inst, &idx, funcName)) {
4398 added = true;
4399 }
4400
4401 // Setup the ICD function pointers
4402 struct loader_icd_term *icd_term = inst->icd_terms;
4403 while (NULL != icd_term) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004404 if (MIN_PHYS_DEV_EXTENSION_ICD_INTERFACE_VERSION <= icd_term->scanned_icd->interface_version &&
Mark Young39389872017-01-19 21:10:49 -07004405 NULL != icd_term->scanned_icd->GetPhysicalDeviceProcAddr) {
4406 icd_term->phys_dev_ext[idx] =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004407 (PFN_PhysDevExt)icd_term->scanned_icd->GetPhysicalDeviceProcAddr(icd_term->instance, funcName);
Mark Young39389872017-01-19 21:10:49 -07004408
4409 // Make sure we set the instance dispatch to point to the
4410 // loader's terminator now since we can at least handle it
4411 // in one ICD.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004412 inst->disp->phys_dev_ext[idx] = loader_get_phys_dev_ext_termin(idx);
Mark Young39389872017-01-19 21:10:49 -07004413 } else {
4414 icd_term->phys_dev_ext[idx] = NULL;
4415 }
4416
4417 icd_term = icd_term->next;
4418 }
4419
4420 // Now, search for the first layer attached and query using it to get
4421 // the first entry point.
Mark Young283fe1c2017-05-04 12:16:35 -06004422 for (i = 0; i < inst->expanded_activated_layer_list.count; i++) {
4423 struct loader_layer_properties *layer_prop = &inst->expanded_activated_layer_list.list[i];
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004424 if (layer_prop->interface_version > 1 && NULL != layer_prop->functions.get_physical_device_proc_addr) {
Mark Young39389872017-01-19 21:10:49 -07004425 inst->disp->phys_dev_ext[idx] =
Tony Barbour55bd5392017-05-17 12:17:18 -06004426 (PFN_PhysDevExt)layer_prop->functions.get_physical_device_proc_addr((VkInstance)inst->instance, funcName);
Mark Young39389872017-01-19 21:10:49 -07004427 if (NULL != inst->disp->phys_dev_ext[idx]) {
4428 break;
4429 }
4430 }
4431 }
4432 }
4433
4434 if (NULL != tramp_addr) {
4435 *tramp_addr = loader_get_phys_dev_ext_tramp(idx);
4436 }
4437
4438 if (NULL != term_addr) {
4439 *term_addr = loader_get_phys_dev_ext_termin(idx);
4440 }
4441
4442 success = true;
4443
4444out:
4445 return success;
4446}
4447
Jon Ashburn23d36b12016-02-02 17:47:28 -07004448struct loader_instance *loader_get_instance(const VkInstance instance) {
Mark Young0f183a82017-02-28 09:58:04 -07004449 // look up the loader_instance in our list by comparing dispatch tables, as
4450 // there is no guarantee the instance is still a loader_instance* after any
4451 // layers which wrap the instance object.
Jon Ashburne0e64572015-09-30 12:56:42 -06004452 const VkLayerInstanceDispatchTable *disp;
4453 struct loader_instance *ptr_instance = NULL;
Mark Young39389872017-01-19 21:10:49 -07004454 disp = loader_get_instance_layer_dispatch(instance);
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004455 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
Mark Young39389872017-01-19 21:10:49 -07004456 if (&inst->disp->layer_inst_disp == disp) {
Jon Ashburne0e64572015-09-30 12:56:42 -06004457 ptr_instance = inst;
4458 break;
4459 }
4460 }
4461 return ptr_instance;
4462}
4463
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004464static loader_platform_dl_handle loader_open_layer_lib(const struct loader_instance *inst, const char *chain_type,
4465 struct loader_layer_properties *prop) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004466 if ((prop->lib_handle = loader_platform_open_library(prop->lib_name)) == NULL) {
Mark Youngb986b5f2017-05-16 09:48:55 -06004467 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 -06004468 } else {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004469 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Loading layer library %s", prop->lib_name);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004470 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004471
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004472 return prop->lib_handle;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004473}
4474
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004475static void loader_close_layer_lib(const struct loader_instance *inst, struct loader_layer_properties *prop) {
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004476 if (prop->lib_handle) {
4477 loader_platform_close_library(prop->lib_handle);
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004478 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Unloading layer library %s", prop->lib_name);
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004479 prop->lib_handle = NULL;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06004480 }
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004481}
Jon Ashburnd38bfb12014-10-14 19:15:22 -06004482
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004483void loader_deactivate_layers(const struct loader_instance *instance, struct loader_device *device,
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004484 struct loader_layer_list *list) {
Mark Young0f183a82017-02-28 09:58:04 -07004485 // Delete instance list of enabled layers and close any layer libraries
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004486 for (uint32_t i = 0; i < list->count; i++) {
4487 struct loader_layer_properties *layer_prop = &list->list[i];
Courtney Goeltzenleuchter80bfd0e2015-12-17 09:51:22 -07004488
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004489 loader_close_layer_lib(instance, layer_prop);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07004490 }
Mark Young0ad83132016-06-30 13:02:42 -06004491 loader_destroy_layer_list(instance, device, list);
Jon Ashburnb8358052014-11-18 09:06:04 -07004492}
4493
Mark Young0f183a82017-02-28 09:58:04 -07004494// Go through the search_list and find any layers which match type. If layer
4495// type match is found in then add it to ext_list.
Mark Youngf2079b92017-05-02 10:49:46 -06004496static void loader_add_implicit_layers(const struct loader_instance *inst, struct loader_layer_list *target_list,
Mark Young283fe1c2017-05-04 12:16:35 -06004497 struct loader_layer_list *expanded_target_list,
Mark Youngf2079b92017-05-02 10:49:46 -06004498 const struct loader_layer_list *source_list) {
4499 for (uint32_t src_layer = 0; src_layer < source_list->count; src_layer++) {
4500 const struct loader_layer_properties *prop = &source_list->list[src_layer];
4501 if (0 == (prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER)) {
Mark Young283fe1c2017-05-04 12:16:35 -06004502 loader_add_implicit_layer(inst, prop, target_list, expanded_target_list, source_list);
Jon Ashburn0c26e712015-07-02 16:10:32 -06004503 }
4504 }
Jon Ashburn0c26e712015-07-02 16:10:32 -06004505}
4506
Mark Youngf2079b92017-05-02 10:49:46 -06004507// Get the layer name(s) from the env_name environment variable. If layer is found in
4508// 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 -07004509static 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 -06004510 struct loader_layer_list *target_list, struct loader_layer_list *expanded_target_list,
4511 const struct loader_layer_list *source_list) {
Jon Ashburneb6d5682015-07-02 14:10:53 -06004512 char *next, *name;
Mark Youngf2079b92017-05-02 10:49:46 -06004513 char *layer_env = loader_secure_getenv(env_name, inst);
4514 if (layer_env == NULL) {
4515 goto out;
Ian Elliott4470a302015-02-17 10:33:47 -07004516 }
Mark Youngf2079b92017-05-02 10:49:46 -06004517 name = loader_stack_alloc(strlen(layer_env) + 1);
Jon Ashburneb6d5682015-07-02 14:10:53 -06004518 if (name == NULL) {
Mark Youngf2079b92017-05-02 10:49:46 -06004519 goto out;
Ian Elliott4470a302015-02-17 10:33:47 -07004520 }
Mark Youngf2079b92017-05-02 10:49:46 -06004521 strcpy(name, layer_env);
Jon Ashburn38a497f2016-01-04 14:01:38 -07004522
Jon Ashburn23d36b12016-02-02 17:47:28 -07004523 while (name && *name) {
Jon Ashburneb6d5682015-07-02 14:10:53 -06004524 next = loader_get_next_path(name);
Mark Young283fe1c2017-05-04 12:16:35 -06004525 loader_find_layer_name_add_list(inst, name, type_flags, source_list, target_list, expanded_target_list);
Jon Ashburneb6d5682015-07-02 14:10:53 -06004526 name = next;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07004527 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06004528
Mark Youngf2079b92017-05-02 10:49:46 -06004529out:
4530
4531 if (layer_env != NULL) {
4532 loader_free_getenv(layer_env, inst);
4533 }
4534
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004535 return;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06004536}
4537
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004538VkResult loader_enable_instance_layers(struct loader_instance *inst, const VkInstanceCreateInfo *pCreateInfo,
4539 const struct loader_layer_list *instance_layers) {
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06004540 VkResult err;
4541
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06004542 assert(inst && "Cannot have null instance");
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004543
Mark Young283fe1c2017-05-04 12:16:35 -06004544 if (!loader_init_layer_list(inst, &inst->app_activated_layer_list)) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004545 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4546 "loader_enable_instance_layers: Failed to initialize"
Mark Young283fe1c2017-05-04 12:16:35 -06004547 " application version of the layer list");
4548 return VK_ERROR_OUT_OF_HOST_MEMORY;
4549 }
4550
4551 if (!loader_init_layer_list(inst, &inst->expanded_activated_layer_list)) {
4552 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4553 "loader_enable_instance_layers: Failed to initialize"
4554 " expanded version of the layer list");
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06004555 return VK_ERROR_OUT_OF_HOST_MEMORY;
Jon Ashburnbd6c4882015-07-02 12:59:25 -06004556 }
4557
Mark Young0f183a82017-02-28 09:58:04 -07004558 // Add any implicit layers first
Mark Young283fe1c2017-05-04 12:16:35 -06004559 loader_add_implicit_layers(inst, &inst->app_activated_layer_list, &inst->expanded_activated_layer_list, instance_layers);
Jon Ashburn0c26e712015-07-02 16:10:32 -06004560
Mark Young0f183a82017-02-28 09:58:04 -07004561 // Add any layers specified via environment variable next
Lenny Komow3b958392018-01-17 13:53:59 -07004562 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 -06004563 &inst->expanded_activated_layer_list, instance_layers);
Jon Ashburnbd6c4882015-07-02 12:59:25 -06004564
Mark Young0f183a82017-02-28 09:58:04 -07004565 // Add layers specified by the application
Mark Young283fe1c2017-05-04 12:16:35 -06004566 err = loader_add_layer_names_to_list(inst, &inst->app_activated_layer_list, &inst->expanded_activated_layer_list,
4567 pCreateInfo->enabledLayerCount, pCreateInfo->ppEnabledLayerNames, instance_layers);
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06004568
4569 return err;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004570}
4571
Mark Young39389872017-01-19 21:10:49 -07004572// Determine the layer interface version to use.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004573bool loader_get_layer_interface_version(PFN_vkNegotiateLoaderLayerInterfaceVersion fp_negotiate_layer_version,
4574 VkNegotiateLayerInterface *interface_struct) {
Mark Young39389872017-01-19 21:10:49 -07004575 memset(interface_struct, 0, sizeof(VkNegotiateLayerInterface));
Mark Young21aa6d62017-03-29 13:39:27 -06004576 interface_struct->sType = LAYER_NEGOTIATE_INTERFACE_STRUCT;
Mark Young39389872017-01-19 21:10:49 -07004577 interface_struct->loaderLayerInterfaceVersion = 1;
4578
4579 if (fp_negotiate_layer_version != NULL) {
4580 // Layer supports the negotiation API, so call it with the loader's
4581 // latest version supported
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004582 interface_struct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
Mark Young39389872017-01-19 21:10:49 -07004583 VkResult result = fp_negotiate_layer_version(interface_struct);
4584
4585 if (result != VK_SUCCESS) {
4586 // Layer no longer supports the loader's latest interface version so
4587 // fail loading the Layer
4588 return false;
4589 }
4590 }
4591
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004592 if (interface_struct->loaderLayerInterfaceVersion < MIN_SUPPORTED_LOADER_LAYER_INTERFACE_VERSION) {
Mark Young39389872017-01-19 21:10:49 -07004593 // Loader no longer supports the layer's latest interface version so
4594 // fail loading the layer
4595 return false;
4596 }
4597
4598 return true;
4599}
4600
Mark Young0f183a82017-02-28 09:58:04 -07004601// Given the list of layers to activate in the loader_instance
4602// structure. This function will add a VkLayerInstanceCreateInfo
4603// structure to the VkInstanceCreateInfo.pNext pointer.
4604// Each activated layer will have it's own VkLayerInstanceLink
4605// structure that tells the layer what Get*ProcAddr to call to
4606// get function pointers to the next layer down.
4607// Once the chain info has been created this function will
4608// execute the CreateInstance call chain. Each layer will
4609// then have an opportunity in it's CreateInstance function
4610// to setup it's dispatch table when the lower layer returns
4611// successfully.
4612// Each layer can wrap or not-wrap the returned VkInstance object
4613// as it sees fit.
4614// The instance chain is terminated by a loader function
4615// that will call CreateInstance on all available ICD's and
4616// cache those VkInstance objects for future use.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004617VkResult loader_create_instance_chain(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
4618 struct loader_instance *inst, VkInstance *created_instance) {
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004619 uint32_t activated_layers = 0;
4620 VkLayerInstanceCreateInfo chain_info;
4621 VkLayerInstanceLink *layer_instance_link_info = NULL;
4622 VkInstanceCreateInfo loader_create_info;
4623 VkResult res;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004624
Mark Young39389872017-01-19 21:10:49 -07004625 PFN_vkGetInstanceProcAddr next_gipa = loader_gpa_instance_internal;
4626 PFN_vkGetInstanceProcAddr cur_gipa = loader_gpa_instance_internal;
4627 PFN_GetPhysicalDeviceProcAddr next_gpdpa = loader_gpdpa_instance_internal;
4628 PFN_GetPhysicalDeviceProcAddr cur_gpdpa = loader_gpdpa_instance_internal;
Jon Ashburn27cd5842015-05-12 17:26:48 -06004629
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004630 memcpy(&loader_create_info, pCreateInfo, sizeof(VkInstanceCreateInfo));
Jon Ashburn27cd5842015-05-12 17:26:48 -06004631
Mark Young283fe1c2017-05-04 12:16:35 -06004632 if (inst->expanded_activated_layer_list.count > 0) {
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004633 chain_info.u.pLayerInfo = NULL;
4634 chain_info.pNext = pCreateInfo->pNext;
4635 chain_info.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
4636 chain_info.function = VK_LAYER_LINK_INFO;
4637 loader_create_info.pNext = &chain_info;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004638
Mark Young283fe1c2017-05-04 12:16:35 -06004639 layer_instance_link_info = loader_stack_alloc(sizeof(VkLayerInstanceLink) * inst->expanded_activated_layer_list.count);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004640 if (!layer_instance_link_info) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004641 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4642 "loader_create_instance_chain: Failed to alloc Instance"
4643 " objects for layer");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004644 return VK_ERROR_OUT_OF_HOST_MEMORY;
Jon Ashburn27cd5842015-05-12 17:26:48 -06004645 }
4646
Mark Young39389872017-01-19 21:10:49 -07004647 // Create instance chain of enabled layers
Mark Young283fe1c2017-05-04 12:16:35 -06004648 for (int32_t i = inst->expanded_activated_layer_list.count - 1; i >= 0; i--) {
4649 struct loader_layer_properties *layer_prop = &inst->expanded_activated_layer_list.list[i];
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004650 loader_platform_dl_handle lib_handle;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06004651
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004652 lib_handle = loader_open_layer_lib(inst, "instance", layer_prop);
Mark Young39389872017-01-19 21:10:49 -07004653 if (!lib_handle) {
Courtney Goeltzenleuchter524b7e32016-01-14 16:06:06 -07004654 continue;
Mark Young39389872017-01-19 21:10:49 -07004655 }
4656
4657 if (NULL == layer_prop->functions.negotiate_layer_interface) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004658 PFN_vkNegotiateLoaderLayerInterfaceVersion negotiate_interface = NULL;
Mark Young39389872017-01-19 21:10:49 -07004659 bool functions_in_interface = false;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004660 if (strlen(layer_prop->functions.str_negotiate_interface) == 0) {
4661 negotiate_interface = (PFN_vkNegotiateLoaderLayerInterfaceVersion)loader_platform_get_proc_address(
4662 lib_handle, "vkNegotiateLoaderLayerInterfaceVersion");
Mark Young39389872017-01-19 21:10:49 -07004663 } else {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004664 negotiate_interface = (PFN_vkNegotiateLoaderLayerInterfaceVersion)loader_platform_get_proc_address(
4665 lib_handle, layer_prop->functions.str_negotiate_interface);
Mark Young39389872017-01-19 21:10:49 -07004666 }
4667
4668 // If we can negotiate an interface version, then we can also
4669 // get everything we need from the one function call, so try
4670 // that first, and see if we can get all the function pointers
4671 // necessary from that one call.
4672 if (NULL != negotiate_interface) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004673 layer_prop->functions.negotiate_layer_interface = negotiate_interface;
Mark Young39389872017-01-19 21:10:49 -07004674
4675 VkNegotiateLayerInterface interface_struct;
4676
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004677 if (loader_get_layer_interface_version(negotiate_interface, &interface_struct)) {
Mark Youngdee312c2017-03-08 13:38:35 -07004678 // Go ahead and set the properties version to the
Mark Young39389872017-01-19 21:10:49 -07004679 // correct value.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004680 layer_prop->interface_version = interface_struct.loaderLayerInterfaceVersion;
Mark Young39389872017-01-19 21:10:49 -07004681
4682 // If the interface is 2 or newer, we have access to the
4683 // new GetPhysicalDeviceProcAddr function, so grab it,
4684 // and the other necessary functions, from the
4685 // structure.
4686 if (interface_struct.loaderLayerInterfaceVersion > 1) {
4687 cur_gipa = interface_struct.pfnGetInstanceProcAddr;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004688 cur_gpdpa = interface_struct.pfnGetPhysicalDeviceProcAddr;
Mark Young39389872017-01-19 21:10:49 -07004689 if (cur_gipa != NULL) {
4690 // We've set the functions, so make sure we
4691 // don't do the unnecessary calls later.
4692 functions_in_interface = true;
4693 }
4694 }
4695 }
4696 }
4697
4698 if (!functions_in_interface) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004699 if ((cur_gipa = layer_prop->functions.get_instance_proc_addr) == NULL) {
Mark Young39389872017-01-19 21:10:49 -07004700 if (strlen(layer_prop->functions.str_gipa) == 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004701 cur_gipa =
4702 (PFN_vkGetInstanceProcAddr)loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
4703 layer_prop->functions.get_instance_proc_addr = cur_gipa;
Mark Young39389872017-01-19 21:10:49 -07004704 } else {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004705 cur_gipa = (PFN_vkGetInstanceProcAddr)loader_platform_get_proc_address(lib_handle,
4706 layer_prop->functions.str_gipa);
Mark Young39389872017-01-19 21:10:49 -07004707 }
4708
4709 if (NULL == cur_gipa) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004710 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4711 "loader_create_instance_chain: Failed to"
4712 " find \'vkGetInstanceProcAddr\' in "
4713 "layer %s",
Mark Young39389872017-01-19 21:10:49 -07004714 layer_prop->lib_name);
4715 continue;
4716 }
4717 }
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004718 }
4719 }
4720
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004721 layer_instance_link_info[activated_layers].pNext = chain_info.u.pLayerInfo;
4722 layer_instance_link_info[activated_layers].pfnNextGetInstanceProcAddr = next_gipa;
4723 layer_instance_link_info[activated_layers].pfnNextGetPhysicalDeviceProcAddr = next_gpdpa;
Mark Young39389872017-01-19 21:10:49 -07004724 next_gipa = cur_gipa;
4725 if (layer_prop->interface_version > 1 && cur_gpdpa != NULL) {
4726 layer_prop->functions.get_physical_device_proc_addr = cur_gpdpa;
4727 next_gpdpa = cur_gpdpa;
4728 }
4729
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004730 chain_info.u.pLayerInfo = &layer_instance_link_info[activated_layers];
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004731
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004732 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Insert instance layer %s (%s)", layer_prop->info.layerName,
4733 layer_prop->lib_name);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004734
4735 activated_layers++;
4736 }
Jon Ashburn27cd5842015-05-12 17:26:48 -06004737 }
4738
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004739 PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)next_gipa(*created_instance, "vkCreateInstance");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004740 if (fpCreateInstance) {
Jon Ashburnc3c58772016-03-29 11:16:01 -06004741 VkLayerInstanceCreateInfo create_info_disp;
4742
Jon Ashburncc407a22016-04-15 09:25:03 -06004743 create_info_disp.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
Jon Ashburned8f2312016-03-31 10:52:22 -06004744 create_info_disp.function = VK_LOADER_DATA_CALLBACK;
Jon Ashburnc3c58772016-03-29 11:16:01 -06004745
4746 create_info_disp.u.pfnSetInstanceLoaderData = vkSetInstanceDispatch;
4747
4748 create_info_disp.pNext = loader_create_info.pNext;
4749 loader_create_info.pNext = &create_info_disp;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004750 res = fpCreateInstance(&loader_create_info, pAllocator, created_instance);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004751 } else {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004752 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4753 "loader_create_instance_chain: Failed to find "
4754 "\'vkCreateInstance\'");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004755 // Couldn't find CreateInstance function!
4756 res = VK_ERROR_INITIALIZATION_FAILED;
4757 }
4758
Mark Young39389872017-01-19 21:10:49 -07004759 if (res == VK_SUCCESS) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004760 loader_init_instance_core_dispatch_table(&inst->disp->layer_inst_disp, next_gipa, *created_instance);
Jon Ashburn4e8c4162016-03-08 15:21:30 -07004761 inst->instance = *created_instance;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004762 }
4763
4764 return res;
Jon Ashburn27cd5842015-05-12 17:26:48 -06004765}
4766
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004767void loader_activate_instance_layer_extensions(struct loader_instance *inst, VkInstance created_inst) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004768 loader_init_instance_extension_dispatch_table(&inst->disp->layer_inst_disp, inst->disp->layer_inst_disp.GetInstanceProcAddr,
4769 created_inst);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06004770}
4771
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004772VkResult loader_create_device_chain(const struct loader_physical_device_tramp *pd, const VkDeviceCreateInfo *pCreateInfo,
4773 const VkAllocationCallbacks *pAllocator, const struct loader_instance *inst,
4774 struct loader_device *dev) {
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004775 uint32_t activated_layers = 0;
4776 VkLayerDeviceLink *layer_device_link_info;
4777 VkLayerDeviceCreateInfo chain_info;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004778 VkDeviceCreateInfo loader_create_info;
4779 VkResult res;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06004780
Jamie Madill35127872017-03-15 16:17:46 -04004781 PFN_vkGetDeviceProcAddr fpGDPA = NULL, nextGDPA = loader_gpa_device_internal;
4782 PFN_vkGetInstanceProcAddr fpGIPA = NULL, nextGIPA = loader_gpa_instance_internal;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06004783
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004784 memcpy(&loader_create_info, pCreateInfo, sizeof(VkDeviceCreateInfo));
4785
Lenny Komow82e15e02017-10-02 15:08:53 -06004786 // Before we continue, we need to find out if the KHR_device_group extension is in the enabled list. If it is, we then
4787 // need to look for the corresponding VkDeviceGroupDeviceCreateInfoKHR struct in the device list. This is because we
Mark Young0f183a82017-02-28 09:58:04 -07004788 // need to replace all the incoming physical device values (which are really loader trampoline physical device values)
4789 // with the layer/ICD version.
Lenny Komowa1524852017-10-02 15:08:53 -06004790 {
Mark Young0f183a82017-02-28 09:58:04 -07004791 struct VkStructureHeader *pNext = (struct VkStructureHeader *)loader_create_info.pNext;
4792 struct VkStructureHeader *pPrev = (struct VkStructureHeader *)&loader_create_info;
4793 while (NULL != pNext) {
Lenny Komowa1524852017-10-02 15:08:53 -06004794 if (VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO == pNext->sType) {
Lenny Komow82e15e02017-10-02 15:08:53 -06004795 VkDeviceGroupDeviceCreateInfoKHR *cur_struct = (VkDeviceGroupDeviceCreateInfoKHR *)pNext;
Mark Young0f183a82017-02-28 09:58:04 -07004796 if (0 < cur_struct->physicalDeviceCount && NULL != cur_struct->pPhysicalDevices) {
Lenny Komow82e15e02017-10-02 15:08:53 -06004797 VkDeviceGroupDeviceCreateInfoKHR *temp_struct = loader_stack_alloc(sizeof(VkDeviceGroupDeviceCreateInfoKHR));
Mark Young0f183a82017-02-28 09:58:04 -07004798 VkPhysicalDevice *phys_dev_array = NULL;
4799 if (NULL == temp_struct) {
4800 return VK_ERROR_OUT_OF_HOST_MEMORY;
4801 }
Lenny Komow82e15e02017-10-02 15:08:53 -06004802 memcpy(temp_struct, cur_struct, sizeof(VkDeviceGroupDeviceCreateInfoKHR));
Mark Young0f183a82017-02-28 09:58:04 -07004803 phys_dev_array = loader_stack_alloc(sizeof(VkPhysicalDevice) * cur_struct->physicalDeviceCount);
4804 if (NULL == phys_dev_array) {
4805 return VK_ERROR_OUT_OF_HOST_MEMORY;
4806 }
4807
4808 // Before calling down, replace the incoming physical device values (which are really loader trampoline
4809 // physical devices) with the next layer (or possibly even the terminator) physical device values.
4810 struct loader_physical_device_tramp *cur_tramp;
4811 for (uint32_t phys_dev = 0; phys_dev < cur_struct->physicalDeviceCount; phys_dev++) {
4812 cur_tramp = (struct loader_physical_device_tramp *)cur_struct->pPhysicalDevices[phys_dev];
4813 phys_dev_array[phys_dev] = cur_tramp->phys_dev;
4814 }
4815 temp_struct->pPhysicalDevices = phys_dev_array;
4816
4817 // Replace the old struct in the pNext chain with this one.
4818 pPrev->pNext = (const void *)temp_struct;
4819 pNext = (struct VkStructureHeader *)(temp_struct);
4820 }
4821 break;
4822 }
4823
4824 pPrev = pNext;
4825 pNext = (struct VkStructureHeader *)(pPrev->pNext);
4826 }
4827 }
4828
Mark Young283fe1c2017-05-04 12:16:35 -06004829 layer_device_link_info = loader_stack_alloc(sizeof(VkLayerDeviceLink) * dev->expanded_activated_layer_list.count);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004830 if (!layer_device_link_info) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004831 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4832 "loader_create_device_chain: Failed to alloc Device objects"
4833 " for layer. Skipping Layer.");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004834 return VK_ERROR_OUT_OF_HOST_MEMORY;
David Pinedoa0a8a242015-06-24 15:29:18 -06004835 }
Jon Ashburn94e70492015-06-10 10:13:10 -06004836
Mark Young283fe1c2017-05-04 12:16:35 -06004837 if (dev->expanded_activated_layer_list.count > 0) {
Jon Ashburn72690f22016-03-29 12:52:13 -06004838 chain_info.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO;
4839 chain_info.function = VK_LAYER_LINK_INFO;
4840 chain_info.u.pLayerInfo = NULL;
Mark Young39389872017-01-19 21:10:49 -07004841 chain_info.pNext = loader_create_info.pNext;
Jon Ashburn72690f22016-03-29 12:52:13 -06004842 loader_create_info.pNext = &chain_info;
4843
Mark Young39389872017-01-19 21:10:49 -07004844 // Create instance chain of enabled layers
Mark Young283fe1c2017-05-04 12:16:35 -06004845 for (int32_t i = dev->expanded_activated_layer_list.count - 1; i >= 0; i--) {
4846 struct loader_layer_properties *layer_prop = &dev->expanded_activated_layer_list.list[i];
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004847 loader_platform_dl_handle lib_handle;
Mark Young39389872017-01-19 21:10:49 -07004848 bool functions_in_interface = false;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06004849
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004850 lib_handle = loader_open_layer_lib(inst, "device", layer_prop);
Mark Young39389872017-01-19 21:10:49 -07004851 if (!lib_handle) {
Courtney Goeltzenleuchter524b7e32016-01-14 16:06:06 -07004852 continue;
Jon Ashburn21c21ee2015-09-09 11:29:24 -06004853 }
Mark Young39389872017-01-19 21:10:49 -07004854
Mark Young0f183a82017-02-28 09:58:04 -07004855 // If we can negotiate an interface version, then we can also get everything we need from the one function
4856 // 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 -07004857 if (NULL == layer_prop->functions.negotiate_layer_interface) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004858 PFN_vkNegotiateLoaderLayerInterfaceVersion negotiate_interface = NULL;
4859 if (strlen(layer_prop->functions.str_negotiate_interface) == 0) {
4860 negotiate_interface = (PFN_vkNegotiateLoaderLayerInterfaceVersion)loader_platform_get_proc_address(
4861 lib_handle, "vkNegotiateLoaderLayerInterfaceVersion");
Mark Young39389872017-01-19 21:10:49 -07004862 } else {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004863 negotiate_interface = (PFN_vkNegotiateLoaderLayerInterfaceVersion)loader_platform_get_proc_address(
4864 lib_handle, layer_prop->functions.str_negotiate_interface);
Mark Young39389872017-01-19 21:10:49 -07004865 }
4866
4867 if (NULL != negotiate_interface) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004868 layer_prop->functions.negotiate_layer_interface = negotiate_interface;
Mark Young39389872017-01-19 21:10:49 -07004869
4870 VkNegotiateLayerInterface interface_struct;
4871
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004872 if (loader_get_layer_interface_version(negotiate_interface, &interface_struct)) {
Mark Youngdee312c2017-03-08 13:38:35 -07004873 // Go ahead and set the properties version to the correct value.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004874 layer_prop->interface_version = interface_struct.loaderLayerInterfaceVersion;
Mark Young39389872017-01-19 21:10:49 -07004875
Mark Young0f183a82017-02-28 09:58:04 -07004876 // If the interface is 2 or newer, we have access to the new GetPhysicalDeviceProcAddr
4877 // function, so grab it, and the other necessary functions, from the structure.
Mark Young39389872017-01-19 21:10:49 -07004878 if (interface_struct.loaderLayerInterfaceVersion > 1) {
4879 fpGIPA = interface_struct.pfnGetInstanceProcAddr;
4880 fpGDPA = interface_struct.pfnGetDeviceProcAddr;
4881 if (fpGIPA != NULL && fpGDPA) {
4882 // We've set the functions, so make sure we
4883 // don't do the unnecessary calls later.
4884 functions_in_interface = true;
4885 }
4886 }
4887 }
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004888 }
4889 }
4890
Mark Young39389872017-01-19 21:10:49 -07004891 if (!functions_in_interface) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004892 if ((fpGIPA = layer_prop->functions.get_instance_proc_addr) == NULL) {
Mark Young39389872017-01-19 21:10:49 -07004893 if (strlen(layer_prop->functions.str_gipa) == 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004894 fpGIPA = (PFN_vkGetInstanceProcAddr)loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
Mark Young39389872017-01-19 21:10:49 -07004895 layer_prop->functions.get_instance_proc_addr = fpGIPA;
4896 } else
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004897 fpGIPA =
4898 (PFN_vkGetInstanceProcAddr)loader_platform_get_proc_address(lib_handle, layer_prop->functions.str_gipa);
Mark Young39389872017-01-19 21:10:49 -07004899 if (!fpGIPA) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004900 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4901 "loader_create_device_chain: Failed to find "
4902 "\'vkGetInstanceProcAddr\' in layer %s. Skipping"
4903 " layer.",
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004904 layer_prop->lib_name);
Mark Young39389872017-01-19 21:10:49 -07004905 continue;
4906 }
4907 }
4908 if ((fpGDPA = layer_prop->functions.get_device_proc_addr) == NULL) {
4909 if (strlen(layer_prop->functions.str_gdpa) == 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004910 fpGDPA = (PFN_vkGetDeviceProcAddr)loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr");
Mark Young39389872017-01-19 21:10:49 -07004911 layer_prop->functions.get_device_proc_addr = fpGDPA;
4912 } else
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004913 fpGDPA =
4914 (PFN_vkGetDeviceProcAddr)loader_platform_get_proc_address(lib_handle, layer_prop->functions.str_gdpa);
Mark Young39389872017-01-19 21:10:49 -07004915 if (!fpGDPA) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004916 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Failed to find vkGetDeviceProcAddr in layer %s",
4917 layer_prop->lib_name);
Mark Young39389872017-01-19 21:10:49 -07004918 continue;
4919 }
4920 }
4921 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004922 layer_device_link_info[activated_layers].pNext = chain_info.u.pLayerInfo;
4923 layer_device_link_info[activated_layers].pfnNextGetInstanceProcAddr = nextGIPA;
4924 layer_device_link_info[activated_layers].pfnNextGetDeviceProcAddr = nextGDPA;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004925 chain_info.u.pLayerInfo = &layer_device_link_info[activated_layers];
4926 nextGIPA = fpGIPA;
4927 nextGDPA = fpGDPA;
4928
Lenny Komow7ddd4322017-10-16 15:03:37 -06004929 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 -07004930 layer_prop->lib_name);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004931
4932 activated_layers++;
Jon Ashburn94e70492015-06-10 10:13:10 -06004933 }
Jon Ashburn94e70492015-06-10 10:13:10 -06004934 }
4935
Jon Ashburncc407a22016-04-15 09:25:03 -06004936 VkDevice created_device = (VkDevice)dev;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004937 PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)nextGIPA(inst->instance, "vkCreateDevice");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004938 if (fpCreateDevice) {
Jon Ashburned8f2312016-03-31 10:52:22 -06004939 VkLayerDeviceCreateInfo create_info_disp;
4940
Jon Ashburncc407a22016-04-15 09:25:03 -06004941 create_info_disp.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO;
Jon Ashburned8f2312016-03-31 10:52:22 -06004942 create_info_disp.function = VK_LOADER_DATA_CALLBACK;
4943
4944 create_info_disp.u.pfnSetDeviceLoaderData = vkSetDeviceDispatch;
4945
4946 create_info_disp.pNext = loader_create_info.pNext;
4947 loader_create_info.pNext = &create_info_disp;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004948 res = fpCreateDevice(pd->phys_dev, &loader_create_info, pAllocator, &created_device);
Piers Daniellefbbfc12016-04-05 17:28:06 -06004949 if (res != VK_SUCCESS) {
4950 return res;
4951 }
Mark Young65cb3662016-11-07 13:27:02 -07004952 dev->chain_device = created_device;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004953 } else {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004954 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4955 "loader_create_device_chain: Failed to find \'vkCreateDevice\' "
4956 "in layer %s");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004957 // Couldn't find CreateDevice function!
4958 return VK_ERROR_INITIALIZATION_FAILED;
4959 }
Jon Ashburn94e70492015-06-10 10:13:10 -06004960
Mark Young65cb3662016-11-07 13:27:02 -07004961 // Initialize device dispatch table
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004962 loader_init_device_dispatch_table(&dev->loader_dispatch, nextGDPA, dev->chain_device);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004963
4964 return res;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06004965}
Jon Ashburnd38bfb12014-10-14 19:15:22 -06004966
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004967VkResult loader_validate_layers(const struct loader_instance *inst, const uint32_t layer_count,
4968 const char *const *ppEnabledLayerNames, const struct loader_layer_list *list) {
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06004969 struct loader_layer_properties *prop;
4970
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004971 for (uint32_t i = 0; i < layer_count; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004972 VkStringErrorFlags result = vk_string_validate(MaxLoaderStringLength, ppEnabledLayerNames[i]);
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004973 if (result != VK_STRING_ERROR_NONE) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004974 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4975 "loader_validate_layers: Device ppEnabledLayerNames "
4976 "contains string that is too long or is badly formed");
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004977 return VK_ERROR_LAYER_NOT_PRESENT;
4978 }
4979
Jon Ashburn23d36b12016-02-02 17:47:28 -07004980 prop = loader_get_layer_property(ppEnabledLayerNames[i], list);
Mark Youngf2079b92017-05-02 10:49:46 -06004981 if (NULL == prop) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004982 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngc8b807a2017-07-14 17:11:31 -06004983 "loader_validate_layers: Layer %d does not exist in the list of available layers", i);
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06004984 return VK_ERROR_LAYER_NOT_PRESENT;
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06004985 }
4986 }
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06004987 return VK_SUCCESS;
4988}
4989
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004990VkResult loader_validate_instance_extensions(const struct loader_instance *inst, const struct loader_extension_list *icd_exts,
4991 const struct loader_layer_list *instance_layers,
4992 const VkInstanceCreateInfo *pCreateInfo) {
Jon Ashburn5c042ea2015-08-04 11:14:18 -06004993 VkExtensionProperties *extension_prop;
Mark Young48cea0c2017-05-26 14:39:54 -06004994 char *env_value;
4995 bool check_if_known = true;
Lenny Komow3b958392018-01-17 13:53:59 -07004996 VkResult res = VK_SUCCESS;
4997
4998 struct loader_layer_list active_layers;
4999 struct loader_layer_list expanded_layers;
5000 memset(&active_layers, 0, sizeof(active_layers));
5001 memset(&expanded_layers, 0, sizeof(expanded_layers));
5002 if (!loader_init_layer_list(inst, &active_layers)) {
5003 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5004 goto out;
5005 }
5006 if (!loader_init_layer_list(inst, &expanded_layers)) {
5007 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5008 goto out;
5009 }
5010
5011 // Build the lists of active layers (including metalayers) and expanded layers (with metalayers resolved to their components)
5012 loader_add_implicit_layers(inst, &active_layers, &expanded_layers, instance_layers);
5013 loader_add_env_layers(inst, VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER, ENABLED_LAYERS_ENV, &active_layers, &expanded_layers,
5014 instance_layers);
5015 res = loader_add_layer_names_to_list(inst, &active_layers, &expanded_layers, pCreateInfo->enabledLayerCount,
5016 pCreateInfo->ppEnabledLayerNames, instance_layers);
5017 if (VK_SUCCESS != res) {
5018 goto out;
5019 }
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06005020
Jon Ashburnf19916e2016-01-11 13:12:43 -07005021 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005022 VkStringErrorFlags result = vk_string_validate(MaxLoaderStringLength, pCreateInfo->ppEnabledExtensionNames[i]);
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07005023 if (result != VK_STRING_ERROR_NONE) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005024 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young48cea0c2017-05-26 14:39:54 -06005025 "loader_validate_instance_extensions: Instance ppEnabledExtensionNames contains "
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005026 "string that is too long or is badly formed");
Lenny Komow3b958392018-01-17 13:53:59 -07005027 res = VK_ERROR_EXTENSION_NOT_PRESENT;
5028 goto out;
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07005029 }
5030
Mark Young48cea0c2017-05-26 14:39:54 -06005031 // Check if a user wants to disable the instance extension filtering behavior
5032 env_value = loader_getenv("VK_LOADER_DISABLE_INST_EXT_FILTER", inst);
5033 if (NULL != env_value && atoi(env_value) != 0) {
5034 check_if_known = false;
Lenny Komow4053b812016-12-29 16:27:28 -07005035 }
Mark Young48cea0c2017-05-26 14:39:54 -06005036 loader_free_getenv(env_value, inst);
Lenny Komow4053b812016-12-29 16:27:28 -07005037
Mark Young48cea0c2017-05-26 14:39:54 -06005038 if (check_if_known) {
5039 // See if the extension is in the list of supported extensions
5040 bool found = false;
5041 for (uint32_t j = 0; LOADER_INSTANCE_EXTENSIONS[j] != NULL; j++) {
5042 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], LOADER_INSTANCE_EXTENSIONS[j]) == 0) {
5043 found = true;
5044 break;
5045 }
5046 }
5047
5048 // If it isn't in the list, return an error
5049 if (!found) {
5050 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5051 "loader_validate_instance_extensions: Extension %s not found in list of known instance extensions.",
5052 pCreateInfo->ppEnabledExtensionNames[i]);
Lenny Komow3b958392018-01-17 13:53:59 -07005053 res = VK_ERROR_EXTENSION_NOT_PRESENT;
5054 goto out;
Mark Young48cea0c2017-05-26 14:39:54 -06005055 }
Lenny Komow4053b812016-12-29 16:27:28 -07005056 }
5057
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005058 extension_prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i], icd_exts);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06005059
5060 if (extension_prop) {
5061 continue;
5062 }
5063
5064 extension_prop = NULL;
5065
Lenny Komow3b958392018-01-17 13:53:59 -07005066 // Not in global list, search expanded layer extension list
5067 for (uint32_t j = 0; NULL == extension_prop && j < expanded_layers.count; ++j) {
5068 extension_prop =
5069 get_extension_property(pCreateInfo->ppEnabledExtensionNames[i], &expanded_layers.list[j].instance_extension_list);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06005070 }
5071
5072 if (!extension_prop) {
Mark Youngb6399312017-01-10 14:22:15 -07005073 // Didn't find extension name in any of the global layers, error out
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005074 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young48cea0c2017-05-26 14:39:54 -06005075 "loader_validate_instance_extensions: Instance extension %s not supported by available ICDs or enabled "
5076 "layers.",
5077 pCreateInfo->ppEnabledExtensionNames[i]);
Lenny Komow3b958392018-01-17 13:53:59 -07005078 res = VK_ERROR_EXTENSION_NOT_PRESENT;
5079 goto out;
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06005080 }
5081 }
Lenny Komow3b958392018-01-17 13:53:59 -07005082
5083out:
5084 loader_destroy_layer_list(inst, NULL, &active_layers);
5085 loader_destroy_layer_list(inst, NULL, &expanded_layers);
5086 return res;
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06005087}
5088
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005089VkResult loader_validate_device_extensions(struct loader_physical_device_tramp *phys_dev,
5090 const struct loader_layer_list *activated_device_layers,
5091 const struct loader_extension_list *icd_exts, const VkDeviceCreateInfo *pCreateInfo) {
Jon Ashburn5c042ea2015-08-04 11:14:18 -06005092 VkExtensionProperties *extension_prop;
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06005093 struct loader_layer_properties *layer_prop;
5094
Jon Ashburnf19916e2016-01-11 13:12:43 -07005095 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005096 VkStringErrorFlags result = vk_string_validate(MaxLoaderStringLength, pCreateInfo->ppEnabledExtensionNames[i]);
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07005097 if (result != VK_STRING_ERROR_NONE) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005098 loader_log(phys_dev->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young48cea0c2017-05-26 14:39:54 -06005099 "loader_validate_device_extensions: Device ppEnabledExtensionNames contains "
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005100 "string that is too long or is badly formed");
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07005101 return VK_ERROR_EXTENSION_NOT_PRESENT;
5102 }
5103
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06005104 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
Jon Ashburn014438f2016-03-01 19:51:07 -07005105 extension_prop = get_extension_property(extension_name, icd_exts);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06005106
5107 if (extension_prop) {
5108 continue;
5109 }
5110
Mark Youngb6399312017-01-10 14:22:15 -07005111 // Not in global list, search activated layer extension lists
Jon Ashburn471f44c2016-01-13 12:51:43 -07005112 for (uint32_t j = 0; j < activated_device_layers->count; j++) {
5113 layer_prop = &activated_device_layers->list[j];
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06005114
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005115 extension_prop = get_dev_extension_property(extension_name, &layer_prop->device_extension_list);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06005116 if (extension_prop) {
Mark Youngb6399312017-01-10 14:22:15 -07005117 // Found the extension in one of the layers enabled by the app.
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06005118 break;
5119 }
5120 }
5121
5122 if (!extension_prop) {
Mark Youngb6399312017-01-10 14:22:15 -07005123 // Didn't find extension name in any of the device layers, error out
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005124 loader_log(phys_dev->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young48cea0c2017-05-26 14:39:54 -06005125 "loader_validate_device_extensions: Device extension %s not supported by selected physical device "
5126 "or enabled layers.",
5127 pCreateInfo->ppEnabledExtensionNames[i]);
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06005128 return VK_ERROR_EXTENSION_NOT_PRESENT;
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06005129 }
5130 }
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06005131 return VK_SUCCESS;
5132}
5133
Mark Youngb6399312017-01-10 14:22:15 -07005134// Terminator functions for the Instance chain
5135// All named terminator_<Vulakn API name>
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005136VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
5137 const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) {
Mark Young0153e0b2016-11-03 14:27:13 -06005138 struct loader_icd_term *icd_term;
Jon Ashburn5c042ea2015-08-04 11:14:18 -06005139 VkExtensionProperties *prop;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06005140 char **filtered_extension_names = NULL;
5141 VkInstanceCreateInfo icd_create_info;
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06005142 VkResult res = VK_SUCCESS;
Mark Young8b4edb52016-11-11 09:31:55 -07005143 bool one_icd_successful = false;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07005144
Jon Ashburncc407a22016-04-15 09:25:03 -06005145 struct loader_instance *ptr_instance = (struct loader_instance *)*pInstance;
Tony Barbour3c78ff42015-12-04 13:24:39 -07005146 memcpy(&icd_create_info, pCreateInfo, sizeof(icd_create_info));
5147
Jon Ashburnf19916e2016-01-11 13:12:43 -07005148 icd_create_info.enabledLayerCount = 0;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06005149 icd_create_info.ppEnabledLayerNames = NULL;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06005150
Mark Youngb6399312017-01-10 14:22:15 -07005151 // NOTE: Need to filter the extensions to only those supported by the ICD.
5152 // No ICD will advertise support for layers. An ICD library could
5153 // support a layer, but it would be independent of the actual ICD,
5154 // just in the same library.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005155 filtered_extension_names = loader_stack_alloc(pCreateInfo->enabledExtensionCount * sizeof(char *));
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06005156 if (!filtered_extension_names) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005157 loader_log(ptr_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young48cea0c2017-05-26 14:39:54 -06005158 "terminator_CreateInstance: Failed create extension name array for %d extensions",
Mark Youngb6399312017-01-10 14:22:15 -07005159 pCreateInfo->enabledExtensionCount);
Mark Young3a587792016-08-19 15:25:08 -06005160 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5161 goto out;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06005162 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005163 icd_create_info.ppEnabledExtensionNames = (const char *const *)filtered_extension_names;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06005164
Mark Young0153e0b2016-11-03 14:27:13 -06005165 for (uint32_t i = 0; i < ptr_instance->icd_tramp_list.count; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005166 icd_term = loader_icd_add(ptr_instance, &ptr_instance->icd_tramp_list.scanned_list[i]);
Mark Young0153e0b2016-11-03 14:27:13 -06005167 if (NULL == icd_term) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005168 loader_log(ptr_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngc8b807a2017-07-14 17:11:31 -06005169 "terminator_CreateInstance: Failed to add ICD %d to ICD trampoline list.", i);
Mark Young3a587792016-08-19 15:25:08 -06005170 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5171 goto out;
Mark Young0ad83132016-06-30 13:02:42 -06005172 }
Mark Young6267ae62017-01-12 12:27:19 -07005173
Lenny Komowa44cc852017-09-12 22:54:21 -06005174 // If any error happens after here, we need to remove the ICD from the list,
5175 // because we've already added it, but haven't validated it
5176
Mark Young0ad83132016-06-30 13:02:42 -06005177 icd_create_info.enabledExtensionCount = 0;
5178 struct loader_extension_list icd_exts;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06005179
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005180 loader_log(ptr_instance, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Build ICD instance extension list");
Mark Young0f183a82017-02-28 09:58:04 -07005181 // traverse scanned icd list adding non-duplicate extensions to the list
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005182 res = loader_init_generic_list(ptr_instance, (struct loader_generic_list *)&icd_exts, sizeof(VkExtensionProperties));
Mark Young3a587792016-08-19 15:25:08 -06005183 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
5184 // If out of memory, bail immediately.
5185 goto out;
5186 } else if (VK_SUCCESS != res) {
Mark Young7e471292016-09-06 09:53:45 -06005187 // Something bad happened with this ICD, so free it and try the
5188 // next.
Mark Young0153e0b2016-11-03 14:27:13 -06005189 ptr_instance->icd_terms = icd_term->next;
5190 icd_term->next = NULL;
5191 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
Mark Young3a587792016-08-19 15:25:08 -06005192 continue;
5193 }
5194
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005195 res = loader_add_instance_extensions(ptr_instance, icd_term->scanned_icd->EnumerateInstanceExtensionProperties,
5196 icd_term->scanned_icd->lib_name, &icd_exts);
Mark Youngdb13a2a2016-09-06 13:53:03 -06005197 if (VK_SUCCESS != res) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005198 loader_destroy_generic_list(ptr_instance, (struct loader_generic_list *)&icd_exts);
Mark Youngdb13a2a2016-09-06 13:53:03 -06005199 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
5200 // If out of memory, bail immediately.
5201 goto out;
5202 } else {
Mark Young0f183a82017-02-28 09:58:04 -07005203 // Something bad happened with this ICD, so free it and try the next.
Mark Young0153e0b2016-11-03 14:27:13 -06005204 ptr_instance->icd_terms = icd_term->next;
5205 icd_term->next = NULL;
5206 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
Mark Youngdb13a2a2016-09-06 13:53:03 -06005207 continue;
5208 }
Mark Young3a587792016-08-19 15:25:08 -06005209 }
Courtney Goeltzenleuchter36eeb742015-12-21 16:41:47 -07005210
Mark Young0ad83132016-06-30 13:02:42 -06005211 for (uint32_t j = 0; j < pCreateInfo->enabledExtensionCount; j++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005212 prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[j], &icd_exts);
Mark Young0ad83132016-06-30 13:02:42 -06005213 if (prop) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005214 filtered_extension_names[icd_create_info.enabledExtensionCount] = (char *)pCreateInfo->ppEnabledExtensionNames[j];
Mark Young0ad83132016-06-30 13:02:42 -06005215 icd_create_info.enabledExtensionCount++;
Jon Ashburn46888392015-01-29 15:45:51 -07005216 }
5217 }
Mark Young0ad83132016-06-30 13:02:42 -06005218
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005219 loader_destroy_generic_list(ptr_instance, (struct loader_generic_list *)&icd_exts);
Mark Young0ad83132016-06-30 13:02:42 -06005220
Lenny Komowe12b3362017-11-03 13:14:32 -06005221 // Get the driver version from vkEnumerateInstanceVersion
5222 uint32_t icd_version = VK_API_VERSION_1_0;
5223 PFN_vkEnumerateInstanceVersion icd_enumerate_instance_version = (PFN_vkEnumerateInstanceVersion)
Lenny Komowd74b3682017-11-07 10:42:19 -07005224 icd_term->scanned_icd->GetInstanceProcAddr(NULL, "vkEnumerateInstanceVersion");
Lenny Komowe12b3362017-11-03 13:14:32 -06005225 VkResult icd_result = VK_SUCCESS;
5226 if (icd_enumerate_instance_version != NULL) {
5227 icd_result = icd_enumerate_instance_version(&icd_version);
5228 if (icd_result != VK_SUCCESS) {
5229 icd_version = VK_API_VERSION_1_0;
5230 loader_log(ptr_instance, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "terminator_CreateInstance: ICD \"%s\" "
5231 "vkEnumerateInstanceVersion returned error. The ICD will be treated as a 1.0 ICD",
5232 icd_term->scanned_icd->lib_name);
5233 }
5234 }
5235
Lenny Komowa1524852017-10-02 15:08:53 -06005236 // Create an instance, substituting the version to 1.0 if necessary
Lenny Komow838df732017-10-11 13:39:33 -06005237 VkApplicationInfo icd_app_info;
Lenny Komow05c419b2017-10-11 09:20:52 -06005238 uint32_t requested_version = pCreateInfo == NULL || pCreateInfo->pApplicationInfo == NULL ? VK_API_VERSION_1_0 : pCreateInfo->pApplicationInfo->apiVersion;
Lenny Komowe12b3362017-11-03 13:14:32 -06005239 if (requested_version > icd_version) {
Lenny Komowa1524852017-10-02 15:08:53 -06005240 if (icd_create_info.pApplicationInfo == NULL) {
5241 memset(&icd_app_info, 0, sizeof(icd_app_info));
5242 } else {
5243 memcpy(&icd_app_info, icd_create_info.pApplicationInfo, sizeof(icd_app_info));
5244 }
5245 icd_app_info.apiVersion = icd_term->scanned_icd->api_version;
5246 icd_create_info.pApplicationInfo = &icd_app_info;
5247 }
Lenny Komowe12b3362017-11-03 13:14:32 -06005248 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 -07005249 if (VK_ERROR_OUT_OF_HOST_MEMORY == icd_result) {
Mark Young3a587792016-08-19 15:25:08 -06005250 // If out of memory, bail immediately.
Mark Young8b4edb52016-11-11 09:31:55 -07005251 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young3a587792016-08-19 15:25:08 -06005252 goto out;
Mark Young8b4edb52016-11-11 09:31:55 -07005253 } else if (VK_SUCCESS != icd_result) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005254 loader_log(ptr_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
5255 "terminator_CreateInstance: Failed to CreateInstance in "
5256 "ICD %d. Skipping ICD.",
Mark Youngb6399312017-01-10 14:22:15 -07005257 i);
Mark Young0153e0b2016-11-03 14:27:13 -06005258 ptr_instance->icd_terms = icd_term->next;
5259 icd_term->next = NULL;
5260 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
Mark Young3a587792016-08-19 15:25:08 -06005261 continue;
5262 }
Mark Young0ad83132016-06-30 13:02:42 -06005263
Mark Young0f183a82017-02-28 09:58:04 -07005264 if (!loader_icd_init_entries(icd_term, icd_term->instance,
5265 ptr_instance->icd_tramp_list.scanned_list[i].GetInstanceProcAddr)) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005266 loader_log(ptr_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
5267 "terminator_CreateInstance: Failed to CreateInstance and find "
5268 "entrypoints with ICD. Skipping ICD.");
Lenny Komowa44cc852017-09-12 22:54:21 -06005269 ptr_instance->icd_terms = icd_term->next;
5270 icd_term->next = NULL;
5271 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
Mark Young3a587792016-08-19 15:25:08 -06005272 continue;
Mark Young0ad83132016-06-30 13:02:42 -06005273 }
Mark Young8b4edb52016-11-11 09:31:55 -07005274
5275 // If we made it this far, at least one ICD was successful
5276 one_icd_successful = true;
Jon Ashburn46888392015-01-29 15:45:51 -07005277 }
Jon Ashburn1beab2d2015-01-26 14:51:40 -07005278
Mark Young0f183a82017-02-28 09:58:04 -07005279 // If no ICDs were added to instance list and res is unchanged from it's initial value, the loader was unable to
5280 // find a suitable ICD.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005281 if (VK_SUCCESS == res && (ptr_instance->icd_terms == NULL || !one_icd_successful)) {
Mark Young3a587792016-08-19 15:25:08 -06005282 res = VK_ERROR_INCOMPATIBLE_DRIVER;
5283 }
5284
5285out:
5286
5287 if (VK_SUCCESS != res) {
Mark Young0153e0b2016-11-03 14:27:13 -06005288 while (NULL != ptr_instance->icd_terms) {
5289 icd_term = ptr_instance->icd_terms;
5290 ptr_instance->icd_terms = icd_term->next;
5291 if (NULL != icd_term->instance) {
Mark Young0f183a82017-02-28 09:58:04 -07005292 icd_term->dispatch.DestroyInstance(icd_term->instance, pAllocator);
Mark Young3a587792016-08-19 15:25:08 -06005293 }
Mark Young0153e0b2016-11-03 14:27:13 -06005294 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06005295 }
Ian Elliotteb450762015-02-05 15:19:15 -07005296 }
Jon Ashburn46888392015-01-29 15:45:51 -07005297
Mark Young3a587792016-08-19 15:25:08 -06005298 return res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07005299}
5300
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005301VKAPI_ATTR void VKAPI_CALL terminator_DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
Courtney Goeltzenleuchterdeceded2015-06-08 15:04:02 -06005302 struct loader_instance *ptr_instance = loader_instance(instance);
Karl Schultze2ef9e62017-01-13 14:01:35 -07005303 if (NULL == ptr_instance) {
5304 return;
5305 }
Mark Young0153e0b2016-11-03 14:27:13 -06005306 struct loader_icd_term *icd_terms = ptr_instance->icd_terms;
5307 struct loader_icd_term *next_icd_term;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07005308
5309 // Remove this instance from the list of instances:
5310 struct loader_instance *prev = NULL;
5311 struct loader_instance *next = loader.instances;
5312 while (next != NULL) {
5313 if (next == ptr_instance) {
5314 // Remove this instance from the list:
5315 if (prev)
5316 prev->next = next->next;
Jon Ashburnc5c49602015-02-03 09:26:59 -07005317 else
5318 loader.instances = next->next;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07005319 break;
5320 }
5321 prev = next;
5322 next = next->next;
5323 }
Jon Ashburn1beab2d2015-01-26 14:51:40 -07005324
Mark Young0153e0b2016-11-03 14:27:13 -06005325 while (NULL != icd_terms) {
5326 if (icd_terms->instance) {
Mark Young0f183a82017-02-28 09:58:04 -07005327 icd_terms->dispatch.DestroyInstance(icd_terms->instance, pAllocator);
Tony Barbourf20f87b2015-04-22 09:02:32 -06005328 }
Mark Young0153e0b2016-11-03 14:27:13 -06005329 next_icd_term = icd_terms->next;
5330 icd_terms->instance = VK_NULL_HANDLE;
5331 loader_icd_destroy(ptr_instance, icd_terms, pAllocator);
Jon Ashburna6fd2612015-06-16 14:43:19 -06005332
Mark Young0153e0b2016-11-03 14:27:13 -06005333 icd_terms = next_icd_term;
Jon Ashburn46888392015-01-29 15:45:51 -07005334 }
Jon Ashburn491cd042016-05-16 14:01:18 -06005335
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005336 loader_delete_layer_properties(ptr_instance, &ptr_instance->instance_layer_list);
Mark Young0153e0b2016-11-03 14:27:13 -06005337 loader_scanned_icd_clear(ptr_instance, &ptr_instance->icd_tramp_list);
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005338 loader_destroy_generic_list(ptr_instance, (struct loader_generic_list *)&ptr_instance->ext_list);
Mark Young39389872017-01-19 21:10:49 -07005339 if (NULL != ptr_instance->phys_devs_term) {
Mark Young0193d652016-12-28 16:10:10 -07005340 for (uint32_t i = 0; i < ptr_instance->phys_dev_count_term; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005341 loader_instance_heap_free(ptr_instance, ptr_instance->phys_devs_term[i]);
Lenny Komow8a1f8a52016-12-20 15:35:11 -07005342 }
Mark Young0ad83132016-06-30 13:02:42 -06005343 loader_instance_heap_free(ptr_instance, ptr_instance->phys_devs_term);
Lenny Komow8a1f8a52016-12-20 15:35:11 -07005344 }
Mark Youngd66edd52017-03-10 17:31:18 -07005345 if (NULL != ptr_instance->phys_dev_groups_term) {
5346 for (uint32_t i = 0; i < ptr_instance->phys_dev_group_count_term; i++) {
5347 loader_instance_heap_free(ptr_instance, ptr_instance->phys_dev_groups_term[i]);
5348 }
5349 loader_instance_heap_free(ptr_instance, ptr_instance->phys_dev_groups_term);
5350 }
Jon Ashburnfc1031e2015-11-17 15:31:02 -07005351 loader_free_dev_ext_table(ptr_instance);
Mark Young39389872017-01-19 21:10:49 -07005352 loader_free_phys_dev_ext_table(ptr_instance);
Jon Ashburn1beab2d2015-01-26 14:51:40 -07005353}
5354
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005355VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo,
5356 const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
Mark Young0ad83132016-06-30 13:02:42 -06005357 VkResult res = VK_SUCCESS;
Mark Young0153e0b2016-11-03 14:27:13 -06005358 struct loader_physical_device_term *phys_dev_term;
5359 phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
5360 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Jon Ashburn24cd4be2015-11-01 14:04:06 -07005361
Jon Ashburncc407a22016-04-15 09:25:03 -06005362 struct loader_device *dev = (struct loader_device *)*pDevice;
Mark Young0f183a82017-02-28 09:58:04 -07005363 PFN_vkCreateDevice fpCreateDevice = icd_term->dispatch.CreateDevice;
Mark Young0ad83132016-06-30 13:02:42 -06005364 struct loader_extension_list icd_exts;
5365
Joey Bzdekc2536de2017-10-23 17:13:33 -06005366 struct VkStructureHeader *caller_dgci_container = NULL;
Mike Schuchardt51390c52018-02-06 16:56:31 -07005367 VkDeviceGroupDeviceCreateInfoKHR *caller_dgci = NULL;
Joey Bzdekc2536de2017-10-23 17:13:33 -06005368
Mark Young65cb3662016-11-07 13:27:02 -07005369 dev->phys_dev_term = phys_dev_term;
5370
Mark Young0ad83132016-06-30 13:02:42 -06005371 icd_exts.list = NULL;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06005372
Jon Ashburn1530c342016-02-26 13:14:27 -07005373 if (fpCreateDevice == NULL) {
Mark Young0153e0b2016-11-03 14:27:13 -06005374 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07005375 "terminator_CreateDevice: No vkCreateDevice command exposed "
5376 "by ICD %s",
Mark Young0153e0b2016-11-03 14:27:13 -06005377 icd_term->scanned_icd->lib_name);
Mark Young0ad83132016-06-30 13:02:42 -06005378 res = VK_ERROR_INITIALIZATION_FAILED;
5379 goto out;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06005380 }
5381
Jon Ashburn1530c342016-02-26 13:14:27 -07005382 VkDeviceCreateInfo localCreateInfo;
5383 memcpy(&localCreateInfo, pCreateInfo, sizeof(localCreateInfo));
Jon Ashburn1530c342016-02-26 13:14:27 -07005384
Mark Youngb6399312017-01-10 14:22:15 -07005385 // NOTE: Need to filter the extensions to only those supported by the ICD.
Mark Younge1ea9012017-03-09 14:17:40 -07005386 // No ICD will advertise support for layers. An ICD library could support a layer,
5387 // but it would be independent of the actual ICD, just in the same library.
Jon Ashburn1530c342016-02-26 13:14:27 -07005388 char **filtered_extension_names = NULL;
Mark Younge1ea9012017-03-09 14:17:40 -07005389 if (0 < pCreateInfo->enabledExtensionCount) {
5390 filtered_extension_names = loader_stack_alloc(pCreateInfo->enabledExtensionCount * sizeof(char *));
5391 if (NULL == filtered_extension_names) {
5392 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5393 "terminator_CreateDevice: Failed to create extension name "
5394 "storage for %d extensions %d",
5395 pCreateInfo->enabledExtensionCount);
5396 return VK_ERROR_OUT_OF_HOST_MEMORY;
5397 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06005398 }
5399
Jon Ashburn1530c342016-02-26 13:14:27 -07005400 localCreateInfo.enabledLayerCount = 0;
5401 localCreateInfo.ppEnabledLayerNames = NULL;
5402
5403 localCreateInfo.enabledExtensionCount = 0;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005404 localCreateInfo.ppEnabledExtensionNames = (const char *const *)filtered_extension_names;
Jon Ashburn1530c342016-02-26 13:14:27 -07005405
Mark Youngb6399312017-01-10 14:22:15 -07005406 // Get the physical device (ICD) extensions
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005407 res = loader_init_generic_list(icd_term->this_instance, (struct loader_generic_list *)&icd_exts, sizeof(VkExtensionProperties));
Mark Young3a587792016-08-19 15:25:08 -06005408 if (VK_SUCCESS != res) {
Mark Young0ad83132016-06-30 13:02:42 -06005409 goto out;
Jon Ashburn014438f2016-03-01 19:51:07 -07005410 }
5411
Mark Young0f183a82017-02-28 09:58:04 -07005412 res = loader_add_device_extensions(icd_term->this_instance, icd_term->dispatch.EnumerateDeviceExtensionProperties,
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005413 phys_dev_term->phys_dev, icd_term->scanned_icd->lib_name, &icd_exts);
Jon Ashburn014438f2016-03-01 19:51:07 -07005414 if (res != VK_SUCCESS) {
Mark Young0ad83132016-06-30 13:02:42 -06005415 goto out;
Jon Ashburn014438f2016-03-01 19:51:07 -07005416 }
5417
Jon Ashburn1530c342016-02-26 13:14:27 -07005418 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
5419 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005420 VkExtensionProperties *prop = get_extension_property(extension_name, &icd_exts);
Jon Ashburn1530c342016-02-26 13:14:27 -07005421 if (prop) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005422 filtered_extension_names[localCreateInfo.enabledExtensionCount] = (char *)extension_name;
Jon Ashburn1530c342016-02-26 13:14:27 -07005423 localCreateInfo.enabledExtensionCount++;
Mark Young9a3ddd42016-10-21 16:25:47 -06005424 } else {
Lenny Komow8314e542018-01-03 10:37:54 -07005425 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005426 "vkCreateDevice extension %s not available for "
5427 "devices associated with ICD %s",
Mark Young0153e0b2016-11-03 14:27:13 -06005428 extension_name, icd_term->scanned_icd->lib_name);
Jon Ashburn1530c342016-02-26 13:14:27 -07005429 }
5430 }
5431
Mark Young0f183a82017-02-28 09:58:04 -07005432 // 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 -06005433 // corresponding VkDeviceGroupDeviceCreateInfo struct in the device list and replace all the physical device values (which
Mark Young0f183a82017-02-28 09:58:04 -07005434 // are really loader physical device terminator values) with the ICD versions.
Lenny Komowa1524852017-10-02 15:08:53 -06005435 //if (icd_term->this_instance->enabled_known_extensions.khr_device_group_creation == 1) {
5436 {
Mark Young0f183a82017-02-28 09:58:04 -07005437 struct VkStructureHeader *pNext = (struct VkStructureHeader *)localCreateInfo.pNext;
5438 struct VkStructureHeader *pPrev = (struct VkStructureHeader *)&localCreateInfo;
5439 while (NULL != pNext) {
Lenny Komowa1524852017-10-02 15:08:53 -06005440 if (VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO == pNext->sType) {
5441 VkDeviceGroupDeviceCreateInfo *cur_struct = (VkDeviceGroupDeviceCreateInfo *)pNext;
Mark Young0f183a82017-02-28 09:58:04 -07005442 if (0 < cur_struct->physicalDeviceCount && NULL != cur_struct->pPhysicalDevices) {
Lenny Komowa1524852017-10-02 15:08:53 -06005443 VkDeviceGroupDeviceCreateInfo *temp_struct = loader_stack_alloc(sizeof(VkDeviceGroupDeviceCreateInfo));
Mark Young0f183a82017-02-28 09:58:04 -07005444 VkPhysicalDevice *phys_dev_array = NULL;
5445 if (NULL == temp_struct) {
5446 return VK_ERROR_OUT_OF_HOST_MEMORY;
5447 }
Lenny Komowa1524852017-10-02 15:08:53 -06005448 memcpy(temp_struct, cur_struct, sizeof(VkDeviceGroupDeviceCreateInfo));
Mark Young0f183a82017-02-28 09:58:04 -07005449 phys_dev_array = loader_stack_alloc(sizeof(VkPhysicalDevice) * cur_struct->physicalDeviceCount);
5450 if (NULL == phys_dev_array) {
5451 return VK_ERROR_OUT_OF_HOST_MEMORY;
5452 }
5453
5454 // Before calling down, replace the incoming physical device values (which are really loader terminator
5455 // physical devices) with the ICDs physical device values.
5456 struct loader_physical_device_term *cur_term;
5457 for (uint32_t phys_dev = 0; phys_dev < cur_struct->physicalDeviceCount; phys_dev++) {
5458 cur_term = (struct loader_physical_device_term *)cur_struct->pPhysicalDevices[phys_dev];
5459 phys_dev_array[phys_dev] = cur_term->phys_dev;
5460 }
5461 temp_struct->pPhysicalDevices = phys_dev_array;
5462
Joey Bzdekc2536de2017-10-23 17:13:33 -06005463 // Keep track of pointers to restore pNext chain before returning
5464 caller_dgci_container = pPrev;
5465 caller_dgci = cur_struct;
5466
Mark Young0f183a82017-02-28 09:58:04 -07005467 // Replace the old struct in the pNext chain with this one.
5468 pPrev->pNext = (const void *)temp_struct;
5469 pNext = (struct VkStructureHeader *)(temp_struct);
5470 }
5471 break;
5472 }
5473
5474 pPrev = pNext;
5475 pNext = (struct VkStructureHeader *)(pPrev->pNext);
5476 }
5477 }
5478
Lenny Komow34d78d22017-05-24 15:47:15 -06005479 // Handle loader emulation for structs that are not supported by the ICD:
5480 // Presently, the emulation leaves the pNext chain alone. This means that the ICD will receive items in the chain which
5481 // are not recognized by the ICD. If this causes the ICD to fail, then the items would have to be removed here. The current
5482 // implementation does not remove them because copying the pNext chain would be impossible if the loader does not recognize
5483 // 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 -06005484 //if (icd_term->dispatch.GetPhysicalDeviceFeatures2 == NULL && icd_term->dispatch.GetPhysicalDeviceFeatures2KHR == NULL) {
5485 {
Lenny Komow34d78d22017-05-24 15:47:15 -06005486 const void *pNext = localCreateInfo.pNext;
5487 while (pNext != NULL) {
5488 switch (*(VkStructureType *)pNext) {
Lenny Komowa1524852017-10-02 15:08:53 -06005489 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2: {
Lenny Komow34d78d22017-05-24 15:47:15 -06005490 const VkPhysicalDeviceFeatures2KHR *features = pNext;
5491
Lenny Komowa1524852017-10-02 15:08:53 -06005492 if (icd_term->dispatch.GetPhysicalDeviceFeatures2 == NULL && icd_term->dispatch.GetPhysicalDeviceFeatures2KHR == NULL) {
5493 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
5494 "vkCreateDevice: Emulating handling of VkPhysicalDeviceFeatures2 in pNext chain for ICD \"%s\"",
5495 icd_term->scanned_icd->lib_name);
5496
5497 // Verify that VK_KHR_get_physical_device_properties2 is enabled
5498 if (icd_term->this_instance->enabled_known_extensions.khr_get_physical_device_properties2) {
5499 localCreateInfo.pEnabledFeatures = &features->features;
5500 }
Lenny Komow34d78d22017-05-24 15:47:15 -06005501 }
5502
5503 // Leave this item in the pNext chain for now
5504
5505 pNext = features->pNext;
5506 break;
5507 }
5508
Lenny Komowa1524852017-10-02 15:08:53 -06005509 case VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO: {
Lenny Komow82e15e02017-10-02 15:08:53 -06005510 const VkDeviceGroupDeviceCreateInfoKHR *group_info = pNext;
Lenny Komow34d78d22017-05-24 15:47:15 -06005511
Lenny Komowa1524852017-10-02 15:08:53 -06005512 if (icd_term->dispatch.EnumeratePhysicalDeviceGroups == NULL && icd_term->dispatch.EnumeratePhysicalDeviceGroupsKHR == NULL) {
5513 loader_log(
5514 icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
5515 "vkCreateDevice: Emulating handling of VkPhysicalDeviceGroupProperties in pNext chain for ICD \"%s\"",
5516 icd_term->scanned_icd->lib_name);
5517
5518 // The group must contain only this one device, since physical device groups aren't actually supported
5519 if (group_info->physicalDeviceCount != 1) {
5520 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Lenny Komow34d78d22017-05-24 15:47:15 -06005521 "vkCreateDevice: Emulation failed to create device from device group info");
Lenny Komowa1524852017-10-02 15:08:53 -06005522 res = VK_ERROR_INITIALIZATION_FAILED;
5523 goto out;
5524 }
Lenny Komow34d78d22017-05-24 15:47:15 -06005525 }
5526
5527 // Nothing needs to be done here because we're leaving the item in the pNext chain and because the spec states
5528 // that the physicalDevice argument must be included in the device group, and we've already checked that it is
5529
5530 pNext = group_info->pNext;
5531 break;
5532 }
5533
5534 // Multiview properties are also allowed, but since VK_KHX_multiview is a device extension, we'll just let the ICD
5535 // handle that error when the user enables the extension here
5536 default: {
5537 const struct VkStructureHeader *header = pNext;
5538 pNext = header->pNext;
5539 break;
5540 }
5541 }
5542 }
5543 }
5544
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005545 res = fpCreateDevice(phys_dev_term->phys_dev, &localCreateInfo, pAllocator, &dev->icd_device);
Jon Ashburn1530c342016-02-26 13:14:27 -07005546 if (res != VK_SUCCESS) {
Mark Young0153e0b2016-11-03 14:27:13 -06005547 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07005548 "terminator_CreateDevice: Failed in ICD %s vkCreateDevice"
5549 "call",
Mark Young0153e0b2016-11-03 14:27:13 -06005550 icd_term->scanned_icd->lib_name);
Mark Young0ad83132016-06-30 13:02:42 -06005551 goto out;
Jon Ashburn1530c342016-02-26 13:14:27 -07005552 }
5553
Mark Young65cb3662016-11-07 13:27:02 -07005554 *pDevice = dev->icd_device;
Mark Young0153e0b2016-11-03 14:27:13 -06005555 loader_add_logical_device(icd_term->this_instance, icd_term, dev);
Jon Ashburn1530c342016-02-26 13:14:27 -07005556
Mark Young0f183a82017-02-28 09:58:04 -07005557 // Init dispatch pointer in new device object
Jon Ashburn1530c342016-02-26 13:14:27 -07005558 loader_init_dispatch(*pDevice, &dev->loader_dispatch);
5559
Mark Young0ad83132016-06-30 13:02:42 -06005560out:
5561 if (NULL != icd_exts.list) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005562 loader_destroy_generic_list(icd_term->this_instance, (struct loader_generic_list *)&icd_exts);
Mark Young0ad83132016-06-30 13:02:42 -06005563 }
5564
Joey Bzdekc2536de2017-10-23 17:13:33 -06005565 // Restore pNext pointer to old VkDeviceGroupDeviceCreateInfoKHX
5566 // in the chain to maintain consistency for the caller.
5567 if (caller_dgci_container != NULL) {
5568 caller_dgci_container->pNext = caller_dgci;
5569 }
5570
Jon Ashburn1530c342016-02-26 13:14:27 -07005571 return res;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06005572}
5573
Mark Young6267ae62017-01-12 12:27:19 -07005574VkResult setupLoaderTrampPhysDevs(VkInstance instance) {
Jon Ashburn24cd4be2015-11-01 14:04:06 -07005575 VkResult res = VK_SUCCESS;
Mark Young6267ae62017-01-12 12:27:19 -07005576 VkPhysicalDevice *local_phys_devs = NULL;
5577 struct loader_instance *inst;
5578 uint32_t total_count = 0;
5579 struct loader_physical_device_tramp **new_phys_devs = NULL;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07005580
Mark Young6267ae62017-01-12 12:27:19 -07005581 inst = loader_get_instance(instance);
5582 if (NULL == inst) {
5583 res = VK_ERROR_INITIALIZATION_FAILED;
5584 goto out;
5585 }
Mark Youngd66edd52017-03-10 17:31:18 -07005586
Mark Youngbb3a29c2017-05-19 12:29:43 -06005587 // Query how many GPUs there
Mark Youngd66edd52017-03-10 17:31:18 -07005588 res = inst->disp->layer_inst_disp.EnumeratePhysicalDevices(instance, &total_count, NULL);
5589 if (res != VK_SUCCESS) {
5590 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5591 "setupLoaderTrampPhysDevs: Failed during dispatch call "
5592 "of \'vkEnumeratePhysicalDevices\' to lower layers or "
5593 "loader to get count.");
5594 goto out;
5595 }
5596
5597 // Really use what the total GPU count is since Optimus and other layers may mess
5598 // the count up.
Mark Young6267ae62017-01-12 12:27:19 -07005599 total_count = inst->total_gpu_count;
5600
5601 // Create an array for the new physical devices, which will be stored
5602 // in the instance for the trampoline code.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005603 new_phys_devs = (struct loader_physical_device_tramp **)loader_instance_heap_alloc(
5604 inst, total_count * sizeof(struct loader_physical_device_tramp *), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young6267ae62017-01-12 12:27:19 -07005605 if (NULL == new_phys_devs) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005606 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5607 "setupLoaderTrampPhysDevs: Failed to allocate new physical device"
5608 " array of size %d",
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005609 total_count);
Mark Youngd8382d72016-12-23 16:59:58 -07005610 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5611 goto out;
5612 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005613 memset(new_phys_devs, 0, total_count * sizeof(struct loader_physical_device_tramp *));
Jon Ashburn014438f2016-03-01 19:51:07 -07005614
Mark Young6267ae62017-01-12 12:27:19 -07005615 // Create a temporary array (on the stack) to keep track of the
5616 // returned VkPhysicalDevice values.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005617 local_phys_devs = loader_stack_alloc(sizeof(VkPhysicalDevice) * total_count);
Mark Young6267ae62017-01-12 12:27:19 -07005618 if (NULL == local_phys_devs) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005619 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5620 "setupLoaderTrampPhysDevs: Failed to allocate local "
5621 "physical device array of size %d",
Mark Young6267ae62017-01-12 12:27:19 -07005622 total_count);
5623 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5624 goto out;
5625 }
5626 memset(local_phys_devs, 0, sizeof(VkPhysicalDevice) * total_count);
5627
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005628 res = inst->disp->layer_inst_disp.EnumeratePhysicalDevices(instance, &total_count, local_phys_devs);
Mark Young6267ae62017-01-12 12:27:19 -07005629 if (VK_SUCCESS != res) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005630 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5631 "setupLoaderTrampPhysDevs: Failed during dispatch call "
5632 "of \'vkEnumeratePhysicalDevices\' to lower layers or "
Mark Youngd66edd52017-03-10 17:31:18 -07005633 "loader to get content.");
Mark Young6267ae62017-01-12 12:27:19 -07005634 goto out;
5635 }
5636
5637 // Copy or create everything to fill the new array of physical devices
5638 for (uint32_t new_idx = 0; new_idx < total_count; new_idx++) {
Mark Young6267ae62017-01-12 12:27:19 -07005639 // Check if this physical device is already in the old buffer
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005640 for (uint32_t old_idx = 0; old_idx < inst->phys_dev_count_tramp; old_idx++) {
5641 if (local_phys_devs[new_idx] == inst->phys_devs_tramp[old_idx]->phys_dev) {
Mark Young6267ae62017-01-12 12:27:19 -07005642 new_phys_devs[new_idx] = inst->phys_devs_tramp[old_idx];
5643 break;
5644 }
Mark Youngd8382d72016-12-23 16:59:58 -07005645 }
5646
Mark Young6267ae62017-01-12 12:27:19 -07005647 // If this physical device isn't in the old buffer, create it
5648 if (NULL == new_phys_devs[new_idx]) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005649 new_phys_devs[new_idx] = (struct loader_physical_device_tramp *)loader_instance_heap_alloc(
5650 inst, sizeof(struct loader_physical_device_tramp), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young6267ae62017-01-12 12:27:19 -07005651 if (NULL == new_phys_devs[new_idx]) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005652 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5653 "setupLoaderTrampPhysDevs: Failed to allocate "
5654 "physical device trampoline object %d",
Mark Young6267ae62017-01-12 12:27:19 -07005655 new_idx);
5656 total_count = new_idx;
Mark Youngd8382d72016-12-23 16:59:58 -07005657 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5658 goto out;
5659 }
5660
Mark Young6267ae62017-01-12 12:27:19 -07005661 // Initialize the new physicalDevice object
5662 loader_set_dispatch((void *)new_phys_devs[new_idx], inst->disp);
5663 new_phys_devs[new_idx]->this_instance = inst;
5664 new_phys_devs[new_idx]->phys_dev = local_phys_devs[new_idx];
Mark Young559d7502016-09-26 11:38:46 -06005665 }
Lenny Komowa5e01122016-12-22 15:29:43 -07005666 }
Mark Young559d7502016-09-26 11:38:46 -06005667
Lenny Komowa5e01122016-12-22 15:29:43 -07005668out:
Mark Youngd8382d72016-12-23 16:59:58 -07005669
Mark Young6267ae62017-01-12 12:27:19 -07005670 if (VK_SUCCESS != res) {
5671 if (NULL != new_phys_devs) {
5672 for (uint32_t i = 0; i < total_count; i++) {
5673 loader_instance_heap_free(inst, new_phys_devs[i]);
Lenny Komowa5e01122016-12-22 15:29:43 -07005674 }
5675 loader_instance_heap_free(inst, new_phys_devs);
Mark Young6267ae62017-01-12 12:27:19 -07005676 }
5677 total_count = 0;
5678 } else {
5679 // Free everything that didn't carry over to the new array of
5680 // physical devices
5681 if (NULL != inst->phys_devs_tramp) {
5682 for (uint32_t i = 0; i < inst->phys_dev_count_tramp; i++) {
5683 bool found = false;
5684 for (uint32_t j = 0; j < total_count; j++) {
5685 if (inst->phys_devs_tramp[i] == new_phys_devs[j]) {
5686 found = true;
5687 break;
5688 }
5689 }
5690 if (!found) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005691 loader_instance_heap_free(inst, inst->phys_devs_tramp[i]);
Mark Young6267ae62017-01-12 12:27:19 -07005692 }
5693 }
5694 loader_instance_heap_free(inst, inst->phys_devs_tramp);
5695 }
Mark Youngd8382d72016-12-23 16:59:58 -07005696
Mark Young6267ae62017-01-12 12:27:19 -07005697 // Swap in the new physical device list
5698 inst->phys_dev_count_tramp = total_count;
5699 inst->phys_devs_tramp = new_phys_devs;
5700 }
5701
5702 return res;
5703}
5704
5705VkResult setupLoaderTermPhysDevs(struct loader_instance *inst) {
5706 VkResult res = VK_SUCCESS;
5707 struct loader_icd_term *icd_term;
5708 struct loader_phys_dev_per_icd *icd_phys_dev_array = NULL;
5709 struct loader_physical_device_term **new_phys_devs = NULL;
Mark Young6267ae62017-01-12 12:27:19 -07005710
5711 inst->total_gpu_count = 0;
5712
5713 // Allocate something to store the physical device characteristics
5714 // that we read from each ICD.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005715 icd_phys_dev_array =
5716 (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 -07005717 if (NULL == icd_phys_dev_array) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005718 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5719 "setupLoaderTermPhysDevs: Failed to allocate temporary "
5720 "ICD Physical device info array of size %d",
Mark Young6267ae62017-01-12 12:27:19 -07005721 inst->total_gpu_count);
5722 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5723 goto out;
5724 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005725 memset(icd_phys_dev_array, 0, sizeof(struct loader_phys_dev_per_icd) * inst->total_icd_count);
Mark Young6267ae62017-01-12 12:27:19 -07005726 icd_term = inst->icd_terms;
5727
5728 // For each ICD, query the number of physical devices, and then get an
5729 // internal value for those physical devices.
Karl Schultz47dd59d2017-01-20 13:19:20 -07005730 for (uint32_t icd_idx = 0; NULL != icd_term; icd_term = icd_term->next, icd_idx++) {
Mark Young0f183a82017-02-28 09:58:04 -07005731 res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &icd_phys_dev_array[icd_idx].count, NULL);
Mark Young6267ae62017-01-12 12:27:19 -07005732 if (VK_SUCCESS != res) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005733 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5734 "setupLoaderTermPhysDevs: Call to "
5735 "ICD %d's \'vkEnumeratePhysicalDevices\' failed with"
5736 " error 0x%08x",
Karl Schultz47dd59d2017-01-20 13:19:20 -07005737 icd_idx, res);
Mark Young6267ae62017-01-12 12:27:19 -07005738 goto out;
5739 }
5740
Karl Schultz47dd59d2017-01-20 13:19:20 -07005741 icd_phys_dev_array[icd_idx].phys_devs =
5742 (VkPhysicalDevice *)loader_stack_alloc(icd_phys_dev_array[icd_idx].count * sizeof(VkPhysicalDevice));
5743 if (NULL == icd_phys_dev_array[icd_idx].phys_devs) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005744 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5745 "setupLoaderTermPhysDevs: Failed to allocate temporary "
5746 "ICD Physical device array for ICD %d of size %d",
Karl Schultz47dd59d2017-01-20 13:19:20 -07005747 icd_idx, inst->total_gpu_count);
Mark Young6267ae62017-01-12 12:27:19 -07005748 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5749 goto out;
5750 }
5751
Mark Young0f183a82017-02-28 09:58:04 -07005752 res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &(icd_phys_dev_array[icd_idx].count),
5753 icd_phys_dev_array[icd_idx].phys_devs);
Mark Young6267ae62017-01-12 12:27:19 -07005754 if (VK_SUCCESS != res) {
5755 goto out;
5756 }
Karl Schultz47dd59d2017-01-20 13:19:20 -07005757 inst->total_gpu_count += icd_phys_dev_array[icd_idx].count;
5758 icd_phys_dev_array[icd_idx].this_icd_term = icd_term;
Mark Young6267ae62017-01-12 12:27:19 -07005759 }
5760
5761 if (0 == inst->total_gpu_count) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005762 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5763 "setupLoaderTermPhysDevs: Failed to detect any valid"
5764 " GPUs in the current config");
Mark Young6267ae62017-01-12 12:27:19 -07005765 res = VK_ERROR_INITIALIZATION_FAILED;
5766 goto out;
5767 }
5768
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005769 new_phys_devs = loader_instance_heap_alloc(inst, sizeof(struct loader_physical_device_term *) * inst->total_gpu_count,
5770 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young6267ae62017-01-12 12:27:19 -07005771 if (NULL == new_phys_devs) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005772 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5773 "setupLoaderTermPhysDevs: Failed to allocate new physical"
5774 " device array of size %d",
Mark Young6267ae62017-01-12 12:27:19 -07005775 inst->total_gpu_count);
5776 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5777 goto out;
5778 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005779 memset(new_phys_devs, 0, sizeof(struct loader_physical_device_term *) * inst->total_gpu_count);
Mark Young6267ae62017-01-12 12:27:19 -07005780
5781 // Copy or create everything to fill the new array of physical devices
5782 uint32_t idx = 0;
5783 for (uint32_t icd_idx = 0; icd_idx < inst->total_icd_count; icd_idx++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005784 for (uint32_t pd_idx = 0; pd_idx < icd_phys_dev_array[icd_idx].count; pd_idx++) {
Mark Young6267ae62017-01-12 12:27:19 -07005785 // Check if this physical device is already in the old buffer
5786 if (NULL != inst->phys_devs_term) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005787 for (uint32_t old_idx = 0; old_idx < inst->phys_dev_count_term; old_idx++) {
5788 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 -07005789 new_phys_devs[idx] = inst->phys_devs_term[old_idx];
5790 break;
5791 }
5792 }
5793 }
5794 // If this physical device isn't in the old buffer, then we
5795 // need to create it.
5796 if (NULL == new_phys_devs[idx]) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005797 new_phys_devs[idx] = loader_instance_heap_alloc(inst, sizeof(struct loader_physical_device_term),
5798 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young6267ae62017-01-12 12:27:19 -07005799 if (NULL == new_phys_devs[idx]) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005800 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5801 "setupLoaderTermPhysDevs: Failed to allocate "
5802 "physical device terminator object %d",
Mark Young6267ae62017-01-12 12:27:19 -07005803 idx);
5804 inst->total_gpu_count = idx;
5805 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5806 goto out;
5807 }
5808
5809 loader_set_dispatch((void *)new_phys_devs[idx], inst->disp);
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005810 new_phys_devs[idx]->this_icd_term = icd_phys_dev_array[icd_idx].this_icd_term;
Mark Young6267ae62017-01-12 12:27:19 -07005811 new_phys_devs[idx]->icd_index = (uint8_t)(icd_idx);
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005812 new_phys_devs[idx]->phys_dev = icd_phys_dev_array[icd_idx].phys_devs[pd_idx];
Mark Young6267ae62017-01-12 12:27:19 -07005813 }
5814 idx++;
5815 }
5816 }
5817
5818out:
5819
5820 if (VK_SUCCESS != res) {
Mark Young156e8552017-02-03 16:27:42 -07005821 if (NULL != new_phys_devs) {
5822 // We've encountered an error, so we should free the new buffers.
Mark Young6267ae62017-01-12 12:27:19 -07005823 for (uint32_t i = 0; i < inst->total_gpu_count; i++) {
5824 loader_instance_heap_free(inst, new_phys_devs[i]);
5825 }
Mark Young156e8552017-02-03 16:27:42 -07005826 loader_instance_heap_free(inst, new_phys_devs);
Mark Young6267ae62017-01-12 12:27:19 -07005827 }
Mark Young156e8552017-02-03 16:27:42 -07005828 inst->total_gpu_count = 0;
Mark Young6267ae62017-01-12 12:27:19 -07005829 } else {
5830 // Free everything that didn't carry over to the new array of
5831 // physical devices. Everything else will have been copied over
5832 // to the new array.
5833 if (NULL != inst->phys_devs_term) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005834 for (uint32_t cur_pd = 0; cur_pd < inst->phys_dev_count_term; cur_pd++) {
Mark Young6267ae62017-01-12 12:27:19 -07005835 bool found = false;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005836 for (uint32_t new_pd_idx = 0; new_pd_idx < inst->total_gpu_count; new_pd_idx++) {
5837 if (inst->phys_devs_term[cur_pd] == new_phys_devs[new_pd_idx]) {
Mark Young6267ae62017-01-12 12:27:19 -07005838 found = true;
5839 break;
5840 }
5841 }
5842 if (!found) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005843 loader_instance_heap_free(inst, inst->phys_devs_term[cur_pd]);
Mark Young6267ae62017-01-12 12:27:19 -07005844 }
5845 }
5846 loader_instance_heap_free(inst, inst->phys_devs_term);
5847 }
5848
5849 // Swap out old and new devices list
5850 inst->phys_dev_count_term = inst->total_gpu_count;
5851 inst->phys_devs_term = new_phys_devs;
5852 }
5853
5854 return res;
5855}
5856
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005857VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount,
5858 VkPhysicalDevice *pPhysicalDevices) {
Mark Young6267ae62017-01-12 12:27:19 -07005859 struct loader_instance *inst = (struct loader_instance *)instance;
5860 VkResult res = VK_SUCCESS;
5861
Mark Youngd66edd52017-03-10 17:31:18 -07005862 // Always call the setup loader terminator physical devices because they may
5863 // have changed at any point.
5864 res = setupLoaderTermPhysDevs(inst);
5865 if (VK_SUCCESS != res) {
5866 goto out;
Mark Young6267ae62017-01-12 12:27:19 -07005867 }
5868
5869 uint32_t copy_count = inst->total_gpu_count;
5870 if (NULL != pPhysicalDevices) {
5871 if (copy_count > *pPhysicalDeviceCount) {
5872 copy_count = *pPhysicalDeviceCount;
5873 res = VK_INCOMPLETE;
5874 }
5875
5876 for (uint32_t i = 0; i < copy_count; i++) {
5877 pPhysicalDevices[i] = (VkPhysicalDevice)inst->phys_devs_term[i];
Jon Ashburn014438f2016-03-01 19:51:07 -07005878 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06005879 }
Mark Young559d7502016-09-26 11:38:46 -06005880
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07005881 *pPhysicalDeviceCount = copy_count;
5882
Mark Young6267ae62017-01-12 12:27:19 -07005883out:
5884
Jon Ashburn24cd4be2015-11-01 14:04:06 -07005885 return res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07005886}
5887
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005888VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
5889 VkPhysicalDeviceProperties *pProperties) {
5890 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Mark Young0153e0b2016-11-03 14:27:13 -06005891 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Young0f183a82017-02-28 09:58:04 -07005892 if (NULL != icd_term->dispatch.GetPhysicalDeviceProperties) {
5893 icd_term->dispatch.GetPhysicalDeviceProperties(phys_dev_term->phys_dev, pProperties);
Mark Youngb6399312017-01-10 14:22:15 -07005894 }
Tony Barbour59a47322015-06-24 16:06:58 -06005895}
5896
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005897VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice,
5898 uint32_t *pQueueFamilyPropertyCount,
5899 VkQueueFamilyProperties *pProperties) {
5900 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Mark Young0153e0b2016-11-03 14:27:13 -06005901 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Young0f183a82017-02-28 09:58:04 -07005902 if (NULL != icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties) {
5903 icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties(phys_dev_term->phys_dev, pQueueFamilyPropertyCount, pProperties);
Mark Youngb6399312017-01-10 14:22:15 -07005904 }
Tony Barbour59a47322015-06-24 16:06:58 -06005905}
5906
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005907VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice,
5908 VkPhysicalDeviceMemoryProperties *pProperties) {
5909 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Mark Young0153e0b2016-11-03 14:27:13 -06005910 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Young0f183a82017-02-28 09:58:04 -07005911 if (NULL != icd_term->dispatch.GetPhysicalDeviceMemoryProperties) {
5912 icd_term->dispatch.GetPhysicalDeviceMemoryProperties(phys_dev_term->phys_dev, pProperties);
Mark Youngb6399312017-01-10 14:22:15 -07005913 }
Jon Ashburn3da71f22015-05-14 12:43:38 -06005914}
5915
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005916VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice,
5917 VkPhysicalDeviceFeatures *pFeatures) {
5918 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Mark Young0153e0b2016-11-03 14:27:13 -06005919 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Young0f183a82017-02-28 09:58:04 -07005920 if (NULL != icd_term->dispatch.GetPhysicalDeviceFeatures) {
5921 icd_term->dispatch.GetPhysicalDeviceFeatures(phys_dev_term->phys_dev, pFeatures);
Mark Youngb6399312017-01-10 14:22:15 -07005922 }
Chris Forbesbc0bb772015-06-21 22:55:02 +12005923}
5924
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005925VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format,
5926 VkFormatProperties *pFormatInfo) {
5927 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Mark Young0153e0b2016-11-03 14:27:13 -06005928 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Young0f183a82017-02-28 09:58:04 -07005929 if (NULL != icd_term->dispatch.GetPhysicalDeviceFormatProperties) {
5930 icd_term->dispatch.GetPhysicalDeviceFormatProperties(phys_dev_term->phys_dev, format, pFormatInfo);
Mark Youngb6399312017-01-10 14:22:15 -07005931 }
Chris Forbesbc0bb772015-06-21 22:55:02 +12005932}
5933
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005934VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format,
5935 VkImageType type, VkImageTiling tiling,
5936 VkImageUsageFlags usage, VkImageCreateFlags flags,
5937 VkImageFormatProperties *pImageFormatProperties) {
5938 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Mark Young0153e0b2016-11-03 14:27:13 -06005939 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Young0f183a82017-02-28 09:58:04 -07005940 if (NULL == icd_term->dispatch.GetPhysicalDeviceImageFormatProperties) {
Mark Youngb6399312017-01-10 14:22:15 -07005941 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5942 "Encountered the vkEnumerateDeviceLayerProperties "
5943 "terminator. This means a layer improperly continued.");
Chia-I Wu17241042015-10-31 00:31:16 +08005944 return VK_ERROR_INITIALIZATION_FAILED;
Mark Youngb6399312017-01-10 14:22:15 -07005945 }
Mark Young0f183a82017-02-28 09:58:04 -07005946 return icd_term->dispatch.GetPhysicalDeviceImageFormatProperties(phys_dev_term->phys_dev, format, type, tiling, usage, flags,
5947 pImageFormatProperties);
Jon Ashburn754864f2015-07-23 18:49:07 -06005948}
5949
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005950VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format,
5951 VkImageType type, VkSampleCountFlagBits samples,
5952 VkImageUsageFlags usage, VkImageTiling tiling,
5953 uint32_t *pNumProperties,
5954 VkSparseImageFormatProperties *pProperties) {
5955 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Mark Young0153e0b2016-11-03 14:27:13 -06005956 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Young0f183a82017-02-28 09:58:04 -07005957 if (NULL != icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties) {
5958 icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties(phys_dev_term->phys_dev, format, type, samples, usage,
5959 tiling, pNumProperties, pProperties);
Mark Youngb6399312017-01-10 14:22:15 -07005960 }
Mark Lobodzinski16e8bef2015-07-03 15:58:09 -06005961}
5962
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005963VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
5964 const char *pLayerName, uint32_t *pPropertyCount,
5965 VkExtensionProperties *pProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06005966 struct loader_physical_device_term *phys_dev_term;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07005967
Mark Young3a587792016-08-19 15:25:08 -06005968 struct loader_layer_list implicit_layer_list = {0};
5969 struct loader_extension_list all_exts = {0};
5970 struct loader_extension_list icd_exts = {0};
Jon Ashburn471f44c2016-01-13 12:51:43 -07005971
Jon Ashburndc5d9202016-02-29 13:00:51 -07005972 assert(pLayerName == NULL || strlen(pLayerName) == 0);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06005973
Mark Young0f183a82017-02-28 09:58:04 -07005974 // Any layer or trampoline wrapping should be removed at this point in time can just cast to the expected
5975 // type for VkPhysicalDevice.
Mark Young0153e0b2016-11-03 14:27:13 -06005976 phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Jon Ashburn471f44c2016-01-13 12:51:43 -07005977
Mark Young0f183a82017-02-28 09:58:04 -07005978 // This case is during the call down the instance chain with pLayerName == NULL
Mark Young0153e0b2016-11-03 14:27:13 -06005979 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Jon Ashburndc5d9202016-02-29 13:00:51 -07005980 uint32_t icd_ext_count = *pPropertyCount;
5981 VkResult res;
Jon Ashburn471f44c2016-01-13 12:51:43 -07005982
Mark Young0f183a82017-02-28 09:58:04 -07005983 // Get the available device extensions
5984 res = icd_term->dispatch.EnumerateDeviceExtensionProperties(phys_dev_term->phys_dev, NULL, &icd_ext_count, pProperties);
Mark Young3a587792016-08-19 15:25:08 -06005985 if (res != VK_SUCCESS) {
5986 goto out;
5987 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07005988
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005989 if (!loader_init_layer_list(icd_term->this_instance, &implicit_layer_list)) {
Mark Young3a587792016-08-19 15:25:08 -06005990 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5991 goto out;
5992 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07005993
Mark Young283fe1c2017-05-04 12:16:35 -06005994 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 -07005995 // We need to determine which implicit layers are active, and then add their extensions. This can't be cached as
5996 // it depends on results of environment variables (which can change).
Jon Ashburndc5d9202016-02-29 13:00:51 -07005997 if (pProperties != NULL) {
Mark Young0f183a82017-02-28 09:58:04 -07005998 // Initialize dev_extension list within the physicalDevice object
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005999 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 -06006000 if (res != VK_SUCCESS) {
6001 goto out;
6002 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07006003
Mark Young0f183a82017-02-28 09:58:04 -07006004 // We need to determine which implicit layers are active, and then add their extensions. This can't be cached as
6005 // it depends on results of environment variables (which can change).
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07006006 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 -06006007 if (res != VK_SUCCESS) {
6008 goto out;
6009 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07006010
Mark Young283fe1c2017-05-04 12:16:35 -06006011 loader_add_implicit_layers(icd_term->this_instance, &implicit_layer_list, NULL,
6012 &icd_term->this_instance->instance_layer_list);
Jon Ashburn471f44c2016-01-13 12:51:43 -07006013
Jon Ashburndc5d9202016-02-29 13:00:51 -07006014 for (uint32_t i = 0; i < implicit_layer_list.count; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07006015 for (uint32_t j = 0; j < implicit_layer_list.list[i].device_extension_list.count; j++) {
6016 res = loader_add_to_ext_list(icd_term->this_instance, &all_exts, 1,
6017 &implicit_layer_list.list[i].device_extension_list.list[j].props);
Mark Young3a587792016-08-19 15:25:08 -06006018 if (res != VK_SUCCESS) {
6019 goto out;
6020 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07006021 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07006022 }
Jon Ashburndc5d9202016-02-29 13:00:51 -07006023 uint32_t capacity = *pPropertyCount;
6024 VkExtensionProperties *props = pProperties;
Jon Ashburn471f44c2016-01-13 12:51:43 -07006025
Jon Ashburndc5d9202016-02-29 13:00:51 -07006026 for (uint32_t i = 0; i < all_exts.count && i < capacity; i++) {
6027 props[i] = all_exts.list[i];
6028 }
Mark Young0f183a82017-02-28 09:58:04 -07006029
6030 // Wasn't enough space for the extensions, we did partial copy now return VK_INCOMPLETE
Jon Ashburndc5d9202016-02-29 13:00:51 -07006031 if (capacity < all_exts.count) {
6032 res = VK_INCOMPLETE;
6033 } else {
6034 *pPropertyCount = all_exts.count;
6035 }
Jon Ashburndc5d9202016-02-29 13:00:51 -07006036 } else {
Mark Young0f183a82017-02-28 09:58:04 -07006037 // Just return the count; need to add in the count of implicit layer extensions
6038 // don't worry about duplicates being added in the count
Jon Ashburndc5d9202016-02-29 13:00:51 -07006039 *pPropertyCount = icd_ext_count;
6040
6041 for (uint32_t i = 0; i < implicit_layer_list.count; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07006042 *pPropertyCount += implicit_layer_list.list[i].device_extension_list.count;
Jon Ashburndc5d9202016-02-29 13:00:51 -07006043 }
6044 res = VK_SUCCESS;
Jon Ashburnb82c1852015-08-11 14:49:54 -06006045 }
Jon Ashburndc5d9202016-02-29 13:00:51 -07006046
Mark Young3a587792016-08-19 15:25:08 -06006047out:
6048
6049 if (NULL != implicit_layer_list.list) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07006050 loader_destroy_generic_list(icd_term->this_instance, (struct loader_generic_list *)&implicit_layer_list);
Mark Young3a587792016-08-19 15:25:08 -06006051 }
6052 if (NULL != all_exts.list) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07006053 loader_destroy_generic_list(icd_term->this_instance, (struct loader_generic_list *)&all_exts);
Mark Young3a587792016-08-19 15:25:08 -06006054 }
6055 if (NULL != icd_exts.list) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07006056 loader_destroy_generic_list(icd_term->this_instance, (struct loader_generic_list *)&icd_exts);
Mark Young3a587792016-08-19 15:25:08 -06006057 }
6058
Jon Ashburndc5d9202016-02-29 13:00:51 -07006059 return res;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06006060}
6061
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07006062VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
6063 VkLayerProperties *pProperties) {
6064 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Mark Youngb6399312017-01-10 14:22:15 -07006065 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07006066 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
6067 "Encountered the vkEnumerateDeviceLayerProperties "
6068 "terminator. This means a layer improperly continued.");
Mark Youngb6399312017-01-10 14:22:15 -07006069 // Should never get here this call isn't dispatched down the chain
Jon Ashburndc5d9202016-02-29 13:00:51 -07006070 return VK_ERROR_INITIALIZATION_FAILED;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06006071}
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07006072
Jon Ashburnf2b4e382016-02-10 20:50:19 -07006073VkStringErrorFlags vk_string_validate(const int max_length, const char *utf8) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07006074 VkStringErrorFlags result = VK_STRING_ERROR_NONE;
Karl Schultz2558bd32016-02-24 14:39:39 -07006075 int num_char_bytes = 0;
Jon Ashburnf2b4e382016-02-10 20:50:19 -07006076 int i, j;
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07006077
Courtney Goeltzenleuchter7a3486d2016-12-21 16:24:34 -07006078 for (i = 0; i <= max_length; i++) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07006079 if (utf8[i] == 0) {
6080 break;
Courtney Goeltzenleuchter7a3486d2016-12-21 16:24:34 -07006081 } else if (i == max_length) {
6082 result |= VK_STRING_ERROR_LENGTH;
6083 break;
Mark Lobodzinski36b4de22016-02-12 11:30:14 -07006084 } else if ((utf8[i] >= 0x20) && (utf8[i] < 0x7f)) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07006085 num_char_bytes = 0;
Jon Ashburnf2b4e382016-02-10 20:50:19 -07006086 } else if ((utf8[i] & UTF8_ONE_BYTE_MASK) == UTF8_ONE_BYTE_CODE) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07006087 num_char_bytes = 1;
Jon Ashburnf2b4e382016-02-10 20:50:19 -07006088 } else if ((utf8[i] & UTF8_TWO_BYTE_MASK) == UTF8_TWO_BYTE_CODE) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07006089 num_char_bytes = 2;
6090 } else if ((utf8[i] & UTF8_THREE_BYTE_MASK) == UTF8_THREE_BYTE_CODE) {
6091 num_char_bytes = 3;
6092 } else {
6093 result = VK_STRING_ERROR_BAD_DATA;
6094 }
6095
6096 // Validate the following num_char_bytes of data
6097 for (j = 0; (j < num_char_bytes) && (i < max_length); j++) {
6098 if (++i == max_length) {
6099 result |= VK_STRING_ERROR_LENGTH;
6100 break;
6101 }
6102 if ((utf8[i] & UTF8_DATA_BYTE_MASK) != UTF8_DATA_BYTE_CODE) {
6103 result |= VK_STRING_ERROR_BAD_DATA;
6104 }
6105 }
6106 }
6107 return result;
6108}
Lenny Komow3cf3ac72017-12-19 16:38:37 -07006109
6110VKAPI_ATTR VkResult VKAPI_CALL
Lenny Komow16586112018-02-13 15:58:47 -07006111terminator_EnumerateInstanceVersion(const VkEnumerateInstanceVersionChain *chain, uint32_t* pApiVersion) {
6112 // NOTE: The Vulkan WG doesn't want us checking pApiVersion for NULL, but instead
6113 // prefers us crashing.
6114 *pApiVersion = VK_MAKE_VERSION(loader_major_version, loader_minor_version, 0);
6115 return VK_SUCCESS;
6116}
6117
6118VKAPI_ATTR VkResult VKAPI_CALL
Lenny Komow3cf3ac72017-12-19 16:38:37 -07006119terminator_EnumerateInstanceExtensionProperties(const VkEnumerateInstanceExtensionPropertiesChain *chain, const char *pLayerName,
6120 uint32_t *pPropertyCount, VkExtensionProperties *pProperties) {
6121 struct loader_extension_list *global_ext_list = NULL;
6122 struct loader_layer_list instance_layers;
6123 struct loader_extension_list local_ext_list;
6124 struct loader_icd_tramp_list icd_tramp_list;
6125 uint32_t copy_size;
6126 VkResult res = VK_SUCCESS;
6127
6128 // tls_instance = NULL;
6129 memset(&local_ext_list, 0, sizeof(local_ext_list));
6130 memset(&instance_layers, 0, sizeof(instance_layers));
Lenny Komow3cf3ac72017-12-19 16:38:37 -07006131
6132 // Get layer libraries if needed
6133 if (pLayerName && strlen(pLayerName) != 0) {
6134 if (vk_string_validate(MaxLoaderStringLength, pLayerName) != VK_STRING_ERROR_NONE) {
6135 assert(VK_FALSE &&
6136 "vkEnumerateInstanceExtensionProperties: "
6137 "pLayerName is too long or is badly formed");
6138 res = VK_ERROR_EXTENSION_NOT_PRESENT;
6139 goto out;
6140 }
6141
6142 loader_layer_scan(NULL, &instance_layers);
6143 for (uint32_t i = 0; i < instance_layers.count; i++) {
6144 struct loader_layer_properties *props = &instance_layers.list[i];
6145 if (strcmp(props->info.layerName, pLayerName) == 0) {
6146 global_ext_list = &props->instance_extension_list;
6147 break;
6148 }
6149 }
6150 } else {
6151 // Scan/discover all ICD libraries
6152 memset(&icd_tramp_list, 0, sizeof(icd_tramp_list));
6153 res = loader_icd_scan(NULL, &icd_tramp_list);
6154 if (VK_SUCCESS != res) {
6155 goto out;
6156 }
6157 // Get extensions from all ICD's, merge so no duplicates
6158 res = loader_get_icd_loader_instance_extensions(NULL, &icd_tramp_list, &local_ext_list);
6159 if (VK_SUCCESS != res) {
6160 goto out;
6161 }
6162 loader_scanned_icd_clear(NULL, &icd_tramp_list);
6163
6164 // Append enabled implicit layers.
6165 loader_implicit_layer_scan(NULL, &instance_layers);
6166 for (uint32_t i = 0; i < instance_layers.count; i++) {
6167 if (!loader_is_implicit_layer_enabled(NULL, &instance_layers.list[i])) {
6168 continue;
6169 }
6170 struct loader_extension_list *ext_list = &instance_layers.list[i].instance_extension_list;
6171 loader_add_to_ext_list(NULL, &local_ext_list, ext_list->count, ext_list->list);
6172 }
6173
6174 global_ext_list = &local_ext_list;
6175 }
6176
6177 if (global_ext_list == NULL) {
6178 res = VK_ERROR_LAYER_NOT_PRESENT;
6179 goto out;
6180 }
6181
6182 if (pProperties == NULL) {
6183 *pPropertyCount = global_ext_list->count;
6184 goto out;
6185 }
6186
6187 copy_size = *pPropertyCount < global_ext_list->count ? *pPropertyCount : global_ext_list->count;
6188 for (uint32_t i = 0; i < copy_size; i++) {
6189 memcpy(&pProperties[i], &global_ext_list->list[i], sizeof(VkExtensionProperties));
6190 }
6191 *pPropertyCount = copy_size;
6192
6193 if (copy_size < global_ext_list->count) {
6194 res = VK_INCOMPLETE;
6195 goto out;
6196 }
6197
6198out:
6199
6200 loader_destroy_generic_list(NULL, (struct loader_generic_list *)&local_ext_list);
6201 loader_delete_layer_properties(NULL, &instance_layers);
6202 return res;
6203}
6204
6205VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateInstanceLayerProperties(const VkEnumerateInstanceLayerPropertiesChain *chain,
6206 uint32_t *pPropertyCount,
6207 VkLayerProperties *pProperties) {
6208 VkResult result = VK_SUCCESS;
6209 struct loader_layer_list instance_layer_list;
6210 tls_instance = NULL;
6211
Lenny Komow23342982018-01-19 11:22:28 -07006212 LOADER_PLATFORM_THREAD_ONCE(&once_init, loader_initialize);
6213
Lenny Komow3cf3ac72017-12-19 16:38:37 -07006214 uint32_t copy_size;
6215
6216 // Get layer libraries
6217 memset(&instance_layer_list, 0, sizeof(instance_layer_list));
6218 loader_layer_scan(NULL, &instance_layer_list);
6219
6220 if (pProperties == NULL) {
6221 *pPropertyCount = instance_layer_list.count;
6222 goto out;
6223 }
6224
6225 copy_size = (*pPropertyCount < instance_layer_list.count) ? *pPropertyCount : instance_layer_list.count;
6226 for (uint32_t i = 0; i < copy_size; i++) {
6227 memcpy(&pProperties[i], &instance_layer_list.list[i].info, sizeof(VkLayerProperties));
6228 }
6229
6230 *pPropertyCount = copy_size;
6231
6232 if (copy_size < instance_layer_list.count) {
6233 result = VK_INCOMPLETE;
6234 goto out;
6235 }
6236
6237out:
6238
6239 loader_delete_layer_properties(NULL, &instance_layer_list);
6240 return result;
6241}
Lenny Komow158e9d92018-01-15 15:43:36 -07006242
Lenny Komow23342982018-01-19 11:22:28 -07006243#if defined(_WIN32) && defined(LOADER_DYNAMIC_LIB)
Lenny Komow158e9d92018-01-15 15:43:36 -07006244BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved) {
6245 switch (reason) {
6246 case DLL_PROCESS_ATTACH:
6247 loader_initialize();
6248 break;
6249 case DLL_PROCESS_DETACH:
6250 if (NULL == reserved) {
6251 loader_release();
6252 }
6253 break;
6254 default:
6255 // Do nothing
6256 break;
6257 }
6258 return TRUE;
6259}
Lenny Komow23342982018-01-19 11:22:28 -07006260#elif !defined(_WIN32)
Lenny Komow158e9d92018-01-15 15:43:36 -07006261__attribute__((constructor)) void loader_init_library() { loader_initialize(); }
6262
6263__attribute__((destructor)) void loader_free_library() { loader_release(); }
6264#endif
Lenny Komow82e15e02017-10-02 15:08:53 -06006265
6266// ---- Vulkan Core 1.1 terminators
6267
Lenny Komow76f0f732017-10-02 15:58:17 -06006268VkResult setupLoaderTermPhysDevGroups(struct loader_instance *inst) {
6269 VkResult res = VK_SUCCESS;
6270 struct loader_icd_term *icd_term;
6271 uint32_t total_count = 0;
6272 uint32_t cur_icd_group_count = 0;
6273 VkPhysicalDeviceGroupPropertiesKHR **new_phys_dev_groups = NULL;
6274 VkPhysicalDeviceGroupPropertiesKHR *local_phys_dev_groups = NULL;
Lenny Komowa1524852017-10-02 15:08:53 -06006275 PFN_vkEnumeratePhysicalDeviceGroups fpEnumeratePhysicalDeviceGroups = NULL;
Lenny Komow76f0f732017-10-02 15:58:17 -06006276
6277 if (0 == inst->phys_dev_count_term) {
6278 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
6279 "setupLoaderTermPhysDevGroups: Loader failed to setup physical "
Lenny Komowa1524852017-10-02 15:08:53 -06006280 "device terminator info before calling \'EnumeratePhysicalDeviceGroups\'.");
Lenny Komow76f0f732017-10-02 15:58:17 -06006281 assert(false);
6282 res = VK_ERROR_INITIALIZATION_FAILED;
6283 goto out;
6284 }
6285
6286 // For each ICD, query the number of physical device groups, and then get an
6287 // internal value for those physical devices.
6288 icd_term = inst->icd_terms;
6289 for (uint32_t icd_idx = 0; NULL != icd_term; icd_term = icd_term->next, icd_idx++) {
Lenny Komowa1524852017-10-02 15:08:53 -06006290 // Get the function pointer to use to call into the ICD. This could be the core or KHR version
6291 if (inst->enabled_known_extensions.khr_device_group_creation) {
6292 fpEnumeratePhysicalDeviceGroups = icd_term->dispatch.EnumeratePhysicalDeviceGroupsKHR;
6293 } else {
6294 fpEnumeratePhysicalDeviceGroups = icd_term->dispatch.EnumeratePhysicalDeviceGroups;
6295 }
6296
Lenny Komow76f0f732017-10-02 15:58:17 -06006297 cur_icd_group_count = 0;
Lenny Komowa1524852017-10-02 15:08:53 -06006298 if (NULL == fpEnumeratePhysicalDeviceGroups) {
Lenny Komow76f0f732017-10-02 15:58:17 -06006299 // Treat each ICD's GPU as it's own group if the extension isn't supported
6300 res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &cur_icd_group_count, NULL);
6301 if (res != VK_SUCCESS) {
6302 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
6303 "setupLoaderTermPhysDevGroups: Failed during dispatch call of "
6304 "\'EnumeratePhysicalDevices\' to ICD %d to get plain phys dev count.",
6305 icd_idx);
6306 goto out;
6307 }
6308 } else {
6309 // Query the actual group info
Lenny Komowa1524852017-10-02 15:08:53 -06006310 res = fpEnumeratePhysicalDeviceGroups(icd_term->instance, &cur_icd_group_count, NULL);
Lenny Komow76f0f732017-10-02 15:58:17 -06006311 if (res != VK_SUCCESS) {
6312 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
6313 "setupLoaderTermPhysDevGroups: Failed during dispatch call of "
Lenny Komowa1524852017-10-02 15:08:53 -06006314 "\'EnumeratePhysicalDeviceGroups\' to ICD %d to get count.",
Lenny Komow76f0f732017-10-02 15:58:17 -06006315 icd_idx);
6316 goto out;
6317 }
6318 }
6319 total_count += cur_icd_group_count;
6320 }
6321
6322 // Create an array for the new physical device groups, which will be stored
6323 // in the instance for the Terminator code.
Lenny Komowa1524852017-10-02 15:08:53 -06006324 new_phys_dev_groups = (VkPhysicalDeviceGroupProperties **)loader_instance_heap_alloc(
6325 inst, total_count * sizeof(VkPhysicalDeviceGroupProperties *), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Lenny Komow76f0f732017-10-02 15:58:17 -06006326 if (NULL == new_phys_dev_groups) {
6327 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
6328 "setupLoaderTermPhysDevGroups: Failed to allocate new physical device"
6329 " group array of size %d",
6330 total_count);
6331 res = VK_ERROR_OUT_OF_HOST_MEMORY;
6332 goto out;
6333 }
Lenny Komowa1524852017-10-02 15:08:53 -06006334 memset(new_phys_dev_groups, 0, total_count * sizeof(VkPhysicalDeviceGroupProperties *));
Lenny Komow76f0f732017-10-02 15:58:17 -06006335
6336 // Create a temporary array (on the stack) to keep track of the
6337 // returned VkPhysicalDevice values.
Lenny Komowa1524852017-10-02 15:08:53 -06006338 local_phys_dev_groups = loader_stack_alloc(sizeof(VkPhysicalDeviceGroupProperties) * total_count);
Lenny Komow76f0f732017-10-02 15:58:17 -06006339 if (NULL == local_phys_dev_groups) {
6340 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
6341 "setupLoaderTermPhysDevGroups: Failed to allocate local "
6342 "physical device group array of size %d",
6343 total_count);
6344 res = VK_ERROR_OUT_OF_HOST_MEMORY;
6345 goto out;
6346 }
6347 // Initialize the memory to something valid
Lenny Komowa1524852017-10-02 15:08:53 -06006348 memset(local_phys_dev_groups, 0, sizeof(VkPhysicalDeviceGroupProperties) * total_count);
Lenny Komow76f0f732017-10-02 15:58:17 -06006349 for (uint32_t group = 0; group < total_count; group++) {
6350 local_phys_dev_groups[group].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHR;
6351 local_phys_dev_groups[group].pNext = NULL;
6352 local_phys_dev_groups[group].subsetAllocation = false;
6353 }
6354
6355 cur_icd_group_count = 0;
6356 icd_term = inst->icd_terms;
6357 for (uint32_t icd_idx = 0; NULL != icd_term; icd_term = icd_term->next, icd_idx++) {
6358 uint32_t count_this_time = total_count - cur_icd_group_count;
6359
Lenny Komowa1524852017-10-02 15:08:53 -06006360 // Get the function pointer to use to call into the ICD. This could be the core or KHR version
6361 if (inst->enabled_known_extensions.khr_device_group_creation) {
6362 fpEnumeratePhysicalDeviceGroups = icd_term->dispatch.EnumeratePhysicalDeviceGroupsKHR;
6363 } else {
6364 fpEnumeratePhysicalDeviceGroups = icd_term->dispatch.EnumeratePhysicalDeviceGroups;
6365 }
6366
6367 if (NULL == fpEnumeratePhysicalDeviceGroups) {
Lenny Komow76f0f732017-10-02 15:58:17 -06006368 VkPhysicalDevice* phys_dev_array = loader_stack_alloc(sizeof(VkPhysicalDevice) * count_this_time);
6369 if (NULL == phys_dev_array) {
6370 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
6371 "setupLoaderTermPhysDevGroups: Failed to allocate local "
6372 "physical device array of size %d",
6373 count_this_time);
6374 res = VK_ERROR_OUT_OF_HOST_MEMORY;
6375 goto out;
6376 }
6377
6378 res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &count_this_time, phys_dev_array);
6379 if (res != VK_SUCCESS) {
6380 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
6381 "setupLoaderTermPhysDevGroups: Failed during dispatch call of "
6382 "\'EnumeratePhysicalDevices\' to ICD %d to get plain phys dev count.",
6383 icd_idx);
6384 goto out;
6385 }
6386
6387 // Add each GPU as it's own group
6388 for (uint32_t indiv_gpu = 0; indiv_gpu < count_this_time; indiv_gpu++) {
6389 local_phys_dev_groups[indiv_gpu + cur_icd_group_count].physicalDeviceCount = 1;
6390 local_phys_dev_groups[indiv_gpu + cur_icd_group_count].physicalDevices[0] = phys_dev_array[indiv_gpu];
6391 }
6392
6393 } else {
Lenny Komowa1524852017-10-02 15:08:53 -06006394 res = fpEnumeratePhysicalDeviceGroups(icd_term->instance, &count_this_time, &local_phys_dev_groups[cur_icd_group_count]);
Lenny Komow76f0f732017-10-02 15:58:17 -06006395 if (VK_SUCCESS != res) {
6396 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
6397 "setupLoaderTermPhysDevGroups: Failed during dispatch call of "
Lenny Komowa1524852017-10-02 15:08:53 -06006398 "\'EnumeratePhysicalDeviceGroups\' to ICD %d to get content.",
Lenny Komow76f0f732017-10-02 15:58:17 -06006399 icd_idx);
6400 goto out;
6401 }
6402 }
6403
6404 cur_icd_group_count += count_this_time;
6405 }
6406
6407 // Replace all the physical device IDs with the proper loader values
6408 for (uint32_t group = 0; group < total_count; group++) {
6409 for (uint32_t group_gpu = 0; group_gpu < local_phys_dev_groups[group].physicalDeviceCount; group_gpu++) {
6410 bool found = false;
6411 for (uint32_t term_gpu = 0; term_gpu < inst->phys_dev_count_term; term_gpu++) {
6412 if (local_phys_dev_groups[group].physicalDevices[group_gpu] == inst->phys_devs_term[term_gpu]->phys_dev) {
6413 local_phys_dev_groups[group].physicalDevices[group_gpu] = (VkPhysicalDevice)inst->phys_devs_term[term_gpu];
6414 found = true;
6415 break;
6416 }
6417 }
6418 if (!found) {
6419 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
6420 "setupLoaderTermPhysDevGroups: Failed to find GPU %d in group %d"
Lenny Komowa1524852017-10-02 15:08:53 -06006421 " returned by \'EnumeratePhysicalDeviceGroups\' in list returned"
Lenny Komow76f0f732017-10-02 15:58:17 -06006422 " by \'EnumeratePhysicalDevices\'", group_gpu, group);
6423 res = VK_ERROR_INITIALIZATION_FAILED;
6424 goto out;
6425 }
6426 }
6427 }
6428
6429 // Copy or create everything to fill the new array of physical device groups
6430 for (uint32_t new_idx = 0; new_idx < total_count; new_idx++) {
6431 // Check if this physical device group with the same contents is already in the old buffer
6432 for (uint32_t old_idx = 0; old_idx < inst->phys_dev_group_count_term; old_idx++) {
6433 if (local_phys_dev_groups[new_idx].physicalDeviceCount == inst->phys_dev_groups_term[old_idx]->physicalDeviceCount) {
6434 bool found_all_gpus = true;
6435 for (uint32_t old_gpu = 0; old_gpu < inst->phys_dev_groups_term[old_idx]->physicalDeviceCount; old_gpu++) {
6436 bool found_gpu = false;
6437 for (uint32_t new_gpu = 0; new_gpu < local_phys_dev_groups[new_idx].physicalDeviceCount; new_gpu++) {
6438 if (local_phys_dev_groups[new_idx].physicalDevices[new_gpu] == inst->phys_dev_groups_term[old_idx]->physicalDevices[old_gpu]) {
6439 found_gpu = true;
6440 break;
6441 }
6442 }
6443
6444 if (!found_gpu) {
6445 found_all_gpus = false;
6446 break;
6447 }
6448 }
6449 if (!found_all_gpus) {
6450 continue;
6451 } else {
6452 new_phys_dev_groups[new_idx] = inst->phys_dev_groups_term[old_idx];
6453 break;
6454 }
6455 }
6456 }
6457
6458 // If this physical device group isn't in the old buffer, create it
6459 if (NULL == new_phys_dev_groups[new_idx]) {
6460 new_phys_dev_groups[new_idx] = (VkPhysicalDeviceGroupPropertiesKHR *)loader_instance_heap_alloc(
6461 inst, sizeof(VkPhysicalDeviceGroupPropertiesKHR), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
6462 if (NULL == new_phys_dev_groups[new_idx]) {
6463 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
6464 "setupLoaderTermPhysDevGroups: Failed to allocate "
6465 "physical device group Terminator object %d",
6466 new_idx);
6467 total_count = new_idx;
6468 res = VK_ERROR_OUT_OF_HOST_MEMORY;
6469 goto out;
6470 }
6471 memcpy(new_phys_dev_groups[new_idx], &local_phys_dev_groups[new_idx],
6472 sizeof(VkPhysicalDeviceGroupPropertiesKHR));
6473 }
6474 }
6475
6476out:
6477
6478 if (VK_SUCCESS != res) {
6479 if (NULL != new_phys_dev_groups) {
6480 for (uint32_t i = 0; i < total_count; i++) {
6481 loader_instance_heap_free(inst, new_phys_dev_groups[i]);
6482 }
6483 loader_instance_heap_free(inst, new_phys_dev_groups);
6484 }
6485 total_count = 0;
6486 } else {
6487 // Free everything that didn't carry over to the new array of
6488 // physical device groups
6489 if (NULL != inst->phys_dev_groups_term) {
6490 for (uint32_t i = 0; i < inst->phys_dev_group_count_term; i++) {
6491 bool found = false;
6492 for (uint32_t j = 0; j < total_count; j++) {
6493 if (inst->phys_dev_groups_term[i] == new_phys_dev_groups[j]) {
6494 found = true;
6495 break;
6496 }
6497 }
6498 if (!found) {
6499 loader_instance_heap_free(inst, inst->phys_dev_groups_term[i]);
6500 }
6501 }
6502 loader_instance_heap_free(inst, inst->phys_dev_groups_term);
6503 }
6504
6505 // Swap in the new physical device group list
6506 inst->phys_dev_group_count_term = total_count;
6507 inst->phys_dev_groups_term = new_phys_dev_groups;
6508 }
6509
6510 return res;
6511}
6512
Lenny Komow82e15e02017-10-02 15:08:53 -06006513VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDeviceGroups(
6514 VkInstance instance, uint32_t *pPhysicalDeviceGroupCount,
6515 VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties) {
6516 struct loader_instance *inst = (struct loader_instance *)instance;
6517 VkResult res = VK_SUCCESS;
6518
6519 // Always call the setup loader terminator physical device groups because they may
6520 // have changed at any point.
6521 res = setupLoaderTermPhysDevGroups(inst);
6522 if (VK_SUCCESS != res) {
6523 goto out;
6524 }
6525
6526 uint32_t copy_count = inst->phys_dev_group_count_term;
6527 if (NULL != pPhysicalDeviceGroupProperties) {
6528 if (copy_count > *pPhysicalDeviceGroupCount) {
6529 copy_count = *pPhysicalDeviceGroupCount;
6530 res = VK_INCOMPLETE;
6531 }
6532
6533 for (uint32_t i = 0; i < copy_count; i++) {
6534 memcpy(&pPhysicalDeviceGroupProperties[i], inst->phys_dev_groups_term[i],
6535 sizeof(VkPhysicalDeviceGroupPropertiesKHR));
6536 }
6537 }
6538
6539 *pPhysicalDeviceGroupCount = copy_count;
6540
6541out:
6542
6543 return res;
6544}
6545
6546VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice,
6547 VkPhysicalDeviceFeatures2 *pFeatures) {
6548 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
6549 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Lenny Komowa1524852017-10-02 15:08:53 -06006550 const struct loader_instance *inst = icd_term->this_instance;
Lenny Komow82e15e02017-10-02 15:08:53 -06006551
Lenny Komowa1524852017-10-02 15:08:53 -06006552 // Get the function pointer to use to call into the ICD. This could be the core or KHR version
6553 PFN_vkGetPhysicalDeviceFeatures2 fpGetPhysicalDeviceFeatures2 = NULL;
6554 if (inst != NULL && inst->enabled_known_extensions.khr_get_physical_device_properties2) {
6555 fpGetPhysicalDeviceFeatures2 = icd_term->dispatch.GetPhysicalDeviceFeatures2KHR;
6556 } else {
6557 fpGetPhysicalDeviceFeatures2 = icd_term->dispatch.GetPhysicalDeviceFeatures2;
6558 }
6559
Lenny Komow88dc89b2017-11-03 14:37:11 -06006560 if (fpGetPhysicalDeviceFeatures2 != NULL || !inst->enabled_known_extensions.khr_get_physical_device_properties2) {
Lenny Komow82e15e02017-10-02 15:08:53 -06006561 // Pass the call to the driver
Lenny Komowa1524852017-10-02 15:08:53 -06006562 fpGetPhysicalDeviceFeatures2(phys_dev_term->phys_dev, pFeatures);
Lenny Komow82e15e02017-10-02 15:08:53 -06006563 } else {
6564 // Emulate the call
6565 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006566 "vkGetPhysicalDeviceFeatures2: Emulating call in ICD \"%s\" using vkGetPhysicalDeviceFeatures",
Lenny Komow82e15e02017-10-02 15:08:53 -06006567 icd_term->scanned_icd->lib_name);
6568
Lenny Komow802a9652017-10-03 13:59:21 -06006569 // Write to the VkPhysicalDeviceFeatures2 struct
Lenny Komow82e15e02017-10-02 15:08:53 -06006570 icd_term->dispatch.GetPhysicalDeviceFeatures(phys_dev_term->phys_dev, &pFeatures->features);
6571
6572 void *pNext = pFeatures->pNext;
6573 while (pNext != NULL) {
6574 switch (*(VkStructureType *)pNext) {
Lenny Komow802a9652017-10-03 13:59:21 -06006575 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES: {
Lenny Komow82e15e02017-10-02 15:08:53 -06006576 // Skip the check if VK_KHR_multiview is enabled because it's a device extension
6577 // Write to the VkPhysicalDeviceMultiviewFeaturesKHR struct
6578 VkPhysicalDeviceMultiviewFeaturesKHR *multiview_features = pNext;
6579 multiview_features->multiview = VK_FALSE;
6580 multiview_features->multiviewGeometryShader = VK_FALSE;
6581 multiview_features->multiviewTessellationShader = VK_FALSE;
6582
6583 pNext = multiview_features->pNext;
6584 break;
6585 }
6586 default: {
6587 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006588 "vkGetPhysicalDeviceFeatures2: Emulation found unrecognized structure type in pFeatures->pNext - "
Lenny Komow82e15e02017-10-02 15:08:53 -06006589 "this struct will be ignored");
6590
6591 struct VkStructureHeader *header = pNext;
6592 pNext = (void *)header->pNext;
6593 break;
6594 }
6595 }
6596 }
6597 }
6598}
6599
6600VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,
6601 VkPhysicalDeviceProperties2 *pProperties) {
6602 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
6603 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Lenny Komowa1524852017-10-02 15:08:53 -06006604 const struct loader_instance *inst = icd_term->this_instance;
Lenny Komow82e15e02017-10-02 15:08:53 -06006605
Lenny Komowa1524852017-10-02 15:08:53 -06006606 // Get the function pointer to use to call into the ICD. This could be the core or KHR version
6607 PFN_vkGetPhysicalDeviceProperties2 fpGetPhysicalDeviceProperties2 = NULL;
6608 if (inst != NULL && inst->enabled_known_extensions.khr_get_physical_device_properties2) {
6609 fpGetPhysicalDeviceProperties2 = icd_term->dispatch.GetPhysicalDeviceProperties2KHR;
6610 } else {
6611 fpGetPhysicalDeviceProperties2 = icd_term->dispatch.GetPhysicalDeviceProperties2;
6612 }
6613
Lenny Komow88dc89b2017-11-03 14:37:11 -06006614 if (fpGetPhysicalDeviceProperties2 != NULL || !inst->enabled_known_extensions.khr_get_physical_device_properties2) {
Lenny Komow82e15e02017-10-02 15:08:53 -06006615 // Pass the call to the driver
Lenny Komowa1524852017-10-02 15:08:53 -06006616 fpGetPhysicalDeviceProperties2(phys_dev_term->phys_dev, pProperties);
Lenny Komow82e15e02017-10-02 15:08:53 -06006617 } else {
6618 // Emulate the call
6619 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006620 "vkGetPhysicalDeviceProperties2: Emulating call in ICD \"%s\" using vkGetPhysicalDeviceProperties",
Lenny Komow82e15e02017-10-02 15:08:53 -06006621 icd_term->scanned_icd->lib_name);
6622
Lenny Komow802a9652017-10-03 13:59:21 -06006623 // Write to the VkPhysicalDeviceProperties2 struct
Lenny Komow82e15e02017-10-02 15:08:53 -06006624 icd_term->dispatch.GetPhysicalDeviceProperties(phys_dev_term->phys_dev, &pProperties->properties);
6625
6626 void *pNext = pProperties->pNext;
6627 while (pNext != NULL) {
6628 switch (*(VkStructureType *)pNext) {
Lenny Komow802a9652017-10-03 13:59:21 -06006629 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES: {
Lenny Komow82e15e02017-10-02 15:08:53 -06006630 VkPhysicalDeviceIDPropertiesKHR *id_properties = pNext;
6631
6632 // Verify that "VK_KHR_external_memory_capabilities" is enabled
6633 if (icd_term->this_instance->enabled_known_extensions.khr_external_memory_capabilities) {
6634 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006635 "vkGetPhysicalDeviceProperties2: Emulation cannot generate unique IDs for struct "
6636 "VkPhysicalDeviceIDProperties - setting IDs to zero instead");
Lenny Komow82e15e02017-10-02 15:08:53 -06006637
6638 // Write to the VkPhysicalDeviceIDPropertiesKHR struct
6639 memset(id_properties->deviceUUID, 0, VK_UUID_SIZE);
6640 memset(id_properties->driverUUID, 0, VK_UUID_SIZE);
6641 id_properties->deviceLUIDValid = VK_FALSE;
6642 }
6643
6644 pNext = id_properties->pNext;
6645 break;
6646 }
6647 default: {
6648 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
6649 "vkGetPhysicalDeviceProperties2KHR: Emulation found unrecognized structure type in "
6650 "pProperties->pNext - this struct will be ignored");
6651
6652 struct VkStructureHeader *header = pNext;
6653 pNext = (void *)header->pNext;
6654 break;
6655 }
6656 }
6657 }
6658 }
6659}
6660
6661VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format,
6662 VkFormatProperties2 *pFormatProperties) {
6663 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
6664 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Lenny Komowa1524852017-10-02 15:08:53 -06006665 const struct loader_instance *inst = icd_term->this_instance;
Lenny Komow82e15e02017-10-02 15:08:53 -06006666
Lenny Komowa1524852017-10-02 15:08:53 -06006667 // Get the function pointer to use to call into the ICD. This could be the core or KHR version
6668 PFN_vkGetPhysicalDeviceFormatProperties2 fpGetPhysicalDeviceFormatProperties2 = NULL;
6669 if (inst != NULL && inst->enabled_known_extensions.khr_get_physical_device_properties2) {
6670 fpGetPhysicalDeviceFormatProperties2 = icd_term->dispatch.GetPhysicalDeviceFormatProperties2KHR;
6671 } else {
6672 fpGetPhysicalDeviceFormatProperties2 = icd_term->dispatch.GetPhysicalDeviceFormatProperties2;
6673 }
6674
Lenny Komow88dc89b2017-11-03 14:37:11 -06006675 if (fpGetPhysicalDeviceFormatProperties2 != NULL || !inst->enabled_known_extensions.khr_get_physical_device_properties2) {
Lenny Komow82e15e02017-10-02 15:08:53 -06006676 // Pass the call to the driver
Lenny Komowa1524852017-10-02 15:08:53 -06006677 fpGetPhysicalDeviceFormatProperties2(phys_dev_term->phys_dev, format, pFormatProperties);
Lenny Komow82e15e02017-10-02 15:08:53 -06006678 } else {
6679 // Emulate the call
6680 loader_log(
6681 icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006682 "vkGetPhysicalDeviceFormatProperties2: Emulating call in ICD \"%s\" using vkGetPhysicalDeviceFormatProperties",
Lenny Komow82e15e02017-10-02 15:08:53 -06006683 icd_term->scanned_icd->lib_name);
6684
Lenny Komow802a9652017-10-03 13:59:21 -06006685 // Write to the VkFormatProperties2 struct
Lenny Komow82e15e02017-10-02 15:08:53 -06006686 icd_term->dispatch.GetPhysicalDeviceFormatProperties(phys_dev_term->phys_dev, format, &pFormatProperties->formatProperties);
6687
6688 if (pFormatProperties->pNext != NULL) {
6689 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006690 "vkGetPhysicalDeviceFormatProperties2: Emulation found unrecognized structure type in "
Lenny Komow82e15e02017-10-02 15:08:53 -06006691 "pFormatProperties->pNext - this struct will be ignored");
6692 }
6693 }
6694}
6695
6696VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceImageFormatProperties2(
6697 VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2KHR *pImageFormatInfo,
6698 VkImageFormatProperties2KHR *pImageFormatProperties) {
6699 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
6700 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Lenny Komowa1524852017-10-02 15:08:53 -06006701 const struct loader_instance *inst = icd_term->this_instance;
Lenny Komow82e15e02017-10-02 15:08:53 -06006702
Lenny Komowa1524852017-10-02 15:08:53 -06006703 // Get the function pointer to use to call into the ICD. This could be the core or KHR version
6704 PFN_vkGetPhysicalDeviceImageFormatProperties2 fpGetPhysicalDeviceImageFormatProperties2 = NULL;
6705 if (inst != NULL && inst->enabled_known_extensions.khr_get_physical_device_properties2) {
6706 fpGetPhysicalDeviceImageFormatProperties2 = icd_term->dispatch.GetPhysicalDeviceImageFormatProperties2KHR;
6707 } else {
6708 fpGetPhysicalDeviceImageFormatProperties2 = icd_term->dispatch.GetPhysicalDeviceImageFormatProperties2;
6709 }
6710
Lenny Komow88dc89b2017-11-03 14:37:11 -06006711 if (fpGetPhysicalDeviceImageFormatProperties2 != NULL || !inst->enabled_known_extensions.khr_get_physical_device_properties2) {
Lenny Komow82e15e02017-10-02 15:08:53 -06006712 // Pass the call to the driver
Lenny Komowa1524852017-10-02 15:08:53 -06006713 return fpGetPhysicalDeviceImageFormatProperties2(phys_dev_term->phys_dev, pImageFormatInfo, pImageFormatProperties);
Lenny Komow82e15e02017-10-02 15:08:53 -06006714 } else {
6715 // Emulate the call
6716 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006717 "vkGetPhysicalDeviceImageFormatProperties2: Emulating call in ICD \"%s\" using "
Lenny Komow82e15e02017-10-02 15:08:53 -06006718 "vkGetPhysicalDeviceImageFormatProperties",
6719 icd_term->scanned_icd->lib_name);
6720
6721 // If there is more info in either pNext, then this is unsupported
6722 if (pImageFormatInfo->pNext != NULL || pImageFormatProperties->pNext != NULL) {
6723 return VK_ERROR_FORMAT_NOT_SUPPORTED;
6724 }
6725
6726 // Write to the VkImageFormatProperties2KHR struct
6727 return icd_term->dispatch.GetPhysicalDeviceImageFormatProperties(
6728 phys_dev_term->phys_dev, pImageFormatInfo->format, pImageFormatInfo->type, pImageFormatInfo->tiling,
6729 pImageFormatInfo->usage, pImageFormatInfo->flags, &pImageFormatProperties->imageFormatProperties);
6730 }
6731}
6732
6733VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceQueueFamilyProperties2(
6734 VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
6735 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
6736 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Lenny Komowa1524852017-10-02 15:08:53 -06006737 const struct loader_instance *inst = icd_term->this_instance;
Lenny Komow82e15e02017-10-02 15:08:53 -06006738
Lenny Komowa1524852017-10-02 15:08:53 -06006739 // Get the function pointer to use to call into the ICD. This could be the core or KHR version
6740 PFN_vkGetPhysicalDeviceQueueFamilyProperties2 fpGetPhysicalDeviceQueueFamilyProperties2 = NULL;
6741 if (inst != NULL && inst->enabled_known_extensions.khr_get_physical_device_properties2) {
6742 fpGetPhysicalDeviceQueueFamilyProperties2 = icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties2KHR;
6743 } else {
6744 fpGetPhysicalDeviceQueueFamilyProperties2 = icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties2;
6745 }
6746
Lenny Komow88dc89b2017-11-03 14:37:11 -06006747 if (fpGetPhysicalDeviceQueueFamilyProperties2 != NULL || !inst->enabled_known_extensions.khr_get_physical_device_properties2) {
Lenny Komow82e15e02017-10-02 15:08:53 -06006748 // Pass the call to the driver
Lenny Komowa1524852017-10-02 15:08:53 -06006749 fpGetPhysicalDeviceQueueFamilyProperties2(phys_dev_term->phys_dev, pQueueFamilyPropertyCount, pQueueFamilyProperties);
Lenny Komow82e15e02017-10-02 15:08:53 -06006750 } else {
6751 // Emulate the call
6752 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006753 "vkGetPhysicalDeviceQueueFamilyProperties2: Emulating call in ICD \"%s\" using "
Lenny Komow82e15e02017-10-02 15:08:53 -06006754 "vkGetPhysicalDeviceQueueFamilyProperties",
6755 icd_term->scanned_icd->lib_name);
6756
6757 if (pQueueFamilyProperties == NULL || *pQueueFamilyPropertyCount == 0) {
6758 // Write to pQueueFamilyPropertyCount
6759 icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties(phys_dev_term->phys_dev, pQueueFamilyPropertyCount, NULL);
6760 } else {
6761 // Allocate a temporary array for the output of the old function
6762 VkQueueFamilyProperties *properties = loader_stack_alloc(*pQueueFamilyPropertyCount * sizeof(VkQueueFamilyProperties));
6763 if (properties == NULL) {
6764 *pQueueFamilyPropertyCount = 0;
6765 loader_log(
6766 icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006767 "vkGetPhysicalDeviceQueueFamilyProperties2: Out of memory - Failed to allocate array for loader emulation.");
Lenny Komow82e15e02017-10-02 15:08:53 -06006768 return;
6769 }
6770
6771 icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties(phys_dev_term->phys_dev, pQueueFamilyPropertyCount,
6772 properties);
6773 for (uint32_t i = 0; i < *pQueueFamilyPropertyCount; ++i) {
6774 // Write to the VkQueueFamilyProperties2KHR struct
6775 memcpy(&pQueueFamilyProperties[i].queueFamilyProperties, &properties[i], sizeof(VkQueueFamilyProperties));
6776
6777 if (pQueueFamilyProperties[i].pNext != NULL) {
6778 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006779 "vkGetPhysicalDeviceQueueFamilyProperties2: Emulation found unrecognized structure type in "
Lenny Komow82e15e02017-10-02 15:08:53 -06006780 "pQueueFamilyProperties[%d].pNext - this struct will be ignored",
6781 i);
6782 }
6783 }
6784 }
6785 }
6786}
6787
6788VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceMemoryProperties2(
6789 VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2 *pMemoryProperties) {
6790 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
6791 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Lenny Komowa1524852017-10-02 15:08:53 -06006792 const struct loader_instance *inst = icd_term->this_instance;
Lenny Komow82e15e02017-10-02 15:08:53 -06006793
Lenny Komowa1524852017-10-02 15:08:53 -06006794 // Get the function pointer to use to call into the ICD. This could be the core or KHR version
6795 PFN_vkGetPhysicalDeviceMemoryProperties2 fpGetPhysicalDeviceMemoryProperties2 = NULL;
6796 if (inst != NULL && inst->enabled_known_extensions.khr_get_physical_device_properties2) {
6797 fpGetPhysicalDeviceMemoryProperties2 = icd_term->dispatch.GetPhysicalDeviceMemoryProperties2KHR;
6798 } else {
6799 fpGetPhysicalDeviceMemoryProperties2 = icd_term->dispatch.GetPhysicalDeviceMemoryProperties2;
6800 }
6801
Lenny Komow88dc89b2017-11-03 14:37:11 -06006802 if (fpGetPhysicalDeviceMemoryProperties2 != NULL || !inst->enabled_known_extensions.khr_get_physical_device_properties2) {
Lenny Komow82e15e02017-10-02 15:08:53 -06006803 // Pass the call to the driver
Lenny Komowa1524852017-10-02 15:08:53 -06006804 fpGetPhysicalDeviceMemoryProperties2(phys_dev_term->phys_dev, pMemoryProperties);
Lenny Komow82e15e02017-10-02 15:08:53 -06006805 } else {
6806 // Emulate the call
6807 loader_log(
6808 icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006809 "vkGetPhysicalDeviceMemoryProperties2: Emulating call in ICD \"%s\" using vkGetPhysicalDeviceMemoryProperties",
Lenny Komow82e15e02017-10-02 15:08:53 -06006810 icd_term->scanned_icd->lib_name);
6811
6812 // Write to the VkPhysicalDeviceMemoryProperties2 struct
6813 icd_term->dispatch.GetPhysicalDeviceMemoryProperties(phys_dev_term->phys_dev, &pMemoryProperties->memoryProperties);
6814
6815 if (pMemoryProperties->pNext != NULL) {
6816 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006817 "vkGetPhysicalDeviceMemoryProperties2: Emulation found unrecognized structure type in "
Lenny Komow82e15e02017-10-02 15:08:53 -06006818 "pMemoryProperties->pNext - this struct will be ignored");
6819 }
6820 }
6821}
6822
6823VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceSparseImageFormatProperties2(
6824 VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2KHR *pFormatInfo, uint32_t *pPropertyCount,
6825 VkSparseImageFormatProperties2KHR *pProperties) {
6826 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
6827 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Lenny Komowa1524852017-10-02 15:08:53 -06006828 const struct loader_instance *inst = icd_term->this_instance;
Lenny Komow82e15e02017-10-02 15:08:53 -06006829
Lenny Komowa1524852017-10-02 15:08:53 -06006830 // Get the function pointer to use to call into the ICD. This could be the core or KHR version
6831 PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 fpGetPhysicalDeviceSparseImageFormatProperties2 = NULL;
6832 if (inst != NULL && inst->enabled_known_extensions.khr_get_physical_device_properties2) {
6833 fpGetPhysicalDeviceSparseImageFormatProperties2 = icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties2KHR;
6834 } else {
6835 fpGetPhysicalDeviceSparseImageFormatProperties2 = icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties2;
6836 }
6837
Lenny Komow88dc89b2017-11-03 14:37:11 -06006838 if (fpGetPhysicalDeviceSparseImageFormatProperties2 != NULL || !inst->enabled_known_extensions.khr_get_physical_device_properties2) {
Lenny Komow82e15e02017-10-02 15:08:53 -06006839 // Pass the call to the driver
Lenny Komowa1524852017-10-02 15:08:53 -06006840 fpGetPhysicalDeviceSparseImageFormatProperties2(phys_dev_term->phys_dev, pFormatInfo, pPropertyCount, pProperties);
Lenny Komow82e15e02017-10-02 15:08:53 -06006841 } else {
6842 // Emulate the call
6843 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006844 "vkGetPhysicalDeviceSparseImageFormatProperties2: Emulating call in ICD \"%s\" using "
Lenny Komow82e15e02017-10-02 15:08:53 -06006845 "vkGetPhysicalDeviceSparseImageFormatProperties",
6846 icd_term->scanned_icd->lib_name);
6847
6848 if (pFormatInfo->pNext != NULL) {
6849 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006850 "vkGetPhysicalDeviceSparseImageFormatProperties2: Emulation found unrecognized structure type in "
Lenny Komow82e15e02017-10-02 15:08:53 -06006851 "pFormatInfo->pNext - this struct will be ignored");
6852 }
6853
6854 if (pProperties == NULL || *pPropertyCount == 0) {
6855 // Write to pPropertyCount
6856 icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties(
6857 phys_dev_term->phys_dev, pFormatInfo->format, pFormatInfo->type, pFormatInfo->samples, pFormatInfo->usage,
6858 pFormatInfo->tiling, pPropertyCount, NULL);
6859 } else {
6860 // Allocate a temporary array for the output of the old function
6861 VkSparseImageFormatProperties *properties =
6862 loader_stack_alloc(*pPropertyCount * sizeof(VkSparseImageMemoryRequirements));
6863 if (properties == NULL) {
6864 *pPropertyCount = 0;
6865 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006866 "vkGetPhysicalDeviceSparseImageFormatProperties2: Out of memory - Failed to allocate array for "
Lenny Komow82e15e02017-10-02 15:08:53 -06006867 "loader emulation.");
6868 return;
6869 }
6870
6871 icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties(
6872 phys_dev_term->phys_dev, pFormatInfo->format, pFormatInfo->type, pFormatInfo->samples, pFormatInfo->usage,
6873 pFormatInfo->tiling, pPropertyCount, properties);
6874 for (uint32_t i = 0; i < *pPropertyCount; ++i) {
6875 // Write to the VkSparseImageFormatProperties2KHR struct
6876 memcpy(&pProperties[i].properties, &properties[i], sizeof(VkSparseImageFormatProperties));
6877
6878 if (pProperties[i].pNext != NULL) {
6879 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006880 "vkGetPhysicalDeviceSparseImageFormatProperties2: Emulation found unrecognized structure type in "
Lenny Komow82e15e02017-10-02 15:08:53 -06006881 "pProperties[%d].pNext - this struct will be ignored",
6882 i);
6883 }
6884 }
6885 }
6886 }
6887}
6888
6889VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceExternalBufferProperties(
6890 VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo,
6891 VkExternalBufferProperties *pExternalBufferProperties) {
6892 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
6893 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Lenny Komowa1524852017-10-02 15:08:53 -06006894 const struct loader_instance *inst = icd_term->this_instance;
Lenny Komow82e15e02017-10-02 15:08:53 -06006895
Lenny Komowa1524852017-10-02 15:08:53 -06006896 // Get the function pointer to use to call into the ICD. This could be the core or KHR version
6897 PFN_vkGetPhysicalDeviceExternalBufferProperties fpGetPhysicalDeviceExternalBufferProperties = NULL;
6898 if (inst != NULL && inst->enabled_known_extensions.khr_external_memory_capabilities) {
6899 fpGetPhysicalDeviceExternalBufferProperties = icd_term->dispatch.GetPhysicalDeviceExternalBufferPropertiesKHR;
6900 } else {
6901 fpGetPhysicalDeviceExternalBufferProperties = icd_term->dispatch.GetPhysicalDeviceExternalBufferProperties;
6902 }
6903
Lenny Komow88dc89b2017-11-03 14:37:11 -06006904 if (fpGetPhysicalDeviceExternalBufferProperties || !inst->enabled_known_extensions.khr_external_memory_capabilities) {
Lenny Komow82e15e02017-10-02 15:08:53 -06006905 // Pass the call to the driver
Lenny Komowa1524852017-10-02 15:08:53 -06006906 fpGetPhysicalDeviceExternalBufferProperties(phys_dev_term->phys_dev, pExternalBufferInfo, pExternalBufferProperties);
Lenny Komow82e15e02017-10-02 15:08:53 -06006907 } else {
6908 // Emulate the call
6909 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006910 "vkGetPhysicalDeviceExternalBufferProperties: Emulating call in ICD \"%s\"", icd_term->scanned_icd->lib_name);
Lenny Komow82e15e02017-10-02 15:08:53 -06006911
6912 if (pExternalBufferInfo->pNext != NULL) {
6913 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006914 "vkGetPhysicalDeviceExternalBufferProperties: Emulation found unrecognized structure type in "
Lenny Komow82e15e02017-10-02 15:08:53 -06006915 "pExternalBufferInfo->pNext - this struct will be ignored");
6916 }
6917
6918 // Fill in everything being unsupported
6919 memset(&pExternalBufferProperties->externalMemoryProperties, 0, sizeof(VkExternalMemoryPropertiesKHR));
6920
6921 if (pExternalBufferProperties->pNext != NULL) {
6922 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006923 "vkGetPhysicalDeviceExternalBufferProperties: Emulation found unrecognized structure type in "
Lenny Komow82e15e02017-10-02 15:08:53 -06006924 "pExternalBufferProperties->pNext - this struct will be ignored");
6925 }
6926 }
6927}
6928
6929VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceExternalSemaphoreProperties(
6930 VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo *pExternalSemaphoreInfo,
6931 VkExternalSemaphoreProperties *pExternalSemaphoreProperties) {
6932 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
6933 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Lenny Komowa1524852017-10-02 15:08:53 -06006934 const struct loader_instance *inst = icd_term->this_instance;
Lenny Komow82e15e02017-10-02 15:08:53 -06006935
Lenny Komowa1524852017-10-02 15:08:53 -06006936 // Get the function pointer to use to call into the ICD. This could be the core or KHR version
6937 PFN_vkGetPhysicalDeviceExternalSemaphoreProperties fpGetPhysicalDeviceExternalSemaphoreProperties = NULL;
6938 if (inst != NULL && inst->enabled_known_extensions.khr_external_semaphore_capabilities) {
6939 fpGetPhysicalDeviceExternalSemaphoreProperties = icd_term->dispatch.GetPhysicalDeviceExternalSemaphorePropertiesKHR;
6940 } else {
6941 fpGetPhysicalDeviceExternalSemaphoreProperties = icd_term->dispatch.GetPhysicalDeviceExternalSemaphoreProperties;
6942 }
6943
Lenny Komow88dc89b2017-11-03 14:37:11 -06006944 if (fpGetPhysicalDeviceExternalSemaphoreProperties != NULL || !inst->enabled_known_extensions.khr_external_semaphore_capabilities) {
Lenny Komow82e15e02017-10-02 15:08:53 -06006945 // Pass the call to the driver
Lenny Komowa1524852017-10-02 15:08:53 -06006946 fpGetPhysicalDeviceExternalSemaphoreProperties(phys_dev_term->phys_dev, pExternalSemaphoreInfo, pExternalSemaphoreProperties);
Lenny Komow82e15e02017-10-02 15:08:53 -06006947 } else {
6948 // Emulate the call
6949 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006950 "vkGetPhysicalDeviceExternalSemaphoreProperties: Emulating call in ICD \"%s\"",
Lenny Komow82e15e02017-10-02 15:08:53 -06006951 icd_term->scanned_icd->lib_name);
6952
6953 if (pExternalSemaphoreInfo->pNext != NULL) {
6954 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006955 "vkGetPhysicalDeviceExternalSemaphoreProperties: Emulation found unrecognized structure type in "
Lenny Komow82e15e02017-10-02 15:08:53 -06006956 "pExternalSemaphoreInfo->pNext - this struct will be ignored");
6957 }
6958
6959 // Fill in everything being unsupported
6960 pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
6961 pExternalSemaphoreProperties->compatibleHandleTypes = 0;
6962 pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
6963
6964 if (pExternalSemaphoreProperties->pNext != NULL) {
6965 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006966 "vkGetPhysicalDeviceExternalSemaphoreProperties: Emulation found unrecognized structure type in "
Lenny Komow82e15e02017-10-02 15:08:53 -06006967 "pExternalSemaphoreProperties->pNext - this struct will be ignored");
6968 }
6969 }
6970}
6971
6972VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceExternalFenceProperties(
6973 VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo *pExternalFenceInfo,
6974 VkExternalFenceProperties *pExternalFenceProperties) {
6975 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
6976 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Lenny Komowa1524852017-10-02 15:08:53 -06006977 const struct loader_instance *inst = icd_term->this_instance;
Lenny Komow82e15e02017-10-02 15:08:53 -06006978
Lenny Komowa1524852017-10-02 15:08:53 -06006979 // Get the function pointer to use to call into the ICD. This could be the core or KHR version
6980 PFN_vkGetPhysicalDeviceExternalFenceProperties fpGetPhysicalDeviceExternalFenceProperties = NULL;
6981 if (inst != NULL && inst->enabled_known_extensions.khr_external_fence_capabilities) {
6982 fpGetPhysicalDeviceExternalFenceProperties = icd_term->dispatch.GetPhysicalDeviceExternalFencePropertiesKHR;
6983 } else {
6984 fpGetPhysicalDeviceExternalFenceProperties = icd_term->dispatch.GetPhysicalDeviceExternalFenceProperties;
6985 }
6986
Lenny Komow88dc89b2017-11-03 14:37:11 -06006987 if (fpGetPhysicalDeviceExternalFenceProperties != NULL || !inst->enabled_known_extensions.khr_external_fence_capabilities) {
Lenny Komow82e15e02017-10-02 15:08:53 -06006988 // Pass the call to the driver
Lenny Komowa1524852017-10-02 15:08:53 -06006989 fpGetPhysicalDeviceExternalFenceProperties(phys_dev_term->phys_dev, pExternalFenceInfo, pExternalFenceProperties);
Lenny Komow82e15e02017-10-02 15:08:53 -06006990 } else {
6991 // Emulate the call
6992 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006993 "vkGetPhysicalDeviceExternalFenceProperties: Emulating call in ICD \"%s\"", icd_term->scanned_icd->lib_name);
Lenny Komow82e15e02017-10-02 15:08:53 -06006994
6995 if (pExternalFenceInfo->pNext != NULL) {
6996 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06006997 "vkGetPhysicalDeviceExternalFenceProperties: Emulation found unrecognized structure type in "
Lenny Komow82e15e02017-10-02 15:08:53 -06006998 "pExternalFenceInfo->pNext - this struct will be ignored");
6999 }
7000
7001 // Fill in everything being unsupported
7002 pExternalFenceProperties->exportFromImportedHandleTypes = 0;
7003 pExternalFenceProperties->compatibleHandleTypes = 0;
7004 pExternalFenceProperties->externalFenceFeatures = 0;
7005
7006 if (pExternalFenceProperties->pNext != NULL) {
7007 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komow802a9652017-10-03 13:59:21 -06007008 "vkGetPhysicalDeviceExternalFenceProperties: Emulation found unrecognized structure type in "
Lenny Komow82e15e02017-10-02 15:08:53 -06007009 "pExternalFenceProperties->pNext - this struct will be ignored");
7010 }
7011 }
7012}