blob: fad8f24dbcbda1ed7e02da6b7391107b2fdfb333 [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 Wu19300602014-08-04 08:03:57 +080044#include "loader.h"
Jon Ashburn07daee72015-05-21 18:13:33 -060045#include "wsi_lunarg.h"
Jon Ashburn27cd5842015-05-12 17:26:48 -060046#include "gpa_helper.h"
47#include "table_ops.h"
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060048#include "debug_report.h"
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -060049#include "vkIcd.h"
Ian Elliott655cad72015-02-12 17:08:34 -070050// The following is #included again to catch certain OS-specific functions
51// being used:
52#include "loader_platform.h"
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080053
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060054void loader_add_to_ext_list(
55 struct loader_extension_list *ext_list,
56 uint32_t prop_list_count,
57 const struct loader_extension_property *prop_list);
58
Courtney Goeltzenleuchtered488302015-06-01 14:09:34 -060059static loader_platform_dl_handle loader_add_layer_lib(
60 const char *chain_type,
61 struct loader_extension_property *ext_prop);
62
63static void loader_remove_layer_lib(
64 struct loader_instance *inst,
65 struct loader_extension_property *ext_prop);
66
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060067/* TODO: do we need to lock around access to linked lists and such? */
Jon Ashburn27cd5842015-05-12 17:26:48 -060068struct loader_struct loader = {0};
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080069
Jon Ashburn27cd5842015-05-12 17:26:48 -060070VkLayerInstanceDispatchTable instance_disp = {
71 .GetInstanceProcAddr = vkGetInstanceProcAddr,
Jon Ashburn27cd5842015-05-12 17:26:48 -060072 .CreateInstance = loader_CreateInstance,
73 .DestroyInstance = loader_DestroyInstance,
74 .EnumeratePhysicalDevices = loader_EnumeratePhysicalDevices,
Jon Ashburn95a77ba2015-05-15 15:09:35 -060075 .GetPhysicalDeviceInfo = loader_GetPhysicalDeviceInfo,
76 .CreateDevice = loader_CreateDevice,
Jon Ashburneceb13e2015-05-18 15:28:32 -060077 .GetGlobalExtensionInfo = vkGetGlobalExtensionInfo,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -060078 .GetPhysicalDeviceExtensionInfo = vkGetPhysicalDeviceExtensionInfo,
Jon Ashburn95a77ba2015-05-15 15:09:35 -060079 .GetMultiDeviceCompatibility = loader_GetMultiDeviceCompatibility,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060080 .GetDisplayInfoWSI = loader_GetDisplayInfoWSI,
81 .DbgCreateMsgCallback = loader_DbgCreateMsgCallback,
82 .DbgDestroyMsgCallback = loader_DbgDestroyMsgCallback,
Jon Ashburn27cd5842015-05-12 17:26:48 -060083};
84
85LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_icd);
86LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_layer);
87LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_exts);
Ian Elliott2d4ab1e2015-01-13 17:52:38 -070088
Ian Elliott4470a302015-02-17 10:33:47 -070089#if defined(WIN32)
Ian Elliott5aa4ea22015-03-31 15:32:41 -060090char *loader_get_registry_string(const HKEY hive,
91 const LPCTSTR sub_key,
92 const char *value)
93{
94 DWORD access_flags = KEY_QUERY_VALUE;
95 DWORD value_type;
96 HKEY key;
Ian Elliottf851ddf2015-04-28 15:57:32 -060097 VkResult rtn_value;
Ian Elliott5aa4ea22015-03-31 15:32:41 -060098 char *rtn_str = NULL;
Tony Barbour18f71552015-04-22 11:36:22 -060099 DWORD rtn_len = 0;
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600100 size_t allocated_len = 0;
101
102 rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
103 if (rtn_value != ERROR_SUCCESS) {
104 // We didn't find the key. Try the 32-bit hive (where we've seen the
105 // key end up on some people's systems):
106 access_flags |= KEY_WOW64_32KEY;
107 rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
108 if (rtn_value != ERROR_SUCCESS) {
109 // We still couldn't find the key, so give up:
110 return NULL;
111 }
112 }
113
114 rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
Ian Elliottf851ddf2015-04-28 15:57:32 -0600115 (PVOID) rtn_str, (LPDWORD) &rtn_len);
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600116 if (rtn_value == ERROR_SUCCESS) {
117 // If we get to here, we found the key, and need to allocate memory
118 // large enough for rtn_str, and query again:
119 allocated_len = rtn_len + 4;
120 rtn_str = malloc(allocated_len);
121 rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
Ian Elliottf851ddf2015-04-28 15:57:32 -0600122 (PVOID) rtn_str, (LPDWORD) &rtn_len);
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600123 if (rtn_value == ERROR_SUCCESS) {
124 // We added 4 extra bytes to rtn_str, so that we can ensure that
125 // the string is NULL-terminated (albeit, in a brute-force manner):
126 rtn_str[allocated_len-1] = '\0';
127 } else {
128 // This should never occur, but in case it does, clean up:
129 free(rtn_str);
130 rtn_str = NULL;
131 }
132 } // else - shouldn't happen, but if it does, return rtn_str, which is NULL
133
134 // Close the registry key that was opened:
135 RegCloseKey(key);
136
137 return rtn_str;
138}
139
140
Ian Elliott4470a302015-02-17 10:33:47 -0700141// For ICD developers, look in the registry, and look for an environment
142// variable for a path(s) where to find the ICD(s):
143static char *loader_get_registry_and_env(const char *env_var,
144 const char *registry_value)
145{
146 char *env_str = getenv(env_var);
147 size_t env_len = (env_str == NULL) ? 0 : strlen(env_str);
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600148 char *registry_str = NULL;
Tony Barbour18f71552015-04-22 11:36:22 -0600149 size_t registry_len = 0;
Ian Elliott4470a302015-02-17 10:33:47 -0700150 char *rtn_str = NULL;
151 size_t rtn_len;
152
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600153 registry_str = loader_get_registry_string(HKEY_LOCAL_MACHINE,
Ian Elliott06ebd752015-04-09 18:07:15 -0600154 "Software\\Vulkan",
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600155 registry_value);
Ian Elliottf851ddf2015-04-28 15:57:32 -0600156 registry_len = (registry_str) ? (DWORD) strlen(registry_str) : 0;
Ian Elliott4470a302015-02-17 10:33:47 -0700157
158 rtn_len = env_len + registry_len + 1;
159 if (rtn_len <= 2) {
160 // We found neither the desired registry value, nor the environment
161 // variable; return NULL:
162 return NULL;
163 } else {
164 // We found something, and so we need to allocate memory for the string
165 // to return:
166 rtn_str = malloc(rtn_len);
167 }
168
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600169 if (registry_len == 0) {
Ian Elliott4470a302015-02-17 10:33:47 -0700170 // We didn't find the desired registry value, and so we must have found
171 // only the environment variable:
172 _snprintf(rtn_str, rtn_len, "%s", env_str);
173 } else if (env_str != NULL) {
174 // We found both the desired registry value and the environment
175 // variable, so concatenate them both:
176 _snprintf(rtn_str, rtn_len, "%s;%s", registry_str, env_str);
177 } else {
178 // We must have only found the desired registry value:
179 _snprintf(rtn_str, rtn_len, "%s", registry_str);
180 }
181
Ian Elliott2de26bc2015-04-03 13:13:01 -0600182 if (registry_str) {
183 free(registry_str);
184 }
Ian Elliott4470a302015-02-17 10:33:47 -0700185
186 return(rtn_str);
187}
188#endif // WIN32
189
190
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600191static void loader_log(VkFlags msg_type, int32_t msg_code,
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800192 const char *format, ...)
193{
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800194 char msg[256];
195 va_list ap;
196 int ret;
197
198 va_start(ap, format);
199 ret = vsnprintf(msg, sizeof(msg), format, ap);
Ian Elliott42045842015-02-13 14:29:21 -0700200 if ((ret >= (int) sizeof(msg)) || ret < 0) {
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800201 msg[sizeof(msg) - 1] = '\0';
202 }
203 va_end(ap);
204
Jon Ashburnae053e92015-04-24 14:10:50 -0700205#if defined(WIN32)
206 OutputDebugString(msg);
Jon Ashburn1de39402015-05-05 16:20:46 -0600207#endif
Courtney Goeltzenleuchterc80a5572015-04-13 14:10:06 -0600208 fputs(msg, stderr);
209 fputc('\n', stderr);
Jon Ashburn1de39402015-05-05 16:20:46 -0600210
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800211}
212
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600213bool compare_vk_extension_properties(const VkExtensionProperties *op1, const VkExtensionProperties *op2)
214{
215 return memcmp(op1, op2, sizeof(VkExtensionProperties)) == 0 ? true : false;
216}
217
218/*
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600219 * Search the given ext_list for an extension
220 * matching the given vk_ext_prop
221 */
222bool has_vk_extension_property(
223 const VkExtensionProperties *vk_ext_prop,
224 const struct loader_extension_list *ext_list)
225{
226 for (uint32_t i = 0; i < ext_list->count; i++) {
227 if (compare_vk_extension_properties(&ext_list->list[i].info, vk_ext_prop))
228 return true;
229 }
230 return false;
231}
232
233/*
234 * Search the given ext_list for an extension
235 * matching the given vk_ext_prop
236 */
237static struct loader_extension_property *get_extension_property_from_vkext(
238 const VkExtensionProperties *vk_ext_prop,
239 const struct loader_extension_list *ext_list)
240{
241 for (uint32_t i = 0; i < ext_list->count; i++) {
242 if (compare_vk_extension_properties(&ext_list->list[i].info, vk_ext_prop))
243 return &ext_list->list[i];
244 }
245 return NULL;
246}
247
248static void get_global_extensions(
249 const PFN_vkGetGlobalExtensionInfo fp_get,
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600250 const char *get_extension_info_name,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600251 const char *lib_name,
252 const enum extension_origin origin,
253 struct loader_extension_list *ext_list)
254{
255 uint32_t i, count;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600256 size_t siz = sizeof(count);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600257 struct loader_extension_property ext_props;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600258 VkResult res;
259
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600260 res = fp_get(VK_EXTENSION_INFO_TYPE_COUNT, 0, &siz, &count);
261 if (res != VK_SUCCESS) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600262 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extension count from ICD");
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600263 return;
264 }
265 siz = sizeof(VkExtensionProperties);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600266 for (i = 0; i < count; i++) {
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600267 memset(&ext_props, 0, sizeof(ext_props));
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600268 res = fp_get(VK_EXTENSION_INFO_TYPE_PROPERTIES, i, &siz, &ext_props.info);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600269 if (res == VK_SUCCESS) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600270 ext_props.hosted = false;
271 ext_props.origin = origin;
272 ext_props.lib_name = lib_name;
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600273 strncpy(ext_props.get_extension_info_name, get_extension_info_name, MAX_EXTENSION_NAME_SIZE);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600274 loader_add_to_ext_list(ext_list, 1, &ext_props);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600275 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600276 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600277
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600278 return;
279}
280
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600281static void get_physical_device_layer_extensions(
282 struct loader_instance *ptr_instance,
283 VkPhysicalDevice physical_device,
284 const uint32_t layer_index,
285 struct loader_extension_list *ext_list)
286{
287 uint32_t i, count;
288 size_t siz = sizeof(count);
289 VkResult res;
290 loader_platform_dl_handle lib_handle;
291 PFN_vkGetPhysicalDeviceExtensionInfo fp_get;
292 struct loader_extension_property ext_props;
293
294 if (!loader.scanned_layers[layer_index].physical_device_extensions_supported) {
295 return;
296 }
297
298 ext_props.origin = VK_EXTENSION_ORIGIN_LAYER;
299 ext_props.lib_name = loader.scanned_layers[layer_index].lib_name;
Jon Ashburn128f9422015-05-28 19:16:58 -0600300 char funcStr[MAX_EXTENSION_NAME_SIZE+1]; // add one character for 0 termination
301 snprintf(funcStr, MAX_EXTENSION_NAME_SIZE, "%sGetPhysicalDeviceExtensionInfo", ext_props.info.name);
302 funcStr[MAX_EXTENSION_NAME_SIZE] = 0; // make sure string is 0 terminated
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600303 lib_handle = loader_add_layer_lib("device", &ext_props);
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600304
305 /* first try extension specific function, then generic */
306 fp_get = (PFN_vkGetPhysicalDeviceExtensionInfo) loader_platform_get_proc_address(lib_handle, funcStr);
307 if (!fp_get) {
Jon Ashburn128f9422015-05-28 19:16:58 -0600308 sprintf(funcStr, "vkGetPhysicalDeviceExtensionInfo");
309 fp_get = (PFN_vkGetPhysicalDeviceExtensionInfo) loader_platform_get_proc_address(lib_handle, funcStr);
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600310 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600311 if (fp_get) {
312 res = fp_get(physical_device, VK_EXTENSION_INFO_TYPE_COUNT, 0, &siz, &count);
313 if (res == VK_SUCCESS) {
314 siz = sizeof(VkExtensionProperties);
315 for (i = 0; i < count; i++) {
316 memset(&ext_props, 0, sizeof(ext_props));
317 res = fp_get(physical_device, VK_EXTENSION_INFO_TYPE_PROPERTIES, i, &siz, &ext_props.info);
318 if (res == VK_SUCCESS && (ext_props.info.sType == VK_STRUCTURE_TYPE_EXTENSION_PROPERTIES)) {
319 ext_props.hosted = false;
320 ext_props.origin = VK_EXTENSION_ORIGIN_LAYER;
Jon Ashburn128f9422015-05-28 19:16:58 -0600321 strcpy(ext_props.get_extension_info_name, funcStr);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600322 ext_props.lib_name = loader.scanned_layers[layer_index].lib_name;
323 loader_add_to_ext_list(ext_list, 1, &ext_props);
324 }
325 }
326 } else {
327 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting physical device extension info count from Layer %s", ext_props.lib_name);
328 }
329 }
330
331 loader_remove_layer_lib(ptr_instance, &ext_props);
332 return;
333}
334
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600335static bool loader_init_ext_list(struct loader_extension_list *ext_info)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600336{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600337 ext_info->capacity = 32 * sizeof(struct loader_extension_property);
338 ext_info->list = malloc(ext_info->capacity);
339 if (ext_info->list == NULL) {
340 return false;
341 }
342 memset(ext_info->list, 0, ext_info->capacity);
343 ext_info->count = 0;
344 return true;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600345}
346
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -0600347void loader_destroy_ext_list(struct loader_extension_list *ext_info)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600348{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600349 free(ext_info->list);
350 ext_info->count = 0;
351 ext_info->capacity = 0;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600352}
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600353
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600354static void loader_add_vk_ext_to_ext_list(
355 struct loader_extension_list *ext_list,
356 uint32_t prop_list_count,
357 const VkExtensionProperties *props,
358 const struct loader_extension_list *search_list)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600359{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600360 struct loader_extension_property *ext_prop;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600361
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600362 for (uint32_t i = 0; i < prop_list_count; i++) {
363 // look for duplicates
364 if (has_vk_extension_property(&props[i], ext_list)) {
365 continue;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600366 }
367
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600368 ext_prop = get_extension_property_from_vkext(&props[i], search_list);
369 if (!ext_prop) {
370 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unable to find extension %s", props[i].name);
371 continue;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600372 }
373
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600374 loader_add_to_ext_list(ext_list, 1, ext_prop);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600375 }
376}
377
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600378/*
379 * Append non-duplicate extension properties defined in prop_list
380 * to the given ext_info list
381 */
382void loader_add_to_ext_list(
383 struct loader_extension_list *ext_list,
384 uint32_t prop_list_count,
385 const struct loader_extension_property *props)
386{
387 uint32_t i;
388 struct loader_extension_property *cur_ext;
389
390 if (ext_list->list == NULL || ext_list->capacity == 0) {
391 loader_init_ext_list(ext_list);
392 }
393
394 if (ext_list->list == NULL)
395 return;
396
397 for (i = 0; i < prop_list_count; i++) {
398 cur_ext = (struct loader_extension_property *) &props[i];
399
400 // look for duplicates
401 if (has_vk_extension_property(&cur_ext->info, ext_list)) {
402 continue;
403 }
404
405 // add to list at end
406 // check for enough capacity
407 if (ext_list->count * sizeof(struct loader_extension_property)
408 >= ext_list->capacity) {
409 // double capacity
410 ext_list->capacity *= 2;
411 ext_list->list = realloc(ext_list->list, ext_list->capacity);
412 }
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600413
414 /*
415 * Check if any extensions already on the list come from the same
416 * library and use the same Get*ExtensionInfo. If so, link this
417 * extension to the previous as an alias. That way when we activate
418 * extensions we only activiate the associated layer once no
419 * matter how many extensions are used.
420 */
421 for (uint32_t j = 0; j < ext_list->count; j++) {
422 struct loader_extension_property *active_property = &ext_list->list[j];
423 if (cur_ext->lib_name &&
424 cur_ext->origin == VK_EXTENSION_ORIGIN_LAYER &&
425 active_property->origin == VK_EXTENSION_ORIGIN_LAYER &&
426 strcmp(cur_ext->lib_name, active_property->lib_name) == 0 &&
427 strcmp(cur_ext->get_extension_info_name, active_property->get_extension_info_name) == 0 &&
428 active_property->alias == NULL) {
429 cur_ext->alias = active_property;
430 break;
431 }
432 }
433
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600434 memcpy(&ext_list->list[ext_list->count], cur_ext, sizeof(struct loader_extension_property));
435 ext_list->count++;
436 }
437}
438
439/*
440 * Search the search_list for any extension with
441 * a name that matches the given ext_name.
442 * Add all matching extensions to the found_list
443 * Do not add if found VkExtensionProperties is already
444 * on the found_list
445 */
446static void loader_search_ext_list_for_name(
447 const char *ext_name,
448 const struct loader_extension_list *search_list,
449 struct loader_extension_list *found_list)
450{
451 for (uint32_t i = 0; i < search_list->count; i++) {
452 struct loader_extension_property *ext_prop = &search_list->list[i];
453 if (0 == strcmp(ext_prop->info.name, ext_name)) {
454 /* Found an extension with the same name, add to found_list */
455 loader_add_to_ext_list(found_list, 1, &search_list->list[i]);
456 }
457 }
458}
459
460bool loader_is_extension_scanned(const VkExtensionProperties *ext_prop)
Jon Ashburnfc2e38c2015-04-14 09:15:32 -0600461{
462 uint32_t i;
463
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600464 for (i = 0; i < loader.global_extensions.count; i++) {
465 if (compare_vk_extension_properties(&loader.global_extensions.list[i].info, ext_prop))
Jon Ashburnfc2e38c2015-04-14 09:15:32 -0600466 return true;
467 }
468 return false;
469}
470
Jon Ashburn27cd5842015-05-12 17:26:48 -0600471void loader_coalesce_extensions(void)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600472{
473 uint32_t i;
474 struct loader_scanned_icds *icd_list = loader.scanned_icd_list;
475
476 // traverse scanned icd list adding non-duplicate extensions to the list
477 while (icd_list != NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600478 loader_add_to_ext_list(&loader.global_extensions,
479 icd_list->global_extension_list.count,
480 icd_list->global_extension_list.list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600481 icd_list = icd_list->next;
482 };
483
484 //Traverse layers list adding non-duplicate extensions to the list
485 for (i = 0; i < loader.scanned_layer_count; i++) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600486 loader_add_to_ext_list(&loader.global_extensions,
487 loader.scanned_layers[i].global_extension_list.count,
488 loader.scanned_layers[i].global_extension_list.list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600489 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600490
491 // Traverse loader's extensions, adding non-duplicate extensions to the list
492 debug_report_add_instance_extensions(&loader.global_extensions);
Jon Ashburn0c5d4ab2015-05-26 13:57:35 -0600493 wsi_lunarg_add_instance_extensions(&loader.global_extensions);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600494}
495
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600496static void loader_icd_destroy(
497 struct loader_instance *ptr_inst,
498 struct loader_icd *icd)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800499{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600500 ptr_inst->total_icd_count--;
Jon Ashburn128f9422015-05-28 19:16:58 -0600501 free(icd->gpus);
502 free(icd->loader_dispatch);
503 //TODO free wrappedGpus or remove them
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800504 free(icd);
505}
506
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600507static struct loader_icd * loader_icd_create(const struct loader_scanned_icds *scanned)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800508{
509 struct loader_icd *icd;
510
511 icd = malloc(sizeof(*icd));
512 if (!icd)
513 return NULL;
514
Courtney Goeltzenleuchter55001bb2014-10-28 10:29:27 -0600515 memset(icd, 0, sizeof(*icd));
516
Jon Ashburn46d1f582015-01-28 11:01:35 -0700517 icd->scanned_icds = scanned;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800518
519 return icd;
520}
521
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600522static struct loader_icd *loader_icd_add(
523 struct loader_instance *ptr_inst,
524 const struct loader_scanned_icds *scanned)
Chia-I Wu13a61a52014-08-04 11:18:20 +0800525{
526 struct loader_icd *icd;
527
Jon Ashburn46d1f582015-01-28 11:01:35 -0700528 icd = loader_icd_create(scanned);
Chia-I Wu13a61a52014-08-04 11:18:20 +0800529 if (!icd)
530 return NULL;
531
Chia-I Wu13a61a52014-08-04 11:18:20 +0800532 /* prepend to the list */
Jon Ashburn46888392015-01-29 15:45:51 -0700533 icd->next = ptr_inst->icds;
534 ptr_inst->icds = icd;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600535 ptr_inst->total_icd_count++;
Chia-I Wu13a61a52014-08-04 11:18:20 +0800536
537 return icd;
538}
539
Jon Ashburn46d1f582015-01-28 11:01:35 -0700540static void loader_scanned_icd_add(const char *filename)
541{
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700542 loader_platform_dl_handle handle;
Jon Ashburn3da71f22015-05-14 12:43:38 -0600543 void *fp_create_inst;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600544 void *fp_get_global_ext_info;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600545 void *fp_get_device_ext_info;
Jon Ashburn46d1f582015-01-28 11:01:35 -0700546 struct loader_scanned_icds *new_node;
547
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700548 // Used to call: dlopen(filename, RTLD_LAZY);
549 handle = loader_platform_open_library(filename);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700550 if (!handle) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600551 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_open_library_error(filename));
Jon Ashburn46d1f582015-01-28 11:01:35 -0700552 return;
553 }
554
555#define LOOKUP(func_ptr, func) do { \
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600556 func_ptr = (PFN_vk ##func) loader_platform_get_proc_address(handle, "vk" #func); \
Jon Ashburn46d1f582015-01-28 11:01:35 -0700557 if (!func_ptr) { \
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600558 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
Jon Ashburn46d1f582015-01-28 11:01:35 -0700559 return; \
560 } \
561} while (0)
562
Jon Ashburn46888392015-01-29 15:45:51 -0700563 LOOKUP(fp_create_inst, CreateInstance);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600564 LOOKUP(fp_get_global_ext_info, GetGlobalExtensionInfo);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600565 LOOKUP(fp_get_device_ext_info, GetPhysicalDeviceExtensionInfo);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700566#undef LOOKUP
567
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600568 new_node = (struct loader_scanned_icds *) malloc(sizeof(struct loader_scanned_icds)
569 + strlen(filename) + 1);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700570 if (!new_node) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600571 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
Jon Ashburn46d1f582015-01-28 11:01:35 -0700572 return;
573 }
574
575 new_node->handle = handle;
Jon Ashburn46888392015-01-29 15:45:51 -0700576 new_node->CreateInstance = fp_create_inst;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600577 new_node->GetGlobalExtensionInfo = fp_get_global_ext_info;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600578 loader_init_ext_list(&new_node->global_extension_list);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600579 loader_init_ext_list(&new_node->device_extension_list);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700580 new_node->next = loader.scanned_icd_list;
Jon Ashburn46d1f582015-01-28 11:01:35 -0700581
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600582 new_node->lib_name = (char *) (new_node + 1);
583 if (!new_node->lib_name) {
584 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
585 return;
586 }
587 strcpy(new_node->lib_name, filename);
588
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600589 loader.scanned_icd_list = new_node;
590
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600591 get_global_extensions(
592 (PFN_vkGetGlobalExtensionInfo) fp_get_global_ext_info,
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600593 "vkGetGlobalExtensionInfo",
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600594 new_node->lib_name,
595 VK_EXTENSION_ORIGIN_ICD,
596 &new_node->global_extension_list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600597}
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700598
Jon Ashburn3da71f22015-05-14 12:43:38 -0600599static void loader_icd_init_entrys(struct loader_icd *icd,
600 struct loader_scanned_icds *scanned_icds)
601{
602 /* initialize entrypoint function pointers */
603
604 #define LOOKUP(func) do { \
605 icd->func = (PFN_vk ##func) loader_platform_get_proc_address(scanned_icds->handle, "vk" #func); \
606 if (!icd->func) { \
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600607 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
Jon Ashburn3da71f22015-05-14 12:43:38 -0600608 return; \
609 } \
610 } while (0)
611
Jon Ashburn8d1b0b52015-05-18 13:20:15 -0600612 /* could change this to use GetInstanceProcAddr in driver instead of dlsym */
613 LOOKUP(GetDeviceProcAddr);
Jon Ashburn3da71f22015-05-14 12:43:38 -0600614 LOOKUP(DestroyInstance);
615 LOOKUP(EnumeratePhysicalDevices);
616 LOOKUP(GetPhysicalDeviceInfo);
617 LOOKUP(CreateDevice);
618 LOOKUP(GetPhysicalDeviceExtensionInfo);
Jon Ashburn3da71f22015-05-14 12:43:38 -0600619 LOOKUP(GetMultiDeviceCompatibility);
Jon Ashburn95a77ba2015-05-15 15:09:35 -0600620 LOOKUP(GetDisplayInfoWSI);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600621 LOOKUP(DbgCreateMsgCallback);
622 LOOKUP(DbgDestroyMsgCallback);
Jon Ashburn3da71f22015-05-14 12:43:38 -0600623#undef LOOKUP
624
625 return;
626}
627
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600628/**
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600629 * Try to \c loader_icd_scan VK driver(s).
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600630 *
631 * This function scans the default system path or path
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600632 * specified by the \c LIBVK_DRIVERS_PATH environment variable in
633 * order to find loadable VK ICDs with the name of libVK_*.
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600634 *
635 * \returns
636 * void; but side effect is to set loader_icd_scanned to true
637 */
Jon Ashburn27cd5842015-05-12 17:26:48 -0600638void loader_icd_scan(void)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800639{
Ian Elliott4470a302015-02-17 10:33:47 -0700640 const char *p, *next;
641 char *libPaths = NULL;
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600642 DIR *sysdir;
643 struct dirent *dent;
644 char icd_library[1024];
Jon Ashburn5cda59c2014-10-03 16:31:35 -0600645 char path[1024];
Ian Elliott19628802015-02-04 12:06:46 -0700646 uint32_t len;
Ian Elliott4470a302015-02-17 10:33:47 -0700647#if defined(WIN32)
648 bool must_free_libPaths;
649 libPaths = loader_get_registry_and_env(DRIVER_PATH_ENV,
650 DRIVER_PATH_REGISTRY_VALUE);
651 if (libPaths != NULL) {
652 must_free_libPaths = true;
653 } else {
654 must_free_libPaths = false;
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600655 libPaths = DEFAULT_VK_DRIVERS_PATH;
Ian Elliott4470a302015-02-17 10:33:47 -0700656 }
657#else // WIN32
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600658 if (geteuid() == getuid()) {
Ian Elliott4470a302015-02-17 10:33:47 -0700659 /* Don't allow setuid apps to use the DRIVER_PATH_ENV env var: */
660 libPaths = getenv(DRIVER_PATH_ENV);
661 }
662 if (libPaths == NULL) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600663 libPaths = DEFAULT_VK_DRIVERS_PATH;
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600664 }
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700665#endif // WIN32
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800666
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600667 for (p = libPaths; *p; p = next) {
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700668 next = strchr(p, PATH_SEPERATOR);
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600669 if (next == NULL) {
Ian Elliott19628802015-02-04 12:06:46 -0700670 len = (uint32_t) strlen(p);
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600671 next = p + len;
672 }
673 else {
Ian Elliott19628802015-02-04 12:06:46 -0700674 len = (uint32_t) (next - p);
Jon Ashburn5cda59c2014-10-03 16:31:35 -0600675 sprintf(path, "%.*s", (len > sizeof(path) - 1) ? (int) sizeof(path) - 1 : len, p);
676 p = path;
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600677 next++;
678 }
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800679
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700680 // TODO/TBD: Do we want to do this on Windows, or just let Windows take
681 // care of its own search path (which it apparently has)?
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600682 sysdir = opendir(p);
683 if (sysdir) {
684 dent = readdir(sysdir);
685 while (dent) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600686 /* Look for ICDs starting with VK_DRIVER_LIBRARY_PREFIX and
687 * ending with VK_LIBRARY_SUFFIX
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700688 */
689 if (!strncmp(dent->d_name,
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600690 VK_DRIVER_LIBRARY_PREFIX,
691 VK_DRIVER_LIBRARY_PREFIX_LEN)) {
Ian Elliott19628802015-02-04 12:06:46 -0700692 uint32_t nlen = (uint32_t) strlen(dent->d_name);
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600693 const char *suf = dent->d_name + nlen - VK_LIBRARY_SUFFIX_LEN;
694 if ((nlen > VK_LIBRARY_SUFFIX_LEN) &&
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700695 !strncmp(suf,
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600696 VK_LIBRARY_SUFFIX,
697 VK_LIBRARY_SUFFIX_LEN)) {
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700698 snprintf(icd_library, 1024, "%s" DIRECTORY_SYMBOL "%s", p,dent->d_name);
699 loader_scanned_icd_add(icd_library);
700 }
701 }
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600702
703 dent = readdir(sysdir);
704 }
705 closedir(sysdir);
706 }
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800707 }
708
Ian Elliott4470a302015-02-17 10:33:47 -0700709#if defined(WIN32)
710 // Free any allocated memory:
711 if (must_free_libPaths) {
712 free(libPaths);
713 }
714#endif // WIN32
715
716 // Note that we've scanned for ICDs:
Jon Ashburn46d1f582015-01-28 11:01:35 -0700717 loader.icds_scanned = true;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800718}
719
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600720
Jon Ashburn27cd5842015-05-12 17:26:48 -0600721void layer_lib_scan(void)
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600722{
723 const char *p, *next;
Ian Elliott4470a302015-02-17 10:33:47 -0700724 char *libPaths = NULL;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600725 DIR *curdir;
726 struct dirent *dent;
Ian Elliott4470a302015-02-17 10:33:47 -0700727 size_t len, i;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600728 char temp_str[1024];
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600729 uint32_t count;
730 PFN_vkGetGlobalExtensionInfo fp_get_ext;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600731
Ian Elliott4470a302015-02-17 10:33:47 -0700732#if defined(WIN32)
733 bool must_free_libPaths;
734 libPaths = loader_get_registry_and_env(LAYERS_PATH_ENV,
735 LAYERS_PATH_REGISTRY_VALUE);
736 if (libPaths != NULL) {
737 must_free_libPaths = true;
738 } else {
739 must_free_libPaths = false;
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600740 libPaths = DEFAULT_VK_LAYERS_PATH;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600741 }
Ian Elliott4470a302015-02-17 10:33:47 -0700742#else // WIN32
743 if (geteuid() == getuid()) {
744 /* Don't allow setuid apps to use the DRIVER_PATH_ENV env var: */
Courtney Goeltzenleuchter66b72f92015-02-18 20:03:02 -0700745 libPaths = getenv(LAYERS_PATH_ENV);
Ian Elliott4470a302015-02-17 10:33:47 -0700746 }
747 if (libPaths == NULL) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600748 libPaths = DEFAULT_VK_LAYERS_PATH;
Ian Elliott4470a302015-02-17 10:33:47 -0700749 }
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700750#endif // WIN32
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600751
Ian Elliott4470a302015-02-17 10:33:47 -0700752 if (libPaths == NULL) {
753 // Have no paths to search:
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -0700754 return;
755 }
Ian Elliott4470a302015-02-17 10:33:47 -0700756 len = strlen(libPaths);
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -0700757 loader.layer_dirs = malloc(len+1);
Ian Elliott4470a302015-02-17 10:33:47 -0700758 if (loader.layer_dirs == NULL) {
759 free(libPaths);
Courtney Goeltzenleuchtera66265b2014-12-02 18:12:51 -0700760 return;
Ian Elliott4470a302015-02-17 10:33:47 -0700761 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600762 // Alloc passed, so we know there is enough space to hold the string
Ian Elliott4470a302015-02-17 10:33:47 -0700763 strcpy(loader.layer_dirs, libPaths);
764#if defined(WIN32)
765 // Free any allocated memory:
766 if (must_free_libPaths) {
767 free(libPaths);
768 must_free_libPaths = false;
769 }
770#endif // WIN32
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -0700771 libPaths = loader.layer_dirs;
772
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600773 /* cleanup any previously scanned libraries */
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600774 for (i = 0; i < loader.scanned_layer_count; i++) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600775 if (loader.scanned_layers[i].lib_name != NULL)
776 free(loader.scanned_layers[i].lib_name);
777 loader_destroy_ext_list(&loader.scanned_layers[i].global_extension_list);
778 loader.scanned_layers[i].lib_name = NULL;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600779 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600780 loader.scanned_layer_count = 0;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600781 count = 0;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600782
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600783 for (p = libPaths; *p; p = next) {
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600784 next = strchr(p, PATH_SEPERATOR);
785 if (next == NULL) {
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600786 len = (uint32_t) strlen(p);
787 next = p + len;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600788 }
789 else {
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600790 len = (uint32_t) (next - p);
791 *(char *) next = '\0';
792 next++;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600793 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600794
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600795 curdir = opendir(p);
796 if (curdir) {
797 dent = readdir(curdir);
798 while (dent) {
799 /* Look for layers starting with VK_LAYER_LIBRARY_PREFIX and
800 * ending with VK_LIBRARY_SUFFIX
801 */
802 if (!strncmp(dent->d_name,
803 VK_LAYER_LIBRARY_PREFIX,
804 VK_LAYER_LIBRARY_PREFIX_LEN)) {
805 uint32_t nlen = (uint32_t) strlen(dent->d_name);
806 const char *suf = dent->d_name + nlen - VK_LIBRARY_SUFFIX_LEN;
807 if ((nlen > VK_LIBRARY_SUFFIX_LEN) &&
808 !strncmp(suf,
809 VK_LIBRARY_SUFFIX,
810 VK_LIBRARY_SUFFIX_LEN)) {
811 loader_platform_dl_handle handle;
812 snprintf(temp_str, sizeof(temp_str),
813 "%s" DIRECTORY_SYMBOL "%s",p,dent->d_name);
814 // Used to call: dlopen(temp_str, RTLD_LAZY)
815 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
816 "Attempt to open library: %s\n", temp_str);
817 if ((handle = loader_platform_open_library(temp_str)) == NULL) {
818 dent = readdir(curdir);
819 continue;
820 }
821 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
822 "Opened library: %s\n", temp_str);
Courtney Goeltzenleuchtera9e4af42015-06-01 14:49:17 -0600823
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600824 /* TODO: Remove fixed count */
825 if (count == MAX_LAYER_LIBRARIES) {
826 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
827 "%s ignored: max layer libraries exceed",
828 temp_str);
829 break;
830 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600831
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600832 fp_get_ext = loader_platform_get_proc_address(handle, "vkGetGlobalExtensionInfo");
833 if (!fp_get_ext) {
834 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
835 "Couldn't dlsym vkGetGlobalExtensionInfo from library %s",
836 temp_str);
837 dent = readdir(curdir);
838 loader_platform_close_library(handle);
839 continue;
840 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600841
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600842 loader.scanned_layers[count].lib_name =
843 malloc(strlen(temp_str) + 1);
844 if (loader.scanned_layers[count].lib_name == NULL) {
845 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "%s ignored: out of memory", temp_str);
846 break;
847 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600848
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600849 strcpy(loader.scanned_layers[count].lib_name, temp_str);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600850
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600851 fprintf(stderr, "Collecting global extensions for %s\n", temp_str);
852 get_global_extensions(
853 fp_get_ext,
854 "vkGetGlobalExtensionInfo",
855 loader.scanned_layers[count].lib_name,
856 VK_EXTENSION_ORIGIN_LAYER,
857 &loader.scanned_layers[count].global_extension_list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600858
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600859 fp_get_ext = loader_platform_get_proc_address(handle,
860 "vkGetPhysicalDeviceExtensionInfo");
861 if (fp_get_ext) {
862 loader.scanned_layers[count].physical_device_extensions_supported = true;
863 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600864
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600865 count++;
866 loader_platform_close_library(handle);
867 }
868 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600869
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600870 dent = readdir(curdir);
871 } // while (dir_entry)
872 if (count == MAX_LAYER_LIBRARIES)
873 break;
874 closedir(curdir);
875 } // if (curdir))
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600876 } // for (libpaths)
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600877
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600878 loader.scanned_layer_count = count;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600879 loader.layers_scanned = true;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600880}
881
Jon Ashburn27cd5842015-05-12 17:26:48 -0600882static void* VKAPI loader_gpa_instance_internal(VkInstance inst, const char * pName)
883{
884 // inst is not wrapped
885 if (inst == VK_NULL_HANDLE) {
886 return NULL;
887 }
888 VkLayerInstanceDispatchTable* disp_table = * (VkLayerInstanceDispatchTable **) inst;
889 void *addr;
890
Jon Ashburn8fd08252015-05-28 16:25:02 -0600891 if (!strcmp(pName, "vkGetInstanceProcAddr"))
892 return (void *) loader_gpa_instance_internal;
893
Jon Ashburn27cd5842015-05-12 17:26:48 -0600894 if (disp_table == NULL)
895 return NULL;
896
897 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600898 if (addr) {
Jon Ashburn27cd5842015-05-12 17:26:48 -0600899 return addr;
Jon Ashburn3d526cb2015-04-13 18:10:06 -0600900 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600901
902 if (disp_table->GetInstanceProcAddr == NULL) {
903 return NULL;
904 }
905 return disp_table->GetInstanceProcAddr(inst, pName);
Jon Ashburn3d526cb2015-04-13 18:10:06 -0600906}
907
Jon Ashburn128f9422015-05-28 19:16:58 -0600908struct loader_icd * loader_get_icd(const VkPhysicalDevice gpu, uint32_t *gpu_index)
Jon Ashburn876b1ac2014-10-17 15:09:07 -0600909{
Jon Ashburn128f9422015-05-28 19:16:58 -0600910
Jon Ashburn98bd4542015-01-29 16:44:24 -0700911 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
912 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
913 for (uint32_t i = 0; i < icd->gpu_count; i++)
Jon Ashburn128f9422015-05-28 19:16:58 -0600914 if (icd->gpus[i] == gpu) {
Jon Ashburn98bd4542015-01-29 16:44:24 -0700915 *gpu_index = i;
916 return icd;
917 }
918 }
Jon Ashburn876b1ac2014-10-17 15:09:07 -0600919 }
920 return NULL;
921}
922
Mark Lobodzinski17caf572015-01-29 08:55:56 -0600923static bool loader_layers_activated(const struct loader_icd *icd, const uint32_t gpu_index)
Jon Ashburn876b1ac2014-10-17 15:09:07 -0600924{
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600925 if (icd->layer_count[gpu_index])
926 return true;
927 else
928 return false;
Jon Ashburn876b1ac2014-10-17 15:09:07 -0600929}
930
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600931static loader_platform_dl_handle loader_add_layer_lib(
Jon Ashburn4f67d742015-05-27 13:19:22 -0600932 const char *chain_type,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600933 struct loader_extension_property *ext_prop)
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600934{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600935 struct loader_lib_info *new_layer_lib_list, *my_lib;
936
937 /* Only loader layer libraries here */
938 if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) {
939 return NULL;
940 }
941
942 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
943 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, ext_prop->lib_name) == 0) {
944 /* Have already loaded this library, just increment ref count */
945 loader.loaded_layer_lib_list[i].ref_count++;
Jon Ashburne68a9ff2015-05-25 14:11:37 -0600946 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600947 "%s Chain: Increment layer reference count for layer library %s",
948 chain_type, ext_prop->lib_name);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600949 return loader.loaded_layer_lib_list[i].lib_handle;
950 }
951 }
952
953 /* Haven't seen this library so load it */
954 new_layer_lib_list = realloc(loader.loaded_layer_lib_list,
955 (loader.loaded_layer_lib_count + 1) * sizeof(struct loader_lib_info));
956 if (!new_layer_lib_list) {
957 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
958 return NULL;
959 }
960
961 my_lib = &new_layer_lib_list[loader.loaded_layer_lib_count];
962
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600963 /* NOTE: We require that the extension property be immutable */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600964 my_lib->lib_name = ext_prop->lib_name;
965 my_lib->ref_count = 0;
966 my_lib->lib_handle = NULL;
967
968 if ((my_lib->lib_handle = loader_platform_open_library(my_lib->lib_name)) == NULL) {
969 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
970 loader_platform_open_library_error(my_lib->lib_name));
971 return NULL;
972 } else {
973 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600974 "Chain: %s: Loading layer library %s",
975 chain_type, ext_prop->lib_name);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600976 }
977 loader.loaded_layer_lib_count++;
978 loader.loaded_layer_lib_list = new_layer_lib_list;
979 my_lib->ref_count++;
980
981 return my_lib->lib_handle;
982}
983
984static void loader_remove_layer_lib(
985 struct loader_instance *inst,
986 struct loader_extension_property *ext_prop)
987{
988 uint32_t idx;
989 struct loader_lib_info *new_layer_lib_list, *my_lib;
990
991 /* Only loader layer libraries here */
992 if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) {
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600993 return;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600994 }
Jon Ashburndf7d5842014-10-16 15:48:50 -0600995
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600996 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
997 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, ext_prop->lib_name) == 0) {
998 /* found matching library */
999 idx = i;
1000 my_lib = &loader.loaded_layer_lib_list[i];
1001 break;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001002 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001003 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001004
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001005 my_lib->ref_count--;
1006 inst->layer_count--;
1007 if (my_lib->ref_count > 0) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001008 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
1009 "Decrement reference count for layer library %s", ext_prop->lib_name);
Jon Ashburn27cd5842015-05-12 17:26:48 -06001010 return;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001011 }
Jon Ashburn19c25022015-04-14 14:14:48 -06001012
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001013 loader_platform_close_library(my_lib->lib_handle);
1014 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
1015 "Unloading layer library %s", ext_prop->lib_name);
1016
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001017 /* Need to remove unused library from list */
1018 new_layer_lib_list = malloc((loader.loaded_layer_lib_count - 1) * sizeof(struct loader_lib_info));
1019 if (!new_layer_lib_list) {
1020 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1021 return;
1022 }
1023
1024 if (idx > 0) {
1025 /* Copy records before idx */
1026 memcpy(new_layer_lib_list, &loader.loaded_layer_lib_list[0],
1027 sizeof(struct loader_lib_info) * idx);
1028 }
1029 if (idx < (loader.loaded_layer_lib_count - 1)) {
1030 /* Copy records after idx */
1031 memcpy(&new_layer_lib_list[idx], &loader.loaded_layer_lib_list[idx+1],
1032 sizeof(struct loader_lib_info) * (loader.loaded_layer_lib_count - idx - 1));
1033 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001034
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001035 free(loader.loaded_layer_lib_list);
1036 loader.loaded_layer_lib_count--;
1037 loader.loaded_layer_lib_list = new_layer_lib_list;
Jon Ashburnb8358052014-11-18 09:06:04 -07001038}
1039
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001040static void loader_add_layer_env(
1041 struct loader_extension_list *ext_list,
1042 const struct loader_extension_list *search_list)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001043{
Ian Elliott4470a302015-02-17 10:33:47 -07001044 char *layerEnv;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001045 uint32_t len;
Jon Ashburnd09bd102014-10-22 21:15:26 -06001046 char *p, *pOrig, *next, *name;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001047
Ian Elliott4470a302015-02-17 10:33:47 -07001048#if defined(WIN32)
1049 layerEnv = loader_get_registry_and_env(LAYER_NAMES_ENV,
1050 LAYER_NAMES_REGISTRY_VALUE);
1051#else // WIN32
1052 layerEnv = getenv(LAYER_NAMES_ENV);
1053#endif // WIN32
1054 if (layerEnv == NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001055 return;
Ian Elliott4470a302015-02-17 10:33:47 -07001056 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001057 p = malloc(strlen(layerEnv) + 1);
Ian Elliott4470a302015-02-17 10:33:47 -07001058 if (p == NULL) {
1059#if defined(WIN32)
1060 free(layerEnv);
1061#endif // WIN32
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001062 return;
Ian Elliott4470a302015-02-17 10:33:47 -07001063 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001064 strcpy(p, layerEnv);
Ian Elliott4470a302015-02-17 10:33:47 -07001065#if defined(WIN32)
1066 free(layerEnv);
1067#endif // WIN32
Jon Ashburnd09bd102014-10-22 21:15:26 -06001068 pOrig = p;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001069
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001070 while (p && *p ) {
Jon Ashburn19c25022015-04-14 14:14:48 -06001071 //memset(&lib_name[0], 0, sizeof(const char *) * MAX_LAYER_LIBRARIES);
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001072 next = strchr(p, PATH_SEPERATOR);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001073 if (next == NULL) {
Ian Elliott19628802015-02-04 12:06:46 -07001074 len = (uint32_t) strlen(p);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001075 next = p + len;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001076 } else {
Ian Elliott19628802015-02-04 12:06:46 -07001077 len = (uint32_t) (next - p);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001078 *(char *) next = '\0';
1079 next++;
1080 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001081 name = basename(p);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001082 loader_search_ext_list_for_name(name, search_list, ext_list);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001083 p = next;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001084 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001085
Jon Ashburnd09bd102014-10-22 21:15:26 -06001086 free(pOrig);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001087 return;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001088}
1089
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001090
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -06001091void loader_deactivate_instance_layers(struct loader_instance *instance)
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001092{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001093 if (!instance->layer_count) {
1094 return;
1095 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001096
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001097 /* Create instance chain of enabled layers */
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -06001098 for (uint32_t i = 0; i < instance->activated_layer_list.count; i++) {
1099 struct loader_extension_property *ext_prop = &instance->activated_layer_list.list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001100
1101 loader_remove_layer_lib(instance, ext_prop);
1102
1103 instance->layer_count--;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001104 }
Jon Ashburn27cd5842015-05-12 17:26:48 -06001105
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001106}
1107
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001108void loader_enable_instance_layers(struct loader_instance *inst)
1109{
1110 if (inst == NULL)
1111 return;
1112
1113 /* Add any layers specified in the environment first */
1114 loader_add_layer_env(&inst->enabled_instance_extensions, &loader.global_extensions);
1115
1116 /* Add layers / extensions specified by the application */
1117 loader_add_vk_ext_to_ext_list(
1118 &inst->enabled_instance_extensions,
1119 inst->app_extension_count,
1120 inst->app_extension_props,
1121 &loader.global_extensions);
1122}
1123
Jon Ashburn27cd5842015-05-12 17:26:48 -06001124uint32_t loader_activate_instance_layers(struct loader_instance *inst)
1125{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001126 uint32_t layer_idx;
Jon Ashburn128f9422015-05-28 19:16:58 -06001127 VkBaseLayerObject *wrappedInstance;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001128
Jon Ashburn27cd5842015-05-12 17:26:48 -06001129 if (inst == NULL)
1130 return 0;
1131
1132 // NOTE inst is unwrapped at this point in time
1133 VkObject baseObj = (VkObject) inst;
1134 VkObject nextObj = (VkObject) inst;
1135 VkBaseLayerObject *nextInstObj;
1136 PFN_vkGetInstanceProcAddr nextGPA = loader_gpa_instance_internal;
1137
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001138 /*
1139 * Figure out how many actual layers will need to be wrapped.
1140 */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001141 for (uint32_t i = 0; i < inst->enabled_instance_extensions.count; i++) {
1142 struct loader_extension_property *ext_prop = &inst->enabled_instance_extensions.list[i];
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001143 if (ext_prop->alias) {
1144 ext_prop = ext_prop->alias;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001145 }
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001146 if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) {
1147 continue;
1148 }
1149 loader_add_to_ext_list(&inst->activated_layer_list, 1, ext_prop);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001150 }
Jon Ashburn27cd5842015-05-12 17:26:48 -06001151
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001152 inst->layer_count = inst->activated_layer_list.count;
1153
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001154 if (!inst->layer_count) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06001155 return 0;
1156 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001157
Jon Ashburn128f9422015-05-28 19:16:58 -06001158 wrappedInstance = malloc(sizeof(VkBaseLayerObject)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001159 * inst->layer_count);
Jon Ashburn128f9422015-05-28 19:16:58 -06001160 if (!wrappedInstance) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001161 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance objects for layer");
1162 return 0;
1163 }
1164
1165 /* Create instance chain of enabled layers */
1166 layer_idx = inst->layer_count - 1;
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001167 for (int32_t i = inst->activated_layer_list.count - 1; i >= 0; i--) {
1168 struct loader_extension_property *ext_prop = &inst->activated_layer_list.list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001169 loader_platform_dl_handle lib_handle;
1170
1171 /*
Courtney Goeltzenleuchteree3b16a2015-06-01 14:12:42 -06001172 * For global exenstions implemented within the loader (i.e. WSI, DEBUG_REPORT
1173 * the extension must provide two entry points for the loader to use:
1174 * - "trampoline" entry point - this is the address returned by GetProcAddr
1175 * and will always do what's necessary to support a global call.
1176 * - "terminator" function - this function will be put at the end of the
1177 * instance chain and will contain the necessary logica to call / process
1178 * the extension for the appropriate ICDs that are available.
1179 * There is no generic mechanism for including these functions, the references
1180 * must be placed into the appropriate loader entry points.
1181 * GetInstanceProcAddr: call extension GetInstanceProcAddr to check for GetProcAddr requests
1182 * loader_coalesce_extensions(void) - add extension records to the list of global
1183 * extension available to the app.
1184 * instance_disp - add function pointer for terminator function to this array.
1185 * The extension itself should be in a separate file that will be
1186 * linked directly with the loader.
1187 * Note: An extension's Get*ProcAddr should not return a function pointer for
1188 * any extension entry points until the extension has been enabled.
1189 * To do this requires a different behavior from Get*ProcAddr functions implemented
1190 * in layers.
1191 * The very first call to a layer will be it's Get*ProcAddr function requesting
1192 * the layer's vkGet*ProcAddr. The layer should intialize it's internal dispatch table
1193 * with the wrapped object given (either Instance or Device) and return the layer's
1194 * Get*ProcAddr function. The layer should also use this opportunity to record the
1195 * baseObject so that it can find the correct local dispatch table on future calls.
1196 * Subsequent calls to Get*ProcAddr, CreateInstance, CreateDevice
1197 * will not use a wrapped object and must look up their local dispatch table from
1198 * the given baseObject.
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001199 */
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001200 assert(ext_prop->origin == VK_EXTENSION_ORIGIN_LAYER);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001201
Jon Ashburn128f9422015-05-28 19:16:58 -06001202 nextInstObj = (wrappedInstance + layer_idx);
Jon Ashburn27cd5842015-05-12 17:26:48 -06001203 nextInstObj->pGPA = nextGPA;
1204 nextInstObj->baseObject = baseObj;
1205 nextInstObj->nextObject = nextObj;
1206 nextObj = (VkObject) nextInstObj;
1207
1208 char funcStr[256];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001209 snprintf(funcStr, 256, "%sGetInstanceProcAddr", ext_prop->info.name);
Jon Ashburn4f67d742015-05-27 13:19:22 -06001210 lib_handle = loader_add_layer_lib("instance", ext_prop);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001211 if ((nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
1212 nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
Jon Ashburn27cd5842015-05-12 17:26:48 -06001213 if (!nextGPA) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001214 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to find vkGetInstanceProcAddr in layer %s", ext_prop->lib_name);
Courtney Goeltzenleuchtera9e4af42015-06-01 14:49:17 -06001215
1216 /* TODO: Should we return nextObj, nextGPA to previous? */
Jon Ashburn27cd5842015-05-12 17:26:48 -06001217 continue;
1218 }
1219
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001220 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
1221 "Insert instance layer library %s for extension: %s",
1222 ext_prop->lib_name, ext_prop->info.name);
1223
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001224 layer_idx--;
Jon Ashburn27cd5842015-05-12 17:26:48 -06001225 }
1226
Jon Ashburn8fd08252015-05-28 16:25:02 -06001227 loader_init_instance_core_dispatch_table(inst->disp, nextGPA, (VkInstance) nextObj, (VkInstance) baseObj);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001228
Jon Ashburn128f9422015-05-28 19:16:58 -06001229 free(wrappedInstance);
Jon Ashburn27cd5842015-05-12 17:26:48 -06001230 return inst->layer_count;
1231}
1232
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001233void loader_activate_instance_layer_extensions(struct loader_instance *inst)
1234{
1235
1236 loader_init_instance_extension_dispatch_table(inst->disp,
1237 inst->disp->GetInstanceProcAddr,
Jon Ashburn128f9422015-05-28 19:16:58 -06001238 (VkInstance) inst);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001239}
1240
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001241void loader_enable_device_layers(struct loader_icd *icd, uint32_t gpu_index)
1242{
1243 if (icd == NULL)
1244 return;
1245
1246 /* Add any layers specified in the environment first */
1247 loader_add_layer_env(&icd->enabled_device_extensions[gpu_index], &loader.global_extensions);
1248
1249 /* Add layers / extensions specified by the application */
1250 loader_add_vk_ext_to_ext_list(
1251 &icd->enabled_device_extensions[gpu_index],
1252 icd->app_extension_count[gpu_index],
1253 icd->app_extension_props[gpu_index],
1254 &loader.global_extensions);
1255}
1256
1257extern uint32_t loader_activate_device_layers(
1258 VkDevice device,
1259 struct loader_icd *icd,
1260 uint32_t gpu_index,
1261 uint32_t ext_count,
1262 const VkExtensionProperties *ext_props)
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001263{
Mark Lobodzinski17caf572015-01-29 08:55:56 -06001264 uint32_t count;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001265 uint32_t layer_idx;
1266
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001267 if (!icd)
1268 return 0;
Jon Ashburn83a64252015-04-15 11:31:12 -06001269 assert(gpu_index < MAX_GPUS_FOR_LAYER);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001270
1271 /* activate any layer libraries */
1272 if (!loader_layers_activated(icd, gpu_index)) {
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001273 VkObject nextObj = (VkObject) device;
1274 VkObject baseObj = nextObj;
1275 VkBaseLayerObject *nextGpuObj;
Jon Ashburn7c096122015-05-22 09:19:49 -06001276 PFN_vkGetDeviceProcAddr nextGPA = icd->GetDeviceProcAddr;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001277
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001278 count = 0;
1279 for (uint32_t i = 0; i < icd->enabled_device_extensions[gpu_index].count; i++) {
1280 struct loader_extension_property *ext_prop = &icd->enabled_device_extensions[gpu_index].list[i];
1281 if (ext_prop->origin == VK_EXTENSION_ORIGIN_LAYER) {
1282 count++;
1283 }
1284 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001285 if (!count)
1286 return 0;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001287
1288 icd->layer_count[gpu_index] = count;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001289
Jon Ashburnbacb0f52015-04-06 10:58:22 -06001290 icd->wrappedGpus[gpu_index] = malloc(sizeof(VkBaseLayerObject) * icd->layer_count[gpu_index]);
Jon Ashburn27cd5842015-05-12 17:26:48 -06001291 if (! icd->wrappedGpus[gpu_index]) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001292 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Gpu objects for layer");
Jon Ashburn27cd5842015-05-12 17:26:48 -06001293 return 0;
1294 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001295 layer_idx = count - 1;
Mark Lobodzinski17caf572015-01-29 08:55:56 -06001296 for (int32_t i = icd->layer_count[gpu_index] - 1; i >= 0; i--) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001297 struct loader_extension_property *ext_prop = &icd->enabled_device_extensions[gpu_index].list[i];
1298 loader_platform_dl_handle lib_handle;
1299
1300 if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) {
1301 continue;
1302 }
1303
Jon Ashburnd09bd102014-10-22 21:15:26 -06001304 nextGpuObj = (icd->wrappedGpus[gpu_index] + i);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001305 nextGpuObj->pGPA = nextGPA;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001306 nextGpuObj->baseObject = baseObj;
1307 nextGpuObj->nextObject = nextObj;
1308 nextObj = (VkObject) nextGpuObj;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001309
Jon Ashburn79113cc2014-12-01 14:22:40 -07001310 char funcStr[256];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001311 snprintf(funcStr, 256, "%sGetDeviceProcAddr", ext_prop->info.name);
Jon Ashburn4f67d742015-05-27 13:19:22 -06001312 lib_handle = loader_add_layer_lib("device", ext_prop);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001313 if ((nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
1314 nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr");
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001315 if (!nextGPA) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001316 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to find vkGetDeviceProcAddr in layer %s", ext_prop->info.name);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001317 continue;
1318 }
1319
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001320 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
1321 "Insert device layer library %s for extension: %s",
1322 ext_prop->lib_name, ext_prop->info.name);
1323
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001324 layer_idx--;
1325 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001326
Jon Ashburn8fd08252015-05-28 16:25:02 -06001327 loader_init_device_dispatch_table(icd->loader_dispatch + gpu_index, nextGPA,
1328 (VkPhysicalDevice) nextObj, (VkPhysicalDevice) baseObj);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001329 } else {
1330 // TODO: Check that active layers match requested?
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001331 }
1332 return icd->layer_count[gpu_index];
1333}
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001334
Jon Ashburn27cd5842015-05-12 17:26:48 -06001335VkResult loader_CreateInstance(
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001336 const VkInstanceCreateInfo* pCreateInfo,
1337 VkInstance* pInstance)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001338{
Jon Ashburneed0c002015-05-21 17:42:17 -06001339 struct loader_instance *ptr_instance = *(struct loader_instance **) pInstance;
Jon Ashburn46888392015-01-29 15:45:51 -07001340 struct loader_scanned_icds *scanned_icds;
1341 struct loader_icd *icd;
Jon Ashburn27cd5842015-05-12 17:26:48 -06001342 VkResult res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001343
Jon Ashburn46888392015-01-29 15:45:51 -07001344 scanned_icds = loader.scanned_icd_list;
1345 while (scanned_icds) {
1346 icd = loader_icd_add(ptr_instance, scanned_icds);
1347 if (icd) {
Jon Ashburnb317fad2015-04-04 14:52:07 -06001348 res = scanned_icds->CreateInstance(pCreateInfo,
Jon Ashburn3da71f22015-05-14 12:43:38 -06001349 &(icd->instance));
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001350 if (res != VK_SUCCESS)
Jon Ashburn46888392015-01-29 15:45:51 -07001351 {
1352 ptr_instance->icds = ptr_instance->icds->next;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001353 loader_icd_destroy(ptr_instance, icd);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001354 icd->instance = VK_NULL_HANDLE;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001355 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Jon Ashburn46888392015-01-29 15:45:51 -07001356 "ICD ignored: failed to CreateInstance on device");
Jon Ashburn3da71f22015-05-14 12:43:38 -06001357 } else
1358 {
1359 loader_icd_init_entrys(icd, scanned_icds);
Jon Ashburn46888392015-01-29 15:45:51 -07001360 }
1361 }
1362 scanned_icds = scanned_icds->next;
1363 }
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001364
Ian Elliotteb450762015-02-05 15:19:15 -07001365 if (ptr_instance->icds == NULL) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001366 return VK_ERROR_INCOMPATIBLE_DRIVER;
Ian Elliotteb450762015-02-05 15:19:15 -07001367 }
Jon Ashburn46888392015-01-29 15:45:51 -07001368
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001369 return res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001370}
1371
Jon Ashburn27cd5842015-05-12 17:26:48 -06001372VkResult loader_DestroyInstance(
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06001373 VkInstance instance)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001374{
Courtney Goeltzenleuchterdeceded2015-06-08 15:04:02 -06001375 struct loader_instance *ptr_instance = loader_instance(instance);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001376 struct loader_icd *icds = ptr_instance->icds;
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06001377 VkResult res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001378
1379 // Remove this instance from the list of instances:
1380 struct loader_instance *prev = NULL;
1381 struct loader_instance *next = loader.instances;
1382 while (next != NULL) {
1383 if (next == ptr_instance) {
1384 // Remove this instance from the list:
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001385 free(ptr_instance->app_extension_props);
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001386 if (prev)
1387 prev->next = next->next;
Jon Ashburnc5c49602015-02-03 09:26:59 -07001388 else
1389 loader.instances = next->next;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001390 break;
1391 }
1392 prev = next;
1393 next = next->next;
1394 }
1395 if (next == NULL) {
1396 // This must be an invalid instance handle or empty list
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001397 return VK_ERROR_INVALID_HANDLE;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001398 }
1399
Jon Ashburn3da71f22015-05-14 12:43:38 -06001400 while (icds) {
1401 if (icds->instance) {
1402 res = icds->DestroyInstance(icds->instance);
Tony Barbourf20f87b2015-04-22 09:02:32 -06001403 if (res != VK_SUCCESS)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001404 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Tony Barbourf20f87b2015-04-22 09:02:32 -06001405 "ICD ignored: failed to DestroyInstance on device");
1406 }
Jon Ashburn128f9422015-05-28 19:16:58 -06001407 loader_icd_destroy(ptr_instance, icds);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001408 icds->instance = VK_NULL_HANDLE;
1409 icds = icds->next;
Jon Ashburn46888392015-01-29 15:45:51 -07001410 }
1411
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001412
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001413 return VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001414}
1415
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001416VkResult loader_init_physical_device_info(
1417 struct loader_instance *ptr_instance)
1418{
1419 struct loader_icd *icd;
1420 uint32_t n, count = 0;
1421 VkResult res = VK_ERROR_UNKNOWN;
1422
1423 icd = ptr_instance->icds;
1424 while (icd) {
1425 res = icd->EnumeratePhysicalDevices(icd->instance, &n, NULL);
1426 if (res != VK_SUCCESS)
1427 return res;
1428 icd->gpu_count = n;
1429 count += n;
1430 icd = icd->next;
1431 }
1432
1433 ptr_instance->total_gpu_count = count;
1434
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001435 icd = ptr_instance->icds;
1436 while (icd) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001437 PFN_vkGetDeviceProcAddr get_proc_addr = icd->GetDeviceProcAddr;
1438
1439 n = icd->gpu_count;
Jon Ashburn128f9422015-05-28 19:16:58 -06001440 icd->gpus = (VkPhysicalDevice *) malloc(n * sizeof(VkPhysicalDevice));
1441 if (!icd->gpus) {
1442 /* TODO: Add cleanup code here */
1443 return VK_ERROR_OUT_OF_HOST_MEMORY;
1444 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001445 res = icd->EnumeratePhysicalDevices(
1446 icd->instance,
1447 &n,
Jon Ashburn128f9422015-05-28 19:16:58 -06001448 icd->gpus);
1449 if ((res == VK_SUCCESS) && (n == icd->gpu_count)) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001450
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001451 icd->loader_dispatch = (VkLayerDispatchTable *) malloc(n *
1452 sizeof(VkLayerDispatchTable));
1453 for (unsigned int i = 0; i < n; i++) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001454
1455 loader_init_device_dispatch_table(icd->loader_dispatch + i,
Jon Ashburn128f9422015-05-28 19:16:58 -06001456 get_proc_addr, icd->gpus[i], icd->gpus[i]);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001457
Jon Ashburn128f9422015-05-28 19:16:58 -06001458 loader_init_dispatch(icd->gpus[i], ptr_instance->disp);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001459
1460 if (!loader_init_ext_list(&icd->device_extension_cache[i])) {
1461 /* TODO: Add cleanup code here */
1462 res = VK_ERROR_OUT_OF_HOST_MEMORY;
1463 }
1464 if (res == VK_SUCCESS && icd->GetPhysicalDeviceExtensionInfo) {
1465 size_t data_size;
1466 uint32_t extension_count;
1467
1468 data_size = sizeof(extension_count);
Jon Ashburn128f9422015-05-28 19:16:58 -06001469 res = icd->GetPhysicalDeviceExtensionInfo(icd->gpus[i], VK_EXTENSION_INFO_TYPE_COUNT, 0, &data_size, &extension_count);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001470 if (data_size == sizeof(extension_count) && res == VK_SUCCESS) {
1471 struct loader_extension_property ext_props;
1472
1473 /* Gather all the ICD extensions */
1474 for (uint32_t extension_id = 0; extension_id < extension_count; extension_id++) {
1475 data_size = sizeof(VkExtensionProperties);
Jon Ashburn128f9422015-05-28 19:16:58 -06001476 res = icd->GetPhysicalDeviceExtensionInfo(icd->gpus[i], VK_EXTENSION_INFO_TYPE_PROPERTIES,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001477 extension_id, &data_size, &ext_props.info);
1478 if (data_size == sizeof(VkExtensionProperties) && res == VK_SUCCESS) {
1479 ext_props.hosted = false;
1480 ext_props.origin = VK_EXTENSION_ORIGIN_ICD;
1481 ext_props.lib_name = icd->scanned_icds->lib_name;
Jon Ashburn128f9422015-05-28 19:16:58 -06001482 // For ICDs, this is the only option
1483 strcpy(ext_props.get_extension_info_name, "vkGetPhysicalDeviceExtensionInfo");
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001484 loader_add_to_ext_list(&icd->device_extension_cache[i], 1, &ext_props);
1485 }
1486 }
1487
1488 // Traverse layers list adding non-duplicate extensions to the list
1489 for (uint32_t l = 0; l < loader.scanned_layer_count; l++) {
Jon Ashburn128f9422015-05-28 19:16:58 -06001490 get_physical_device_layer_extensions(ptr_instance, icd->gpus[i], l, &icd->device_extension_cache[i]);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001491 }
1492 }
1493 }
1494
1495 if (res != VK_SUCCESS) {
1496 /* clean up any extension lists previously created before this request failed */
1497 for (uint32_t j = 0; j < i; j++) {
1498 loader_destroy_ext_list(&icd->device_extension_cache[i]);
1499 }
1500 return res;
1501 }
1502 }
1503
1504 count += n;
1505 }
1506
1507 icd = icd->next;
1508 }
1509
1510 return VK_SUCCESS;
1511}
1512
Jon Ashburn27cd5842015-05-12 17:26:48 -06001513VkResult loader_EnumeratePhysicalDevices(
Courtney Goeltzenleuchter5e41f1d2015-04-20 12:48:54 -06001514 VkInstance instance,
1515 uint32_t* pPhysicalDeviceCount,
1516 VkPhysicalDevice* pPhysicalDevices)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001517{
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001518 uint32_t index = 0;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07001519 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001520 struct loader_icd *icd = ptr_instance->icds;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07001521
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001522 if (ptr_instance->total_gpu_count == 0) {
1523 loader_init_physical_device_info(ptr_instance);
Jon Ashburn4c392fb2015-01-28 19:57:09 -07001524 }
1525
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001526 *pPhysicalDeviceCount = ptr_instance->total_gpu_count;
1527 if (!pPhysicalDevices) {
1528 return VK_SUCCESS;
1529 }
Jon Ashburn4c392fb2015-01-28 19:57:09 -07001530
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001531 while (icd) {
1532 assert((index + icd->gpu_count) <= *pPhysicalDeviceCount);
Jon Ashburn128f9422015-05-28 19:16:58 -06001533 memcpy(&pPhysicalDevices[index], icd->gpus, icd->gpu_count * sizeof(VkPhysicalDevice));
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001534 index += icd->gpu_count;
1535 icd = icd->next;
1536 }
1537
1538 return VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001539}
1540
Jon Ashburn3da71f22015-05-14 12:43:38 -06001541VkResult loader_GetPhysicalDeviceInfo(
1542 VkPhysicalDevice gpu,
1543 VkPhysicalDeviceInfoType infoType,
1544 size_t* pDataSize,
1545 void* pData)
1546{
1547 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06001548 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001549 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
1550
1551 if (icd->GetPhysicalDeviceInfo)
1552 res = icd->GetPhysicalDeviceInfo(gpu, infoType, pDataSize, pData);
1553
1554 return res;
1555}
1556
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001557VkResult loader_CreateDevice(
1558 VkPhysicalDevice gpu,
1559 const VkDeviceCreateInfo* pCreateInfo,
1560 VkDevice* pDevice)
1561{
1562 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06001563 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001564 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001565
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001566 if (icd->CreateDevice) {
1567 res = icd->CreateDevice(gpu, pCreateInfo, pDevice);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001568 if (res != VK_SUCCESS) {
1569 return res;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001570 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001571
1572 VkLayerDispatchTable *dev_disp = icd->loader_dispatch + gpu_index;
1573 loader_init_dispatch(*pDevice, dev_disp);
1574
1575 icd->app_extension_count[gpu_index] = pCreateInfo->extensionCount;
1576 icd->app_extension_props[gpu_index] = (VkExtensionProperties *) malloc(sizeof(VkExtensionProperties) * pCreateInfo->extensionCount);
1577 if (icd->app_extension_props[gpu_index] == NULL && (icd->app_extension_count[gpu_index] > 0)) {
1578 return VK_ERROR_OUT_OF_HOST_MEMORY;
1579 }
1580
1581 /* Make local copy of extension list */
1582 if (icd->app_extension_count[gpu_index] > 0 && icd->app_extension_props[gpu_index] != NULL) {
1583 memcpy(icd->app_extension_props[gpu_index], pCreateInfo->pEnabledExtensions, sizeof(VkExtensionProperties) * pCreateInfo->extensionCount);
1584 }
1585
Courtney Goeltzenleuchteree3b16a2015-06-01 14:12:42 -06001586 /*
1587 * Put together the complete list of extensions to enable
1588 * This includes extensions requested via environment variables.
1589 */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001590 loader_enable_device_layers(icd, gpu_index);
1591
Courtney Goeltzenleuchteree3b16a2015-06-01 14:12:42 -06001592 /*
1593 * Load the libraries needed by the extensions on the
1594 * enabled extension list. This will build the
1595 * device instance chain terminating with the
1596 * selected device.
1597 */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001598 loader_activate_device_layers(*pDevice, icd, gpu_index,
1599 icd->app_extension_count[gpu_index],
1600 icd->app_extension_props[gpu_index]);
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001601 }
1602
1603 return res;
1604}
1605
Jon Ashburnb0fbe912015-05-06 10:15:07 -06001606LOADER_EXPORT void * VKAPI vkGetInstanceProcAddr(VkInstance instance, const char * pName)
1607{
Jon Ashburn07daee72015-05-21 18:13:33 -06001608 if (instance == VK_NULL_HANDLE)
1609 return NULL;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001610
Jon Ashburn07daee72015-05-21 18:13:33 -06001611 void *addr;
1612 /* get entrypoint addresses that are global (in the loader)*/
1613 addr = globalGetProcAddr(pName);
1614 if (addr)
1615 return addr;
Jon Ashburnb0fbe912015-05-06 10:15:07 -06001616
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001617 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
1618
1619 addr = debug_report_instance_gpa(ptr_instance, pName);
1620 if (addr) {
1621 return addr;
1622 }
1623
Jon Ashburn07daee72015-05-21 18:13:33 -06001624 /* return any extension global entrypoints */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001625 addr = wsi_lunarg_GetInstanceProcAddr(instance, pName);
Jon Ashburn07daee72015-05-21 18:13:33 -06001626 if (addr)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001627 return (ptr_instance->wsi_lunarg_enabled) ? addr : NULL;
Jon Ashburn07daee72015-05-21 18:13:33 -06001628
1629 /* return the instance dispatch table entrypoint for extensions */
1630 const VkLayerInstanceDispatchTable *disp_table = * (VkLayerInstanceDispatchTable **) instance;
1631 if (disp_table == NULL)
1632 return NULL;
1633
1634 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
1635 if (addr)
1636 return addr;
Jon Ashburnb0fbe912015-05-06 10:15:07 -06001637
1638 return NULL;
1639}
1640
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001641LOADER_EXPORT void * VKAPI vkGetDeviceProcAddr(VkDevice device, const char * pName)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001642{
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001643 if (device == VK_NULL_HANDLE) {
1644 return NULL;
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001645 }
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001646
Chia-I Wuf46b81a2015-01-04 11:12:47 +08001647 void *addr;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001648
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001649 /* for entrypoints that loader must handle (ie non-dispatchable or create object)
1650 make sure the loader entrypoint is returned */
1651 addr = loader_non_passthrough_gpa(pName);
Ian Elliotte19c9152015-04-15 12:53:19 -06001652 if (addr) {
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001653 return addr;
Ian Elliotte19c9152015-04-15 12:53:19 -06001654 }
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001655
Jon Ashburn07daee72015-05-21 18:13:33 -06001656 /* return any extension device entrypoints the loader knows about */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001657 addr = wsi_lunarg_GetDeviceProcAddr(device, pName);
Jon Ashburn07daee72015-05-21 18:13:33 -06001658 if (addr)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001659 return addr;
Jon Ashburn07daee72015-05-21 18:13:33 -06001660
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001661 /* return the dispatch table entrypoint for the fastest case */
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001662 const VkLayerDispatchTable *disp_table = * (VkLayerDispatchTable **) device;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001663 if (disp_table == NULL)
1664 return NULL;
1665
Jon Ashburn27cd5842015-05-12 17:26:48 -06001666 addr = loader_lookup_device_dispatch_table(disp_table, pName);
Chia-I Wuf46b81a2015-01-04 11:12:47 +08001667 if (addr)
1668 return addr;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001669 else {
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001670 if (disp_table->GetDeviceProcAddr == NULL)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001671 return NULL;
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001672 return disp_table->GetDeviceProcAddr(device, pName);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001673 }
1674}
1675
Jon Ashburneceb13e2015-05-18 15:28:32 -06001676LOADER_EXPORT VkResult VKAPI vkGetGlobalExtensionInfo(
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001677 VkExtensionInfoType infoType,
1678 uint32_t extensionIndex,
1679 size_t* pDataSize,
1680 void* pData)
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001681{
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001682 uint32_t *count;
1683 /* Scan/discover all ICD libraries in a single-threaded manner */
1684 loader_platform_thread_once(&once_icd, loader_icd_scan);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001685
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001686 /* get layer libraries in a single-threaded manner */
1687 loader_platform_thread_once(&once_layer, layer_lib_scan);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001688
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001689 /* merge any duplicate extensions */
1690 loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
1691
1692
1693 if (pDataSize == NULL)
1694 return VK_ERROR_INVALID_POINTER;
1695
1696 switch (infoType) {
1697 case VK_EXTENSION_INFO_TYPE_COUNT:
1698 *pDataSize = sizeof(uint32_t);
1699 if (pData == NULL)
1700 return VK_SUCCESS;
1701 count = (uint32_t *) pData;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001702 *count = loader.global_extensions.count;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001703 break;
1704 case VK_EXTENSION_INFO_TYPE_PROPERTIES:
1705 *pDataSize = sizeof(VkExtensionProperties);
1706 if (pData == NULL)
1707 return VK_SUCCESS;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001708 if (extensionIndex >= loader.global_extensions.count)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001709 return VK_ERROR_INVALID_VALUE;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001710 memcpy((VkExtensionProperties *) pData,
1711 &loader.global_extensions.list[extensionIndex],
1712 sizeof(VkExtensionProperties));
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001713 break;
1714 default:
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001715 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Invalid infoType in vkGetGlobalExtensionInfo");
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001716 return VK_ERROR_INVALID_VALUE;
1717 };
1718
1719 return VK_SUCCESS;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001720}
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001721
1722LOADER_EXPORT VkResult VKAPI vkGetPhysicalDeviceExtensionInfo(
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001723 VkPhysicalDevice gpu,
1724 VkExtensionInfoType infoType,
1725 uint32_t extensionIndex,
1726 size_t* pDataSize,
1727 void* pData)
1728{
1729 uint32_t gpu_index;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001730 uint32_t *count;
Jon Ashburn128f9422015-05-28 19:16:58 -06001731 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001732
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001733 if (pDataSize == NULL)
1734 return VK_ERROR_INVALID_POINTER;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001735
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001736 switch (infoType) {
1737 case VK_EXTENSION_INFO_TYPE_COUNT:
1738 *pDataSize = sizeof(uint32_t);
1739 if (pData == NULL)
1740 return VK_SUCCESS;
1741 count = (uint32_t *) pData;
1742 *count = icd->device_extension_cache[gpu_index].count;
1743 break;
1744 case VK_EXTENSION_INFO_TYPE_PROPERTIES:
1745 *pDataSize = sizeof(VkExtensionProperties);
1746 if (pData == NULL)
1747 return VK_SUCCESS;
1748 if (extensionIndex >= icd->device_extension_cache[gpu_index].count)
1749 return VK_ERROR_INVALID_VALUE;
1750 memcpy((VkExtensionProperties *) pData,
1751 &icd->device_extension_cache[gpu_index].list[extensionIndex],
1752 sizeof(VkExtensionProperties));
1753 break;
1754 default:
1755 return VK_ERROR_INVALID_VALUE;
1756 };
1757
1758 return VK_SUCCESS;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001759}
1760
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001761VkResult loader_GetMultiDeviceCompatibility(
1762 VkPhysicalDevice gpu0,
1763 VkPhysicalDevice gpu1,
1764 VkPhysicalDeviceCompatibilityInfo* pInfo)
1765{
1766 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06001767 struct loader_icd *icd = loader_get_icd(gpu0, &gpu_index);
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001768 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
1769
1770 if (icd->GetMultiDeviceCompatibility)
1771 res = icd->GetMultiDeviceCompatibility(gpu0, gpu1, pInfo);
1772
1773 return res;
1774}