blob: b9f315e7faa97aed1a2be9bb1b17a682530a2a7a [file] [log] [blame]
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001/*
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06002 * Vulkan
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08003 *
4 * Copyright (C) 2014 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
Chia-I Wu701f3f62014-09-02 08:32:09 +080023 *
24 * Authors:
25 * Chia-I Wu <olv@lunarg.com>
Jon Ashburn01e2d662014-11-14 09:52:42 -070026 * Jon Ashburn <jon@lunarg.com>
Chia-I Wu701f3f62014-09-02 08:32:09 +080027 * Courtney Goeltzenleuchter <courtney@lunarg.com>
Ian Elliott5aa4ea22015-03-31 15:32:41 -060028 * Ian Elliott <ian@lunarg.com>
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080029 */
Jon Ashburn6b4d70c2014-10-22 18:13:16 -060030#define _GNU_SOURCE
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080031#include <stdio.h>
32#include <stdlib.h>
33#include <stdarg.h>
34#include <stdbool.h>
35#include <string.h>
36
Chia-I Wu13a61a52014-08-04 11:18:20 +080037#include <sys/types.h>
Ian Elliott2d4ab1e2015-01-13 17:52:38 -070038#if defined(WIN32)
39#include "dirent_on_windows.h"
40#else // WIN32
Chia-I Wu13a61a52014-08-04 11:18:20 +080041#include <dirent.h>
Ian Elliott2d4ab1e2015-01-13 17:52:38 -070042#endif // WIN32
43#include "loader_platform.h"
Chia-I Wuf46b81a2015-01-04 11:12:47 +080044#include "table_ops.h"
Chia-I Wu19300602014-08-04 08:03:57 +080045#include "loader.h"
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -060046#include "vkIcd.h"
Ian Elliott655cad72015-02-12 17:08:34 -070047// The following is #included again to catch certain OS-specific functions
48// being used:
49#include "loader_platform.h"
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080050
Jon Ashburn6b4d70c2014-10-22 18:13:16 -060051struct loader_layers {
Ian Elliott2d4ab1e2015-01-13 17:52:38 -070052 loader_platform_dl_handle lib_handle;
Jon Ashburnb8358052014-11-18 09:06:04 -070053 char name[256];
54};
55
56struct layer_name_pair {
57 char *layer_name;
58 const char *lib_name;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -060059};
60
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080061struct loader_icd {
Jon Ashburn46d1f582015-01-28 11:01:35 -070062 const struct loader_scanned_icds *scanned_icds;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080063
Jon Ashburnbacb0f52015-04-06 10:58:22 -060064 VkLayerDispatchTable *loader_dispatch;
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -060065 uint32_t layer_count[VK_MAX_PHYSICAL_GPUS];
66 struct loader_layers layer_libs[VK_MAX_PHYSICAL_GPUS][MAX_LAYER_LIBRARIES];
Jon Ashburnbacb0f52015-04-06 10:58:22 -060067 VkBaseLayerObject *wrappedGpus[VK_MAX_PHYSICAL_GPUS];
Mark Lobodzinski17caf572015-01-29 08:55:56 -060068 uint32_t gpu_count;
Jon Ashburnbacb0f52015-04-06 10:58:22 -060069 VkBaseLayerObject *gpus;
Jon Ashburndf7d5842014-10-16 15:48:50 -060070
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080071 struct loader_icd *next;
72};
73
Jon Ashburnd38bfb12014-10-14 19:15:22 -060074
Jon Ashburn46d1f582015-01-28 11:01:35 -070075struct loader_scanned_icds {
Ian Elliott2d4ab1e2015-01-13 17:52:38 -070076 loader_platform_dl_handle handle;
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -060077 PFN_vkGetProcAddr GetProcAddr;
78 PFN_vkCreateInstance CreateInstance;
79 PFN_vkDestroyInstance DestroyInstance;
80 PFN_vkEnumerateGpus EnumerateGpus;
81 PFN_vkGetExtensionSupport GetExtensionSupport;
82 VkInstance instance;
Jon Ashburn46d1f582015-01-28 11:01:35 -070083 struct loader_scanned_icds *next;
84};
Jon Ashburnd38bfb12014-10-14 19:15:22 -060085
Jon Ashburn1beab2d2015-01-26 14:51:40 -070086// Note: Since the following is a static structure, all members are initialized
87// to zero.
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080088static struct {
Jon Ashburn1beab2d2015-01-26 14:51:40 -070089 struct loader_instance *instances;
Jon Ashburn46d1f582015-01-28 11:01:35 -070090 bool icds_scanned;
91 struct loader_scanned_icds *scanned_icd_list;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -060092 bool layer_scanned;
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -070093 char *layer_dirs;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -060094 unsigned int scanned_layer_count;
95 char *scanned_layer_names[MAX_LAYER_LIBRARIES];
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080096} loader;
97
Ian Elliott2d4ab1e2015-01-13 17:52:38 -070098
Ian Elliott4470a302015-02-17 10:33:47 -070099#if defined(WIN32)
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600100char *loader_get_registry_string(const HKEY hive,
101 const LPCTSTR sub_key,
102 const char *value)
103{
104 DWORD access_flags = KEY_QUERY_VALUE;
105 DWORD value_type;
106 HKEY key;
107 LONG rtn_value;
108 char *rtn_str = NULL;
109 size_t rtn_len = 0;
110 size_t allocated_len = 0;
111
112 rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
113 if (rtn_value != ERROR_SUCCESS) {
114 // We didn't find the key. Try the 32-bit hive (where we've seen the
115 // key end up on some people's systems):
116 access_flags |= KEY_WOW64_32KEY;
117 rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
118 if (rtn_value != ERROR_SUCCESS) {
119 // We still couldn't find the key, so give up:
120 return NULL;
121 }
122 }
123
124 rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
125 (PVOID) rtn_str, &rtn_len);
126 if (rtn_value == ERROR_SUCCESS) {
127 // If we get to here, we found the key, and need to allocate memory
128 // large enough for rtn_str, and query again:
129 allocated_len = rtn_len + 4;
130 rtn_str = malloc(allocated_len);
131 rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
132 (PVOID) rtn_str, &rtn_len);
133 if (rtn_value == ERROR_SUCCESS) {
134 // We added 4 extra bytes to rtn_str, so that we can ensure that
135 // the string is NULL-terminated (albeit, in a brute-force manner):
136 rtn_str[allocated_len-1] = '\0';
137 } else {
138 // This should never occur, but in case it does, clean up:
139 free(rtn_str);
140 rtn_str = NULL;
141 }
142 } // else - shouldn't happen, but if it does, return rtn_str, which is NULL
143
144 // Close the registry key that was opened:
145 RegCloseKey(key);
146
147 return rtn_str;
148}
149
150
Ian Elliott4470a302015-02-17 10:33:47 -0700151// For ICD developers, look in the registry, and look for an environment
152// variable for a path(s) where to find the ICD(s):
153static char *loader_get_registry_and_env(const char *env_var,
154 const char *registry_value)
155{
156 char *env_str = getenv(env_var);
157 size_t env_len = (env_str == NULL) ? 0 : strlen(env_str);
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600158 char *registry_str = NULL;
159 DWORD registry_len = 0;
Ian Elliott4470a302015-02-17 10:33:47 -0700160 char *rtn_str = NULL;
161 size_t rtn_len;
162
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600163 registry_str = loader_get_registry_string(HKEY_LOCAL_MACHINE,
Ian Elliott06ebd752015-04-09 18:07:15 -0600164 "Software\\Vulkan",
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600165 registry_value);
Ian Elliott2de26bc2015-04-03 13:13:01 -0600166 registry_len = (registry_str) ? strlen(registry_str) : 0;
Ian Elliott4470a302015-02-17 10:33:47 -0700167
168 rtn_len = env_len + registry_len + 1;
169 if (rtn_len <= 2) {
170 // We found neither the desired registry value, nor the environment
171 // variable; return NULL:
172 return NULL;
173 } else {
174 // We found something, and so we need to allocate memory for the string
175 // to return:
176 rtn_str = malloc(rtn_len);
177 }
178
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600179 if (registry_len == 0) {
Ian Elliott4470a302015-02-17 10:33:47 -0700180 // We didn't find the desired registry value, and so we must have found
181 // only the environment variable:
182 _snprintf(rtn_str, rtn_len, "%s", env_str);
183 } else if (env_str != NULL) {
184 // We found both the desired registry value and the environment
185 // variable, so concatenate them both:
186 _snprintf(rtn_str, rtn_len, "%s;%s", registry_str, env_str);
187 } else {
188 // We must have only found the desired registry value:
189 _snprintf(rtn_str, rtn_len, "%s", registry_str);
190 }
191
Ian Elliott2de26bc2015-04-03 13:13:01 -0600192 if (registry_str) {
193 free(registry_str);
194 }
Ian Elliott4470a302015-02-17 10:33:47 -0700195
196 return(rtn_str);
197}
198#endif // WIN32
199
200
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600201static void loader_log(VK_DBG_MSG_TYPE msg_type, int32_t msg_code,
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800202 const char *format, ...)
203{
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800204 char msg[256];
205 va_list ap;
206 int ret;
207
208 va_start(ap, format);
209 ret = vsnprintf(msg, sizeof(msg), format, ap);
Ian Elliott42045842015-02-13 14:29:21 -0700210 if ((ret >= (int) sizeof(msg)) || ret < 0) {
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800211 msg[sizeof(msg) - 1] = '\0';
212 }
213 va_end(ap);
214
Courtney Goeltzenleuchterc80a5572015-04-13 14:10:06 -0600215 fputs(msg, stderr);
216 fputc('\n', stderr);
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800217}
218
219static void
220loader_icd_destroy(struct loader_icd *icd)
221{
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700222 loader_platform_close_library(icd->scanned_icds->handle);
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800223 free(icd);
224}
225
226static struct loader_icd *
Jon Ashburn46d1f582015-01-28 11:01:35 -0700227loader_icd_create(const struct loader_scanned_icds *scanned)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800228{
229 struct loader_icd *icd;
230
231 icd = malloc(sizeof(*icd));
232 if (!icd)
233 return NULL;
234
Courtney Goeltzenleuchter55001bb2014-10-28 10:29:27 -0600235 memset(icd, 0, sizeof(*icd));
236
Jon Ashburn46d1f582015-01-28 11:01:35 -0700237 icd->scanned_icds = scanned;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800238
239 return icd;
240}
241
Jon Ashburn46888392015-01-29 15:45:51 -0700242static struct loader_icd *loader_icd_add(struct loader_instance *ptr_inst,
243 const struct loader_scanned_icds *scanned)
Chia-I Wu13a61a52014-08-04 11:18:20 +0800244{
245 struct loader_icd *icd;
246
Jon Ashburn46d1f582015-01-28 11:01:35 -0700247 icd = loader_icd_create(scanned);
Chia-I Wu13a61a52014-08-04 11:18:20 +0800248 if (!icd)
249 return NULL;
250
Chia-I Wu13a61a52014-08-04 11:18:20 +0800251 /* prepend to the list */
Jon Ashburn46888392015-01-29 15:45:51 -0700252 icd->next = ptr_inst->icds;
253 ptr_inst->icds = icd;
Chia-I Wu13a61a52014-08-04 11:18:20 +0800254
255 return icd;
256}
257
Jon Ashburn46d1f582015-01-28 11:01:35 -0700258static void loader_scanned_icd_add(const char *filename)
259{
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700260 loader_platform_dl_handle handle;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -0700261 void *fp_gpa, *fp_enumerate, *fp_create_inst, *fp_destroy_inst, *fp_get_extension_support;
Jon Ashburn46d1f582015-01-28 11:01:35 -0700262 struct loader_scanned_icds *new_node;
263
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700264 // Used to call: dlopen(filename, RTLD_LAZY);
265 handle = loader_platform_open_library(filename);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700266 if (!handle) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600267 loader_log(VK_DBG_MSG_WARNING, 0, loader_platform_open_library_error(filename));
Jon Ashburn46d1f582015-01-28 11:01:35 -0700268 return;
269 }
270
271#define LOOKUP(func_ptr, func) do { \
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600272 func_ptr = (PFN_vk ##func) loader_platform_get_proc_address(handle, "vk" #func); \
Jon Ashburn46d1f582015-01-28 11:01:35 -0700273 if (!func_ptr) { \
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600274 loader_log(VK_DBG_MSG_WARNING, 0, loader_platform_get_proc_address_error("vk" #func)); \
Jon Ashburn46d1f582015-01-28 11:01:35 -0700275 return; \
276 } \
277} while (0)
278
279 LOOKUP(fp_gpa, GetProcAddr);
Jon Ashburn46888392015-01-29 15:45:51 -0700280 LOOKUP(fp_create_inst, CreateInstance);
281 LOOKUP(fp_destroy_inst, DestroyInstance);
Jon Ashburn4c392fb2015-01-28 19:57:09 -0700282 LOOKUP(fp_enumerate, EnumerateGpus);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -0700283 LOOKUP(fp_get_extension_support, GetExtensionSupport);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700284#undef LOOKUP
285
286 new_node = (struct loader_scanned_icds *) malloc(sizeof(struct loader_scanned_icds));
287 if (!new_node) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600288 loader_log(VK_DBG_MSG_WARNING, 0, "Out of memory can't add icd");
Jon Ashburn46d1f582015-01-28 11:01:35 -0700289 return;
290 }
291
292 new_node->handle = handle;
293 new_node->GetProcAddr = fp_gpa;
Jon Ashburn46888392015-01-29 15:45:51 -0700294 new_node->CreateInstance = fp_create_inst;
295 new_node->DestroyInstance = fp_destroy_inst;
Jon Ashburn4c392fb2015-01-28 19:57:09 -0700296 new_node->EnumerateGpus = fp_enumerate;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -0700297 new_node->GetExtensionSupport = fp_get_extension_support;
Jon Ashburn46d1f582015-01-28 11:01:35 -0700298 new_node->next = loader.scanned_icd_list;
299 loader.scanned_icd_list = new_node;
300}
301
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700302
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600303/**
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600304 * Try to \c loader_icd_scan VK driver(s).
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600305 *
306 * This function scans the default system path or path
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600307 * specified by the \c LIBVK_DRIVERS_PATH environment variable in
308 * order to find loadable VK ICDs with the name of libVK_*.
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600309 *
310 * \returns
311 * void; but side effect is to set loader_icd_scanned to true
312 */
313static void loader_icd_scan(void)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800314{
Ian Elliott4470a302015-02-17 10:33:47 -0700315 const char *p, *next;
316 char *libPaths = NULL;
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600317 DIR *sysdir;
318 struct dirent *dent;
319 char icd_library[1024];
Jon Ashburn5cda59c2014-10-03 16:31:35 -0600320 char path[1024];
Ian Elliott19628802015-02-04 12:06:46 -0700321 uint32_t len;
Ian Elliott4470a302015-02-17 10:33:47 -0700322#if defined(WIN32)
323 bool must_free_libPaths;
324 libPaths = loader_get_registry_and_env(DRIVER_PATH_ENV,
325 DRIVER_PATH_REGISTRY_VALUE);
326 if (libPaths != NULL) {
327 must_free_libPaths = true;
328 } else {
329 must_free_libPaths = false;
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600330 libPaths = DEFAULT_VK_DRIVERS_PATH;
Ian Elliott4470a302015-02-17 10:33:47 -0700331 }
332#else // WIN32
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600333 if (geteuid() == getuid()) {
Ian Elliott4470a302015-02-17 10:33:47 -0700334 /* Don't allow setuid apps to use the DRIVER_PATH_ENV env var: */
335 libPaths = getenv(DRIVER_PATH_ENV);
336 }
337 if (libPaths == NULL) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600338 libPaths = DEFAULT_VK_DRIVERS_PATH;
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600339 }
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700340#endif // WIN32
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800341
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600342 for (p = libPaths; *p; p = next) {
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700343 next = strchr(p, PATH_SEPERATOR);
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600344 if (next == NULL) {
Ian Elliott19628802015-02-04 12:06:46 -0700345 len = (uint32_t) strlen(p);
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600346 next = p + len;
347 }
348 else {
Ian Elliott19628802015-02-04 12:06:46 -0700349 len = (uint32_t) (next - p);
Jon Ashburn5cda59c2014-10-03 16:31:35 -0600350 sprintf(path, "%.*s", (len > sizeof(path) - 1) ? (int) sizeof(path) - 1 : len, p);
351 p = path;
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600352 next++;
353 }
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800354
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700355 // TODO/TBD: Do we want to do this on Windows, or just let Windows take
356 // care of its own search path (which it apparently has)?
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600357 sysdir = opendir(p);
358 if (sysdir) {
359 dent = readdir(sysdir);
360 while (dent) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600361 /* Look for ICDs starting with VK_DRIVER_LIBRARY_PREFIX and
362 * ending with VK_LIBRARY_SUFFIX
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700363 */
364 if (!strncmp(dent->d_name,
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600365 VK_DRIVER_LIBRARY_PREFIX,
366 VK_DRIVER_LIBRARY_PREFIX_LEN)) {
Ian Elliott19628802015-02-04 12:06:46 -0700367 uint32_t nlen = (uint32_t) strlen(dent->d_name);
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600368 const char *suf = dent->d_name + nlen - VK_LIBRARY_SUFFIX_LEN;
369 if ((nlen > VK_LIBRARY_SUFFIX_LEN) &&
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700370 !strncmp(suf,
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600371 VK_LIBRARY_SUFFIX,
372 VK_LIBRARY_SUFFIX_LEN)) {
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700373 snprintf(icd_library, 1024, "%s" DIRECTORY_SYMBOL "%s", p,dent->d_name);
374 loader_scanned_icd_add(icd_library);
375 }
376 }
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600377
378 dent = readdir(sysdir);
379 }
380 closedir(sysdir);
381 }
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800382 }
383
Ian Elliott4470a302015-02-17 10:33:47 -0700384#if defined(WIN32)
385 // Free any allocated memory:
386 if (must_free_libPaths) {
387 free(libPaths);
388 }
389#endif // WIN32
390
391 // Note that we've scanned for ICDs:
Jon Ashburn46d1f582015-01-28 11:01:35 -0700392 loader.icds_scanned = true;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800393}
394
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600395
Ian Elliott4470a302015-02-17 10:33:47 -0700396static void layer_lib_scan(void)
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600397{
398 const char *p, *next;
Ian Elliott4470a302015-02-17 10:33:47 -0700399 char *libPaths = NULL;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600400 DIR *curdir;
401 struct dirent *dent;
Ian Elliott4470a302015-02-17 10:33:47 -0700402 size_t len, i;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600403 char temp_str[1024];
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600404
Ian Elliott4470a302015-02-17 10:33:47 -0700405#if defined(WIN32)
406 bool must_free_libPaths;
407 libPaths = loader_get_registry_and_env(LAYERS_PATH_ENV,
408 LAYERS_PATH_REGISTRY_VALUE);
409 if (libPaths != NULL) {
410 must_free_libPaths = true;
411 } else {
412 must_free_libPaths = false;
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600413 libPaths = DEFAULT_VK_LAYERS_PATH;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600414 }
Ian Elliott4470a302015-02-17 10:33:47 -0700415#else // WIN32
416 if (geteuid() == getuid()) {
417 /* Don't allow setuid apps to use the DRIVER_PATH_ENV env var: */
Courtney Goeltzenleuchter66b72f92015-02-18 20:03:02 -0700418 libPaths = getenv(LAYERS_PATH_ENV);
Ian Elliott4470a302015-02-17 10:33:47 -0700419 }
420 if (libPaths == NULL) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600421 libPaths = DEFAULT_VK_LAYERS_PATH;
Ian Elliott4470a302015-02-17 10:33:47 -0700422 }
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700423#endif // WIN32
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600424
Ian Elliott4470a302015-02-17 10:33:47 -0700425 if (libPaths == NULL) {
426 // Have no paths to search:
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -0700427 return;
428 }
Ian Elliott4470a302015-02-17 10:33:47 -0700429 len = strlen(libPaths);
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -0700430 loader.layer_dirs = malloc(len+1);
Ian Elliott4470a302015-02-17 10:33:47 -0700431 if (loader.layer_dirs == NULL) {
432 free(libPaths);
Courtney Goeltzenleuchtera66265b2014-12-02 18:12:51 -0700433 return;
Ian Elliott4470a302015-02-17 10:33:47 -0700434 }
435 // Alloc passed, so we know there is enough space to hold the string, don't
436 // need strncpy
437 strcpy(loader.layer_dirs, libPaths);
438#if defined(WIN32)
439 // Free any allocated memory:
440 if (must_free_libPaths) {
441 free(libPaths);
442 must_free_libPaths = false;
443 }
444#endif // WIN32
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -0700445 libPaths = loader.layer_dirs;
446
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600447 /* cleanup any previously scanned libraries */
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600448 for (i = 0; i < loader.scanned_layer_count; i++) {
449 if (loader.scanned_layer_names[i] != NULL)
450 free(loader.scanned_layer_names[i]);
451 loader.scanned_layer_names[i] = NULL;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600452 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600453 loader.scanned_layer_count = 0;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600454
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600455 for (p = libPaths; *p; p = next) {
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700456 next = strchr(p, PATH_SEPERATOR);
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600457 if (next == NULL) {
Ian Elliott19628802015-02-04 12:06:46 -0700458 len = (uint32_t) strlen(p);
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600459 next = p + len;
460 }
461 else {
Ian Elliott19628802015-02-04 12:06:46 -0700462 len = (uint32_t) (next - p);
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600463 *(char *) next = '\0';
464 next++;
465 }
466
467 curdir = opendir(p);
468 if (curdir) {
469 dent = readdir(curdir);
470 while (dent) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600471 /* Look for layers starting with VK_LAYER_LIBRARY_PREFIX and
472 * ending with VK_LIBRARY_SUFFIX
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700473 */
474 if (!strncmp(dent->d_name,
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600475 VK_LAYER_LIBRARY_PREFIX,
476 VK_LAYER_LIBRARY_PREFIX_LEN)) {
Ian Elliott19628802015-02-04 12:06:46 -0700477 uint32_t nlen = (uint32_t) strlen(dent->d_name);
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600478 const char *suf = dent->d_name + nlen - VK_LIBRARY_SUFFIX_LEN;
479 if ((nlen > VK_LIBRARY_SUFFIX_LEN) &&
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700480 !strncmp(suf,
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600481 VK_LIBRARY_SUFFIX,
482 VK_LIBRARY_SUFFIX_LEN)) {
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700483 loader_platform_dl_handle handle;
484 snprintf(temp_str, sizeof(temp_str), "%s" DIRECTORY_SYMBOL "%s",p,dent->d_name);
485 // Used to call: dlopen(temp_str, RTLD_LAZY)
486 if ((handle = loader_platform_open_library(temp_str)) == NULL) {
487 dent = readdir(curdir);
488 continue;
489 }
490 if (loader.scanned_layer_count == MAX_LAYER_LIBRARIES) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600491 loader_log(VK_DBG_MSG_ERROR, 0, "%s ignored: max layer libraries exceed", temp_str);
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700492 break;
493 }
494 if ((loader.scanned_layer_names[loader.scanned_layer_count] = malloc(strlen(temp_str) + 1)) == NULL) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600495 loader_log(VK_DBG_MSG_ERROR, 0, "%s ignored: out of memory", temp_str);
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700496 break;
497 }
498 strcpy(loader.scanned_layer_names[loader.scanned_layer_count], temp_str);
499 loader.scanned_layer_count++;
500 loader_platform_close_library(handle);
501 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600502 }
503
504 dent = readdir(curdir);
505 }
506 closedir(curdir);
507 }
508 }
509
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600510 loader.layer_scanned = true;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600511}
512
Jon Ashburnbacb0f52015-04-06 10:58:22 -0600513static void loader_init_dispatch_table(VkLayerDispatchTable *tab, PFN_vkGetProcAddr fpGPA, VkPhysicalGpu gpu)
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600514{
Chia-I Wuf46b81a2015-01-04 11:12:47 +0800515 loader_initialize_dispatch_table(tab, fpGPA, gpu);
516
Jon Ashburnf7bcf9b2014-10-15 15:30:23 -0600517 if (tab->EnumerateLayers == NULL)
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600518 tab->EnumerateLayers = vkEnumerateLayers;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600519}
520
Jon Ashburnbacb0f52015-04-06 10:58:22 -0600521extern struct loader_icd * loader_get_icd(const VkBaseLayerObject *gpu, uint32_t *gpu_index)
Jon Ashburn876b1ac2014-10-17 15:09:07 -0600522{
Jon Ashburn98bd4542015-01-29 16:44:24 -0700523 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
524 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
525 for (uint32_t i = 0; i < icd->gpu_count; i++)
526 if ((icd->gpus + i) == gpu || (icd->gpus +i)->baseObject ==
527 gpu->baseObject) {
528 *gpu_index = i;
529 return icd;
530 }
531 }
Jon Ashburn876b1ac2014-10-17 15:09:07 -0600532 }
533 return NULL;
534}
535
Mark Lobodzinski17caf572015-01-29 08:55:56 -0600536static bool loader_layers_activated(const struct loader_icd *icd, const uint32_t gpu_index)
Jon Ashburn876b1ac2014-10-17 15:09:07 -0600537{
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600538 if (icd->layer_count[gpu_index])
539 return true;
540 else
541 return false;
Jon Ashburn876b1ac2014-10-17 15:09:07 -0600542}
543
Mark Lobodzinski17caf572015-01-29 08:55:56 -0600544static void loader_init_layer_libs(struct loader_icd *icd, uint32_t gpu_index, struct layer_name_pair * pLayerNames, uint32_t count)
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600545{
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600546 if (!icd)
547 return;
Jon Ashburndf7d5842014-10-16 15:48:50 -0600548
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600549 struct loader_layers *obj;
550 bool foundLib;
Mark Lobodzinski17caf572015-01-29 08:55:56 -0600551 for (uint32_t i = 0; i < count; i++) {
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600552 foundLib = false;
Mark Lobodzinski17caf572015-01-29 08:55:56 -0600553 for (uint32_t j = 0; j < icd->layer_count[gpu_index]; j++) {
Jon Ashburnb8358052014-11-18 09:06:04 -0700554 if (icd->layer_libs[gpu_index][j].lib_handle && !strcmp(icd->layer_libs[gpu_index][j].name, (char *) pLayerNames[i].layer_name)) {
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600555 foundLib = true;
556 break;
557 }
558 }
559 if (!foundLib) {
560 obj = &(icd->layer_libs[gpu_index][i]);
Jon Ashburnb8358052014-11-18 09:06:04 -0700561 strncpy(obj->name, (char *) pLayerNames[i].layer_name, sizeof(obj->name) - 1);
562 obj->name[sizeof(obj->name) - 1] = '\0';
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700563 // Used to call: dlopen(pLayerNames[i].lib_name, RTLD_LAZY | RTLD_DEEPBIND)
564 if ((obj->lib_handle = loader_platform_open_library(pLayerNames[i].lib_name)) == NULL) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600565 loader_log(VK_DBG_MSG_ERROR, 0, loader_platform_open_library_error(pLayerNames[i].lib_name));
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600566 continue;
567 } else {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600568 loader_log(VK_DBG_MSG_UNKNOWN, 0, "Inserting layer %s from library %s", pLayerNames[i].layer_name, pLayerNames[i].lib_name);
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600569 }
Jon Ashburnb8358052014-11-18 09:06:04 -0700570 free(pLayerNames[i].layer_name);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600571 icd->layer_count[gpu_index]++;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600572 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600573 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600574}
575
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600576static VkResult find_layer_extension(struct loader_icd *icd, uint32_t gpu_index, const char *pExtName, const char **lib_name)
Jon Ashburnb8358052014-11-18 09:06:04 -0700577{
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600578 VkResult err;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -0700579 char *search_name;
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700580 loader_platform_dl_handle handle;
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600581 PFN_vkGetExtensionSupport fpGetExtensionSupport;
Jon Ashburnb8358052014-11-18 09:06:04 -0700582
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -0700583 /*
584 * The loader provides the abstraction that make layers and extensions work via
585 * the currently defined extension mechanism. That is, when app queries for an extension
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600586 * via vkGetExtensionSupport, the loader will call both the driver as well as any layers
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -0700587 * to see who implements that extension. Then, if the app enables the extension during
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600588 * vkCreateDevice the loader will find and load any layers that implement that extension.
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -0700589 */
Jon Ashburnb8358052014-11-18 09:06:04 -0700590
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -0700591 // TODO: What if extension is in multiple places?
592
593 // TODO: Who should we ask first? Driver or layers? Do driver for now.
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600594 err = icd->scanned_icds[gpu_index].GetExtensionSupport((VkPhysicalGpu) (icd->gpus[gpu_index].nextObject), pExtName);
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600595 if (err == VK_SUCCESS) {
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -0700596 if (lib_name) {
597 *lib_name = NULL;
Jon Ashburnb8358052014-11-18 09:06:04 -0700598 }
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600599 return VK_SUCCESS;
Jon Ashburnb8358052014-11-18 09:06:04 -0700600 }
601
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -0700602 for (unsigned int j = 0; j < loader.scanned_layer_count; j++) {
603 search_name = loader.scanned_layer_names[j];
604
605 if ((handle = loader_platform_open_library(search_name)) == NULL)
606 continue;
607
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600608 fpGetExtensionSupport = loader_platform_get_proc_address(handle, "vkGetExtensionSupport");
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -0700609
610 if (fpGetExtensionSupport != NULL) {
611 // Found layer's GetExtensionSupport call
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600612 err = fpGetExtensionSupport((VkPhysicalGpu) (icd->gpus + gpu_index), pExtName);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -0700613
614 loader_platform_close_library(handle);
615
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600616 if (err == VK_SUCCESS) {
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -0700617 if (lib_name) {
618 *lib_name = loader.scanned_layer_names[j];
619 }
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600620 return VK_SUCCESS;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -0700621 }
622 } else {
623 loader_platform_close_library(handle);
624 }
625
626 // No GetExtensionSupport or GetExtensionSupport returned invalid extension
627 // for the layer, so test the layer name as if it is an extension name
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600628 // use default layer name based on library name VK_LAYER_LIBRARY_PREFIX<name>.VK_LIBRARY_SUFFIX
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -0700629 char *pEnd;
630 size_t siz;
631
632 search_name = basename(search_name);
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600633 search_name += strlen(VK_LAYER_LIBRARY_PREFIX);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -0700634 pEnd = strrchr(search_name, '.');
635 siz = (int) (pEnd - search_name);
636 if (siz != strlen(pExtName))
637 continue;
638
639 if (strncmp(search_name, pExtName, siz) == 0) {
640 if (lib_name) {
641 *lib_name = loader.scanned_layer_names[j];
642 }
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600643 return VK_SUCCESS;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -0700644 }
645 }
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600646 return VK_ERROR_INVALID_EXTENSION;
Jon Ashburnb8358052014-11-18 09:06:04 -0700647}
648
Mark Lobodzinski17caf572015-01-29 08:55:56 -0600649static uint32_t loader_get_layer_env(struct loader_icd *icd, uint32_t gpu_index, struct layer_name_pair *pLayerNames)
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600650{
Ian Elliott4470a302015-02-17 10:33:47 -0700651 char *layerEnv;
Mark Lobodzinski17caf572015-01-29 08:55:56 -0600652 uint32_t len, count = 0;
Jon Ashburnd09bd102014-10-22 21:15:26 -0600653 char *p, *pOrig, *next, *name;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600654
Ian Elliott4470a302015-02-17 10:33:47 -0700655#if defined(WIN32)
656 layerEnv = loader_get_registry_and_env(LAYER_NAMES_ENV,
657 LAYER_NAMES_REGISTRY_VALUE);
658#else // WIN32
659 layerEnv = getenv(LAYER_NAMES_ENV);
660#endif // WIN32
661 if (layerEnv == NULL) {
Jon Ashburn3fb55442014-10-23 10:29:09 -0600662 return 0;
Ian Elliott4470a302015-02-17 10:33:47 -0700663 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600664 p = malloc(strlen(layerEnv) + 1);
Ian Elliott4470a302015-02-17 10:33:47 -0700665 if (p == NULL) {
666#if defined(WIN32)
667 free(layerEnv);
668#endif // WIN32
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600669 return 0;
Ian Elliott4470a302015-02-17 10:33:47 -0700670 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600671 strcpy(p, layerEnv);
Ian Elliott4470a302015-02-17 10:33:47 -0700672#if defined(WIN32)
673 free(layerEnv);
674#endif // WIN32
Jon Ashburnd09bd102014-10-22 21:15:26 -0600675 pOrig = p;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600676
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600677 while (p && *p && count < MAX_LAYER_LIBRARIES) {
Jon Ashburnb8358052014-11-18 09:06:04 -0700678 const char *lib_name = NULL;
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700679 next = strchr(p, PATH_SEPERATOR);
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600680 if (next == NULL) {
Ian Elliott19628802015-02-04 12:06:46 -0700681 len = (uint32_t) strlen(p);
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600682 next = p + len;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -0700683 } else {
Ian Elliott19628802015-02-04 12:06:46 -0700684 len = (uint32_t) (next - p);
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600685 *(char *) next = '\0';
686 next++;
687 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600688 name = basename(p);
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600689 if (find_layer_extension(icd, gpu_index, name, &lib_name) != VK_SUCCESS) {
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600690 p = next;
691 continue;
692 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600693
Ian Elliott19628802015-02-04 12:06:46 -0700694 len = (uint32_t) strlen(name);
Jon Ashburnb8358052014-11-18 09:06:04 -0700695 pLayerNames[count].layer_name = malloc(len + 1);
696 if (!pLayerNames[count].layer_name) {
Jon Ashburnd09bd102014-10-22 21:15:26 -0600697 free(pOrig);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600698 return count;
Jon Ashburnd09bd102014-10-22 21:15:26 -0600699 }
Jon Ashburnb8358052014-11-18 09:06:04 -0700700 strncpy((char *) pLayerNames[count].layer_name, name, len);
701 pLayerNames[count].layer_name[len] = '\0';
702 pLayerNames[count].lib_name = lib_name;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600703 count++;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600704 p = next;
705
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -0700706 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600707
Jon Ashburnd09bd102014-10-22 21:15:26 -0600708 free(pOrig);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600709 return count;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600710}
711
Jon Ashburnbacb0f52015-04-06 10:58:22 -0600712static uint32_t loader_get_layer_libs(struct loader_icd *icd, uint32_t gpu_index, uint32_t ext_count, const char *const* ext_names, struct layer_name_pair **ppLayerNames)
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600713{
Jon Ashburnb8358052014-11-18 09:06:04 -0700714 static struct layer_name_pair layerNames[MAX_LAYER_LIBRARIES];
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -0700715 const char *lib_name = NULL;
716 uint32_t count = 0;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600717
718 *ppLayerNames = &layerNames[0];
Courtney Goeltzenleuchter89ba9282015-02-17 14:21:21 -0700719 /* Load any layers specified in the environment first */
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -0700720 count = loader_get_layer_env(icd, gpu_index, layerNames);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600721
Jon Ashburnbacb0f52015-04-06 10:58:22 -0600722 for (uint32_t i = 0; i < ext_count; i++) {
723 const char *pExtName = ext_names[i];
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600724
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600725 if (find_layer_extension(icd, gpu_index, pExtName, &lib_name) == VK_SUCCESS) {
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -0700726 uint32_t len;
727
728 /*
729 * the library name is NULL if the driver supports this
730 * extension and thus no layer to load.
731 */
732 if (lib_name == NULL)
733 continue;
734
735 len = (uint32_t) strlen(pExtName);
736 for (uint32_t j = 0; j < count; j++) {
737 if (len == strlen(layerNames[j].layer_name) &&
738 strncmp(pExtName, layerNames[j].layer_name, len) == 0) {
739 // Extension / Layer already on the list
740 continue;
Jon Ashburnc0e86012015-02-18 11:29:58 -0700741 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600742 }
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -0700743
744 layerNames[count].layer_name = malloc(len + 1);
745 if (!layerNames[count].layer_name)
746 return count;
747 strncpy((char *) layerNames[count].layer_name, pExtName, len);
748 layerNames[count].layer_name[len] = '\0';
749 layerNames[count].lib_name = lib_name;
750 count++;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600751 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600752 }
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -0700753
754 return count;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600755}
756
Jon Ashburn46d1f582015-01-28 11:01:35 -0700757static void loader_deactivate_layer(const struct loader_instance *instance)
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600758{
759 struct loader_icd *icd;
760 struct loader_layers *libs;
761
Jon Ashburn46d1f582015-01-28 11:01:35 -0700762 for (icd = instance->icds; icd; icd = icd->next) {
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600763 if (icd->gpus)
764 free(icd->gpus);
765 icd->gpus = NULL;
766 if (icd->loader_dispatch)
767 free(icd->loader_dispatch);
768 icd->loader_dispatch = NULL;
Mark Lobodzinski17caf572015-01-29 08:55:56 -0600769 for (uint32_t j = 0; j < icd->gpu_count; j++) {
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600770 if (icd->layer_count[j] > 0) {
Mark Lobodzinski17caf572015-01-29 08:55:56 -0600771 for (uint32_t i = 0; i < icd->layer_count[j]; i++) {
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600772 libs = &(icd->layer_libs[j][i]);
773 if (libs->lib_handle)
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700774 loader_platform_close_library(libs->lib_handle);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600775 libs->lib_handle = NULL;
776 }
Jon Ashburnd09bd102014-10-22 21:15:26 -0600777 if (icd->wrappedGpus[j])
778 free(icd->wrappedGpus[j]);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600779 }
780 icd->layer_count[j] = 0;
781 }
782 icd->gpu_count = 0;
783 }
784}
785
Jon Ashburnbacb0f52015-04-06 10:58:22 -0600786extern uint32_t loader_activate_layers(struct loader_icd *icd, uint32_t gpu_index, uint32_t ext_count, const char *const* ext_names)
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600787{
Mark Lobodzinski17caf572015-01-29 08:55:56 -0600788 uint32_t count;
Jon Ashburnbacb0f52015-04-06 10:58:22 -0600789 VkBaseLayerObject *gpu;
Jon Ashburnb8358052014-11-18 09:06:04 -0700790 struct layer_name_pair *pLayerNames;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600791 if (!icd)
792 return 0;
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600793 assert(gpu_index < VK_MAX_PHYSICAL_GPUS);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600794
Jon Ashburnbacb0f52015-04-06 10:58:22 -0600795 gpu = icd->gpus + gpu_index;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600796 /* activate any layer libraries */
797 if (!loader_layers_activated(icd, gpu_index)) {
Jon Ashburnbacb0f52015-04-06 10:58:22 -0600798 VkBaseLayerObject *gpuObj = gpu;
799 VkBaseLayerObject *nextGpuObj, *baseObj = gpuObj->baseObject;
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600800 PFN_vkGetProcAddr nextGPA = vkGetProcAddr;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600801
Jon Ashburnbacb0f52015-04-06 10:58:22 -0600802 count = loader_get_layer_libs(icd, gpu_index, ext_count, ext_names, &pLayerNames);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600803 if (!count)
804 return 0;
Jon Ashburnb8358052014-11-18 09:06:04 -0700805 loader_init_layer_libs(icd, gpu_index, pLayerNames, count);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600806
Jon Ashburnbacb0f52015-04-06 10:58:22 -0600807 icd->wrappedGpus[gpu_index] = malloc(sizeof(VkBaseLayerObject) * icd->layer_count[gpu_index]);
Jon Ashburnd09bd102014-10-22 21:15:26 -0600808 if (! icd->wrappedGpus[gpu_index])
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600809 loader_log(VK_DBG_MSG_ERROR, 0, "Failed to malloc Gpu objects for layer");
Mark Lobodzinski17caf572015-01-29 08:55:56 -0600810 for (int32_t i = icd->layer_count[gpu_index] - 1; i >= 0; i--) {
Jon Ashburnd09bd102014-10-22 21:15:26 -0600811 nextGpuObj = (icd->wrappedGpus[gpu_index] + i);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600812 nextGpuObj->pGPA = nextGPA;
Jon Ashburnf2610012014-10-24 15:48:55 -0600813 nextGpuObj->baseObject = baseObj;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600814 nextGpuObj->nextObject = gpuObj;
815 gpuObj = nextGpuObj;
816
Jon Ashburn79113cc2014-12-01 14:22:40 -0700817 char funcStr[256];
818 snprintf(funcStr, 256, "%sGetProcAddr",icd->layer_libs[gpu_index][i].name);
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600819 if ((nextGPA = (PFN_vkGetProcAddr) loader_platform_get_proc_address(icd->layer_libs[gpu_index][i].lib_handle, funcStr)) == NULL)
820 nextGPA = (PFN_vkGetProcAddr) loader_platform_get_proc_address(icd->layer_libs[gpu_index][i].lib_handle, "vkGetProcAddr");
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600821 if (!nextGPA) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600822 loader_log(VK_DBG_MSG_ERROR, 0, "Failed to find vkGetProcAddr in layer %s", icd->layer_libs[gpu_index][i].name);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600823 continue;
824 }
825
Jon Ashburnf2610012014-10-24 15:48:55 -0600826 if (i == 0) {
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600827 loader_init_dispatch_table(icd->loader_dispatch + gpu_index, nextGPA, gpuObj);
Jon Ashburnf2610012014-10-24 15:48:55 -0600828 //Insert the new wrapped objects into the list with loader object at head
Jon Ashburnbacb0f52015-04-06 10:58:22 -0600829 gpu->nextObject = gpuObj;
830 gpu->pGPA = nextGPA;
Jon Ashburnf2610012014-10-24 15:48:55 -0600831 gpuObj = icd->wrappedGpus[gpu_index] + icd->layer_count[gpu_index] - 1;
832 gpuObj->nextObject = baseObj;
Jon Ashburn46d1f582015-01-28 11:01:35 -0700833 gpuObj->pGPA = icd->scanned_icds->GetProcAddr;
Jon Ashburnf2610012014-10-24 15:48:55 -0600834 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600835
836 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600837 }
838 else {
839 //make sure requested Layers matches currently activated Layers
Jon Ashburnbacb0f52015-04-06 10:58:22 -0600840 count = loader_get_layer_libs(icd, gpu_index, ext_count, ext_names, &pLayerNames);
Mark Lobodzinski17caf572015-01-29 08:55:56 -0600841 for (uint32_t i = 0; i < count; i++) {
Jon Ashburnb8358052014-11-18 09:06:04 -0700842 if (strcmp(icd->layer_libs[gpu_index][i].name, pLayerNames[i].layer_name)) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600843 loader_log(VK_DBG_MSG_ERROR, 0, "Layers activated != Layers requested");
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600844 break;
845 }
846 }
847 if (count != icd->layer_count[gpu_index]) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600848 loader_log(VK_DBG_MSG_ERROR, 0, "Number of Layers activated != number requested");
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600849 }
850 }
851 return icd->layer_count[gpu_index];
852}
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600853
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600854LOADER_EXPORT VkResult VKAPI vkCreateInstance(
Courtney Goeltzenleuchter95487bc2015-04-14 18:48:46 -0600855 const VkInstanceCreateInfo* pCreateInfo,
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600856 VkInstance* pInstance)
Jon Ashburn1beab2d2015-01-26 14:51:40 -0700857{
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700858 static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_icd);
859 static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_layer);
Jon Ashburn1beab2d2015-01-26 14:51:40 -0700860 struct loader_instance *ptr_instance = NULL;
Jon Ashburn46888392015-01-29 15:45:51 -0700861 struct loader_scanned_icds *scanned_icds;
862 struct loader_icd *icd;
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600863 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
Jon Ashburn340d6662015-04-08 15:49:00 -0600864 uint32_t i;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600865
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700866 /* Scan/discover all ICD libraries in a single-threaded manner */
867 loader_platform_thread_once(&once_icd, loader_icd_scan);
Jon Ashburn46888392015-01-29 15:45:51 -0700868
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700869 /* get layer libraries in a single-threaded manner */
870 loader_platform_thread_once(&once_layer, layer_lib_scan);
Jon Ashburn46888392015-01-29 15:45:51 -0700871
Jon Ashburn1beab2d2015-01-26 14:51:40 -0700872 ptr_instance = (struct loader_instance*) malloc(sizeof(struct loader_instance));
873 if (ptr_instance == NULL) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600874 return VK_ERROR_OUT_OF_MEMORY;
Jon Ashburn1beab2d2015-01-26 14:51:40 -0700875 }
876 memset(ptr_instance, 0, sizeof(struct loader_instance));
Jon Ashburn340d6662015-04-08 15:49:00 -0600877 ptr_instance->extension_count = pCreateInfo->extensionCount;
878 ptr_instance->extension_names = (ptr_instance->extension_count > 0) ?
879 malloc(sizeof (char *) * ptr_instance->extension_count) : NULL;
880 for (i = 0; i < ptr_instance->extension_count; i++) {
881 ptr_instance->extension_names[i] = malloc(strlen(pCreateInfo->ppEnabledExtensionNames[i] + 1));
882 if (ptr_instance->extension_names[i] == NULL)
883 return VK_ERROR_OUT_OF_MEMORY;
884 strcpy(ptr_instance->extension_names[i], pCreateInfo->ppEnabledExtensionNames[i]);
885 }
Jon Ashburn1beab2d2015-01-26 14:51:40 -0700886 ptr_instance->next = loader.instances;
887 loader.instances = ptr_instance;
888
Jon Ashburn46888392015-01-29 15:45:51 -0700889 scanned_icds = loader.scanned_icd_list;
890 while (scanned_icds) {
891 icd = loader_icd_add(ptr_instance, scanned_icds);
892 if (icd) {
Jon Ashburnb317fad2015-04-04 14:52:07 -0600893 res = scanned_icds->CreateInstance(pCreateInfo,
Jon Ashburn46888392015-01-29 15:45:51 -0700894 &(scanned_icds->instance));
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600895 if (res != VK_SUCCESS)
Jon Ashburn46888392015-01-29 15:45:51 -0700896 {
897 ptr_instance->icds = ptr_instance->icds->next;
898 loader_icd_destroy(icd);
899 scanned_icds->instance = NULL;
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600900 loader_log(VK_DBG_MSG_WARNING, 0,
Jon Ashburn46888392015-01-29 15:45:51 -0700901 "ICD ignored: failed to CreateInstance on device");
902 }
903 }
904 scanned_icds = scanned_icds->next;
905 }
Jon Ashburn1beab2d2015-01-26 14:51:40 -0700906
Ian Elliotteb450762015-02-05 15:19:15 -0700907 if (ptr_instance->icds == NULL) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600908 return VK_ERROR_INCOMPATIBLE_DRIVER;
Ian Elliotteb450762015-02-05 15:19:15 -0700909 }
Jon Ashburn46888392015-01-29 15:45:51 -0700910
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600911 *pInstance = (VkInstance) ptr_instance;
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600912 return VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -0700913}
914
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600915LOADER_EXPORT VkResult VKAPI vkDestroyInstance(
916 VkInstance instance)
Jon Ashburn1beab2d2015-01-26 14:51:40 -0700917{
918 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
Jon Ashburn46888392015-01-29 15:45:51 -0700919 struct loader_scanned_icds *scanned_icds;
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600920 VkResult res;
Jon Ashburn340d6662015-04-08 15:49:00 -0600921 uint32_t i;
Jon Ashburn1beab2d2015-01-26 14:51:40 -0700922
923 // Remove this instance from the list of instances:
924 struct loader_instance *prev = NULL;
925 struct loader_instance *next = loader.instances;
926 while (next != NULL) {
927 if (next == ptr_instance) {
928 // Remove this instance from the list:
Jon Ashburn340d6662015-04-08 15:49:00 -0600929 for (i = 0; i < ptr_instance->extension_count; i++) {
930 free(ptr_instance->extension_names[i]);
931 }
Jon Ashburn1beab2d2015-01-26 14:51:40 -0700932 if (prev)
933 prev->next = next->next;
Jon Ashburnc5c49602015-02-03 09:26:59 -0700934 else
935 loader.instances = next->next;
Jon Ashburn1beab2d2015-01-26 14:51:40 -0700936 break;
937 }
938 prev = next;
939 next = next->next;
940 }
941 if (next == NULL) {
942 // This must be an invalid instance handle or empty list
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600943 return VK_ERROR_INVALID_HANDLE;
Jon Ashburn1beab2d2015-01-26 14:51:40 -0700944 }
945
Jon Ashburn46888392015-01-29 15:45:51 -0700946 // cleanup any prior layer initializations
947 loader_deactivate_layer(ptr_instance);
Jon Ashburn1beab2d2015-01-26 14:51:40 -0700948
Jon Ashburn46888392015-01-29 15:45:51 -0700949 scanned_icds = loader.scanned_icd_list;
950 while (scanned_icds) {
951 if (scanned_icds->instance)
952 res = scanned_icds->DestroyInstance(scanned_icds->instance);
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600953 if (res != VK_SUCCESS)
954 loader_log(VK_DBG_MSG_WARNING, 0,
Jon Ashburn46888392015-01-29 15:45:51 -0700955 "ICD ignored: failed to DestroyInstance on device");
956 scanned_icds->instance = NULL;
957 scanned_icds = scanned_icds->next;
958 }
959
Jon Ashburn1beab2d2015-01-26 14:51:40 -0700960 free(ptr_instance);
961
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600962 return VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -0700963}
964
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600965LOADER_EXPORT VkResult VKAPI vkEnumerateGpus(
Jon Ashburn1beab2d2015-01-26 14:51:40 -0700966
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600967 VkInstance instance,
Jon Ashburn1beab2d2015-01-26 14:51:40 -0700968 uint32_t maxGpus,
969 uint32_t* pGpuCount,
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600970 VkPhysicalGpu* pGpus)
Jon Ashburn1beab2d2015-01-26 14:51:40 -0700971{
Jon Ashburn4c392fb2015-01-28 19:57:09 -0700972 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
973 struct loader_icd *icd;
Jon Ashburn8d66a052015-01-29 15:47:01 -0700974 uint32_t count = 0;
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600975 VkResult res;
Jon Ashburn4c392fb2015-01-28 19:57:09 -0700976
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600977 //in spirit of VK don't error check on the instance parameter
Jon Ashburn4c392fb2015-01-28 19:57:09 -0700978 icd = ptr_instance->icds;
979 while (icd) {
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600980 VkPhysicalGpu gpus[VK_MAX_PHYSICAL_GPUS];
Jon Ashburnbacb0f52015-04-06 10:58:22 -0600981 VkBaseLayerObject * wrapped_gpus;
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600982 PFN_vkGetProcAddr get_proc_addr = icd->scanned_icds->GetProcAddr;
Jon Ashburn8d66a052015-01-29 15:47:01 -0700983 uint32_t n, max = maxGpus - count;
Jon Ashburn4c392fb2015-01-28 19:57:09 -0700984
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600985 if (max > VK_MAX_PHYSICAL_GPUS) {
986 max = VK_MAX_PHYSICAL_GPUS;
Jon Ashburn4c392fb2015-01-28 19:57:09 -0700987 }
988
Jon Ashburn46888392015-01-29 15:45:51 -0700989 res = icd->scanned_icds->EnumerateGpus(icd->scanned_icds->instance,
990 max, &n,
Jon Ashburn4c392fb2015-01-28 19:57:09 -0700991 gpus);
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600992 if (res == VK_SUCCESS && n) {
Jon Ashburnbacb0f52015-04-06 10:58:22 -0600993 wrapped_gpus = (VkBaseLayerObject*) malloc(n *
994 sizeof(VkBaseLayerObject));
Jon Ashburn4c392fb2015-01-28 19:57:09 -0700995 icd->gpus = wrapped_gpus;
996 icd->gpu_count = n;
Jon Ashburnbacb0f52015-04-06 10:58:22 -0600997 icd->loader_dispatch = (VkLayerDispatchTable *) malloc(n *
998 sizeof(VkLayerDispatchTable));
Ian Elliott19628802015-02-04 12:06:46 -0700999 for (unsigned int i = 0; i < n; i++) {
Jon Ashburn4c392fb2015-01-28 19:57:09 -07001000 (wrapped_gpus + i)->baseObject = gpus[i];
1001 (wrapped_gpus + i)->pGPA = get_proc_addr;
1002 (wrapped_gpus + i)->nextObject = gpus[i];
1003 memcpy(pGpus + count, &wrapped_gpus, sizeof(*pGpus));
1004 loader_init_dispatch_table(icd->loader_dispatch + i,
1005 get_proc_addr, gpus[i]);
Courtney Goeltzenleuchter64ca9232015-02-10 18:40:14 -07001006
1007 /* Verify ICD compatibility */
1008 if (!valid_loader_magic_value(gpus[i])) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001009 loader_log(VK_DBG_MSG_WARNING, 0,
Courtney Goeltzenleuchter64ca9232015-02-10 18:40:14 -07001010 "Loader: Incompatible ICD, first dword must be initialized to ICD_LOADER_MAGIC. See loader/README.md for details.\n");
1011 assert(0);
1012 }
1013
Jon Ashburnbacb0f52015-04-06 10:58:22 -06001014 const VkLayerDispatchTable **disp;
1015 disp = (const VkLayerDispatchTable **) gpus[i];
Jon Ashburn4c392fb2015-01-28 19:57:09 -07001016 *disp = icd->loader_dispatch + i;
Jon Ashburnecceaad2015-04-08 18:20:54 -06001017 loader_activate_layers(icd, i, ptr_instance->extension_count,
1018 (const char *const*) ptr_instance->extension_names);
Jon Ashburn4c392fb2015-01-28 19:57:09 -07001019 }
1020
Jon Ashburn4c392fb2015-01-28 19:57:09 -07001021 count += n;
1022
1023 if (count >= maxGpus) {
1024 break;
1025 }
1026 }
1027
1028 icd = icd->next;
1029 }
1030
Jon Ashburn4c392fb2015-01-28 19:57:09 -07001031 *pGpuCount = count;
1032
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001033 return (count > 0) ? VK_SUCCESS : res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001034}
1035
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06001036LOADER_EXPORT void * VKAPI vkGetProcAddr(VkPhysicalGpu gpu, const char * pName)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001037{
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001038 if (gpu == NULL) {
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001039 return NULL;
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001040 }
Jon Ashburnbacb0f52015-04-06 10:58:22 -06001041 VkBaseLayerObject* gpuw = (VkBaseLayerObject *) gpu;
1042 VkLayerDispatchTable * disp_table = * (VkLayerDispatchTable **) gpuw->baseObject;
Chia-I Wuf46b81a2015-01-04 11:12:47 +08001043 void *addr;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001044
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001045 if (disp_table == NULL)
1046 return NULL;
1047
Chia-I Wuf46b81a2015-01-04 11:12:47 +08001048 addr = loader_lookup_dispatch_table(disp_table, pName);
1049 if (addr)
1050 return addr;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001051 else {
Jon Ashburnf2610012014-10-24 15:48:55 -06001052 if (disp_table->GetProcAddr == NULL)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001053 return NULL;
Jon Ashburnf2610012014-10-24 15:48:55 -06001054 return disp_table->GetProcAddr(gpuw->nextObject, pName);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001055 }
1056}
1057
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06001058LOADER_EXPORT VkResult VKAPI vkGetExtensionSupport(VkPhysicalGpu gpu, const char *pExtName)
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001059{
1060 uint32_t gpu_index;
Jon Ashburnbacb0f52015-04-06 10:58:22 -06001061 struct loader_icd *icd = loader_get_icd((const VkBaseLayerObject *) gpu, &gpu_index);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001062
1063 if (!icd)
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001064 return VK_ERROR_UNAVAILABLE;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001065
1066 return find_layer_extension(icd, gpu_index, pExtName, NULL);
1067}
1068
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06001069LOADER_EXPORT VkResult VKAPI vkEnumerateLayers(VkPhysicalGpu gpu, size_t maxLayerCount, size_t maxStringSize, size_t* pOutLayerCount, char* const* pOutLayers, void* pReserved)
Jon Ashburnf7bcf9b2014-10-15 15:30:23 -06001070{
Mark Lobodzinski17caf572015-01-29 08:55:56 -06001071 uint32_t gpu_index;
Ian Elliott19628802015-02-04 12:06:46 -07001072 size_t count = 0;
Jon Ashburn1323eb72014-12-02 13:03:09 -07001073 char *lib_name;
Jon Ashburnbacb0f52015-04-06 10:58:22 -06001074 struct loader_icd *icd = loader_get_icd((const VkBaseLayerObject *) gpu, &gpu_index);
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001075 loader_platform_dl_handle handle;
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06001076 PFN_vkEnumerateLayers fpEnumerateLayers;
Mark Lobodzinski17caf572015-01-29 08:55:56 -06001077 char layer_buf[16][256];
1078 char * layers[16];
Jon Ashburnf7bcf9b2014-10-15 15:30:23 -06001079
Jon Ashburn1323eb72014-12-02 13:03:09 -07001080 if (pOutLayerCount == NULL || pOutLayers == NULL)
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001081 return VK_ERROR_INVALID_POINTER;
Jon Ashburnf7bcf9b2014-10-15 15:30:23 -06001082
Jon Ashburn46d1f582015-01-28 11:01:35 -07001083 if (!icd)
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001084 return VK_ERROR_UNAVAILABLE;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001085
Jon Ashburn1323eb72014-12-02 13:03:09 -07001086 for (int i = 0; i < 16; i++)
1087 layers[i] = &layer_buf[i][0];
1088
1089 for (unsigned int j = 0; j < loader.scanned_layer_count && count < maxLayerCount; j++) {
1090 lib_name = loader.scanned_layer_names[j];
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001091 // Used to call: dlopen(*lib_name, RTLD_LAZY)
1092 if ((handle = loader_platform_open_library(lib_name)) == NULL)
Jon Ashburn1323eb72014-12-02 13:03:09 -07001093 continue;
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001094 if ((fpEnumerateLayers = loader_platform_get_proc_address(handle, "vkEnumerateLayers")) == NULL) {
1095 //use default layer name based on library name VK_LAYER_LIBRARY_PREFIX<name>.VK_LIBRARY_SUFFIX
Jon Ashburn1323eb72014-12-02 13:03:09 -07001096 char *pEnd, *cpyStr;
Ian Elliott42045842015-02-13 14:29:21 -07001097 size_t siz;
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001098 loader_platform_close_library(handle);
Jon Ashburn1323eb72014-12-02 13:03:09 -07001099 lib_name = basename(lib_name);
1100 pEnd = strrchr(lib_name, '.');
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001101 siz = (int) (pEnd - lib_name - strlen(VK_LAYER_LIBRARY_PREFIX) + 1);
Jon Ashburn1323eb72014-12-02 13:03:09 -07001102 if (pEnd == NULL || siz <= 0)
1103 continue;
1104 cpyStr = malloc(siz);
1105 if (cpyStr == NULL) {
1106 free(cpyStr);
1107 continue;
1108 }
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001109 strncpy(cpyStr, lib_name + strlen(VK_LAYER_LIBRARY_PREFIX), siz);
Jon Ashburn1323eb72014-12-02 13:03:09 -07001110 cpyStr[siz - 1] = '\0';
1111 if (siz > maxStringSize)
Ian Elliott19628802015-02-04 12:06:46 -07001112 siz = (int) maxStringSize;
Jon Ashburn1323eb72014-12-02 13:03:09 -07001113 strncpy((char *) (pOutLayers[count]), cpyStr, siz);
1114 pOutLayers[count][siz - 1] = '\0';
1115 count++;
1116 free(cpyStr);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001117 } else {
Mark Lobodzinski17caf572015-01-29 08:55:56 -06001118 size_t cnt;
1119 uint32_t n;
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06001120 VkResult res;
Ian Elliott19628802015-02-04 12:06:46 -07001121 n = (uint32_t) ((maxStringSize < 256) ? maxStringSize : 256);
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001122 res = fpEnumerateLayers(NULL, 16, n, &cnt, layers, (char *) icd->gpus + gpu_index);
1123 loader_platform_close_library(handle);
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001124 if (res != VK_SUCCESS)
Jon Ashburn1323eb72014-12-02 13:03:09 -07001125 continue;
1126 if (cnt + count > maxLayerCount)
1127 cnt = maxLayerCount - count;
Ian Elliott19628802015-02-04 12:06:46 -07001128 for (uint32_t i = (uint32_t) count; i < cnt + count; i++) {
Jon Ashburn1323eb72014-12-02 13:03:09 -07001129 strncpy((char *) (pOutLayers[i]), (char *) layers[i - count], n);
1130 if (n > 0)
1131 pOutLayers[i - count][n - 1] = '\0';
1132 }
1133 count += cnt;
1134 }
1135 }
1136
Jon Ashburnf7bcf9b2014-10-15 15:30:23 -06001137 *pOutLayerCount = count;
1138
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001139 return VK_SUCCESS;
Jon Ashburnf7bcf9b2014-10-15 15:30:23 -06001140}
1141
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06001142LOADER_EXPORT VkResult VKAPI vkDbgRegisterMsgCallback(VkInstance instance, VK_DBG_MSG_CALLBACK_FUNCTION pfnMsgCallback, void* pUserData)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001143{
Jon Ashburn01e2d662014-11-14 09:52:42 -07001144 const struct loader_icd *icd;
Jon Ashburn98bd4542015-01-29 16:44:24 -07001145 struct loader_instance *inst;
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06001146 VkResult res;
Mark Lobodzinski17caf572015-01-29 08:55:56 -06001147 uint32_t gpu_idx;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001148
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001149 if (instance == VK_NULL_HANDLE)
1150 return VK_ERROR_INVALID_HANDLE;
Courtney Goeltzenleuchterc80a5572015-04-13 14:10:06 -06001151
1152 assert(loader.icds_scanned);
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001153
Jon Ashburn98bd4542015-01-29 16:44:24 -07001154 for (inst = loader.instances; inst; inst = inst->next) {
Jon Ashburnbb510252015-03-17 13:47:55 -06001155 if (inst == instance)
1156 break;
1157 }
1158
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001159 if (inst == VK_NULL_HANDLE)
1160 return VK_ERROR_INVALID_HANDLE;
Jon Ashburnbb510252015-03-17 13:47:55 -06001161
1162 for (icd = inst->icds; icd; icd = icd->next) {
1163 for (uint32_t i = 0; i < icd->gpu_count; i++) {
1164 res = (icd->loader_dispatch + i)->DbgRegisterMsgCallback(icd->scanned_icds->instance,
Jon Ashburn98bd4542015-01-29 16:44:24 -07001165 pfnMsgCallback, pUserData);
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001166 if (res != VK_SUCCESS) {
Jon Ashburnbb510252015-03-17 13:47:55 -06001167 gpu_idx = i;
Jon Ashburn98bd4542015-01-29 16:44:24 -07001168 break;
Jon Ashburnbb510252015-03-17 13:47:55 -06001169 }
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001170 }
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001171 if (res != VK_SUCCESS)
Jon Ashburn01e2d662014-11-14 09:52:42 -07001172 break;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001173 }
1174
Jon Ashburnbb510252015-03-17 13:47:55 -06001175
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001176 /* roll back on errors */
1177 if (icd) {
Jon Ashburnbb510252015-03-17 13:47:55 -06001178 for (const struct loader_icd *tmp = inst->icds; tmp != icd;
Jon Ashburn98bd4542015-01-29 16:44:24 -07001179 tmp = tmp->next) {
Jon Ashburnbb510252015-03-17 13:47:55 -06001180 for (uint32_t i = 0; i < icd->gpu_count; i++)
1181 (tmp->loader_dispatch + i)->DbgUnregisterMsgCallback(tmp->scanned_icds->instance, pfnMsgCallback);
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001182 }
Jon Ashburn01e2d662014-11-14 09:52:42 -07001183 /* and gpus on current icd */
Mark Lobodzinski17caf572015-01-29 08:55:56 -06001184 for (uint32_t i = 0; i < gpu_idx; i++)
Courtney Goeltzenleuchterc80a5572015-04-13 14:10:06 -06001185 (icd->loader_dispatch + i)->DbgUnregisterMsgCallback(icd->scanned_icds->instance, pfnMsgCallback);
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001186
1187 return res;
1188 }
1189
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001190 return VK_SUCCESS;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001191}
1192
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06001193LOADER_EXPORT VkResult VKAPI vkDbgUnregisterMsgCallback(VkInstance instance, VK_DBG_MSG_CALLBACK_FUNCTION pfnMsgCallback)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001194{
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06001195 VkResult res = VK_SUCCESS;
Jon Ashburnbb510252015-03-17 13:47:55 -06001196 struct loader_instance *inst;
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001197 if (instance == VK_NULL_HANDLE)
1198 return VK_ERROR_INVALID_HANDLE;
Courtney Goeltzenleuchterc80a5572015-04-13 14:10:06 -06001199
1200 assert(loader.icds_scanned);
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001201
Jon Ashburnbb510252015-03-17 13:47:55 -06001202 for (inst = loader.instances; inst; inst = inst->next) {
1203 if (inst == instance)
1204 break;
1205 }
1206
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001207 if (inst == VK_NULL_HANDLE)
1208 return VK_ERROR_INVALID_HANDLE;
Jon Ashburnbb510252015-03-17 13:47:55 -06001209
1210 for (const struct loader_icd * icd = inst->icds; icd; icd = icd->next) {
1211 for (uint32_t i = 0; i < icd->gpu_count; i++) {
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06001212 VkResult r;
Jon Ashburnbb510252015-03-17 13:47:55 -06001213 r = (icd->loader_dispatch + i)->DbgUnregisterMsgCallback(icd->scanned_icds->instance, pfnMsgCallback);
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001214 if (r != VK_SUCCESS) {
Jon Ashburnbb510252015-03-17 13:47:55 -06001215 res = r;
Jon Ashburn01e2d662014-11-14 09:52:42 -07001216 }
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001217 }
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001218 }
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001219 return res;
1220}
1221
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06001222LOADER_EXPORT VkResult VKAPI vkDbgSetGlobalOption(VkInstance instance, VK_DBG_GLOBAL_OPTION dbgOption, size_t dataSize, const void* pData)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001223{
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06001224 VkResult res = VK_SUCCESS;
Jon Ashburnbb510252015-03-17 13:47:55 -06001225 struct loader_instance *inst;
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001226 if (instance == VK_NULL_HANDLE)
1227 return VK_ERROR_INVALID_HANDLE;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001228
Courtney Goeltzenleuchterc80a5572015-04-13 14:10:06 -06001229 assert(loader.icds_scanned);
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001230
Jon Ashburnbb510252015-03-17 13:47:55 -06001231 for (inst = loader.instances; inst; inst = inst->next) {
1232 if (inst == instance)
1233 break;
1234 }
1235
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001236 if (inst == VK_NULL_HANDLE)
1237 return VK_ERROR_INVALID_HANDLE;
Jon Ashburnbb510252015-03-17 13:47:55 -06001238 for (const struct loader_icd * icd = inst->icds; icd; icd = icd->next) {
1239 for (uint32_t i = 0; i < icd->gpu_count; i++) {
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06001240 VkResult r;
Jon Ashburnbb510252015-03-17 13:47:55 -06001241 r = (icd->loader_dispatch + i)->DbgSetGlobalOption(icd->scanned_icds->instance, dbgOption,
Jon Ashburn98bd4542015-01-29 16:44:24 -07001242 dataSize, pData);
Jon Ashburnbb510252015-03-17 13:47:55 -06001243 /* unfortunately we cannot roll back */
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001244 if (r != VK_SUCCESS) {
Jon Ashburnbb510252015-03-17 13:47:55 -06001245 res = r;
Jon Ashburn01e2d662014-11-14 09:52:42 -07001246 }
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001247 }
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001248 }
1249
1250 return res;
1251}