blob: 43e344b7676e9c855585d887662b6de8c32f39db [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
Tobin Ehlisb835d1b2015-07-03 10:34:49 -060043#include "vk_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"
Tobin Ehlis0c6f9ee2015-07-03 09:42:57 -060049#include "vk_icd.h"
Jon Ashburn2077e382015-06-29 11:25:34 -060050#include "cJSON.h"
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080051
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060052void loader_add_to_ext_list(
53 struct loader_extension_list *ext_list,
54 uint32_t prop_list_count,
55 const struct loader_extension_property *prop_list);
56
Courtney Goeltzenleuchtered488302015-06-01 14:09:34 -060057static loader_platform_dl_handle loader_add_layer_lib(
58 const char *chain_type,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -060059 struct loader_layer_properties *layer_prop);
Courtney Goeltzenleuchtered488302015-06-01 14:09:34 -060060
61static void loader_remove_layer_lib(
62 struct loader_instance *inst,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -060063 struct loader_layer_properties *layer_prop);
Courtney Goeltzenleuchtered488302015-06-01 14:09:34 -060064
Jon Ashburn27cd5842015-05-12 17:26:48 -060065struct loader_struct loader = {0};
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080066
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -060067static void * VKAPI loader_GetInstanceProcAddr(VkInstance instance, const char * pName);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -060068static bool loader_init_ext_list(struct loader_extension_list *ext_info);
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -060069
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -060070enum loader_debug {
71 LOADER_INFO_BIT = VK_BIT(0),
72 LOADER_WARN_BIT = VK_BIT(1),
73 LOADER_PERF_BIT = VK_BIT(2),
74 LOADER_ERROR_BIT = VK_BIT(3),
75 LOADER_DEBUG_BIT = VK_BIT(4),
76};
77
78uint32_t g_loader_debug = 0;
79uint32_t g_loader_log_msgs = 0;
80
Jon Ashburn6301a0f2015-05-29 13:15:39 -060081//thread safety lock for accessing global data structures such as "loader"
82// all entrypoints on the instance chain need to be locked except GPA
Jon Ashburn2077e382015-06-29 11:25:34 -060083// additionally CreateDevice and DestroyDevice needs to be locked
Jon Ashburn6301a0f2015-05-29 13:15:39 -060084loader_platform_thread_mutex loader_lock;
85
86const VkLayerInstanceDispatchTable instance_disp = {
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -060087 .GetInstanceProcAddr = loader_GetInstanceProcAddr,
Jon Ashburn27cd5842015-05-12 17:26:48 -060088 .CreateInstance = loader_CreateInstance,
89 .DestroyInstance = loader_DestroyInstance,
90 .EnumeratePhysicalDevices = loader_EnumeratePhysicalDevices,
Chris Forbesbc0bb772015-06-21 22:55:02 +120091 .GetPhysicalDeviceFeatures = loader_GetPhysicalDeviceFeatures,
92 .GetPhysicalDeviceFormatInfo = loader_GetPhysicalDeviceFormatInfo,
93 .GetPhysicalDeviceLimits = loader_GetPhysicalDeviceLimits,
Tony Barbour59a47322015-06-24 16:06:58 -060094 .GetPhysicalDeviceProperties = loader_GetPhysicalDeviceProperties,
95 .GetPhysicalDevicePerformance = loader_GetPhysicalDevicePerformance,
96 .GetPhysicalDeviceQueueCount = loader_GetPhysicalDeviceQueueCount,
97 .GetPhysicalDeviceQueueProperties = loader_GetPhysicalDeviceQueueProperties,
98 .GetPhysicalDeviceMemoryProperties = loader_GetPhysicalDeviceMemoryProperties,
Tony Barbour59a47322015-06-24 16:06:58 -060099 .GetPhysicalDeviceExtensionProperties = loader_GetPhysicalDeviceExtensionProperties,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600100 .GetPhysicalDeviceLayerProperties = loader_GetPhysicalDeviceLayerProperties,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600101 .DbgCreateMsgCallback = loader_DbgCreateMsgCallback,
102 .DbgDestroyMsgCallback = loader_DbgDestroyMsgCallback,
Jon Ashburn27cd5842015-05-12 17:26:48 -0600103};
104
105LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_icd);
106LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_layer);
107LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_exts);
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700108
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600109void* loader_heap_alloc(
110 struct loader_instance *instance,
111 size_t size,
112 VkSystemAllocType alloc_type)
113{
114 if (instance && instance->alloc_callbacks.pfnAlloc) {
115 /* TODO: What should default alignment be? 1, 4, 8, other? */
116 return instance->alloc_callbacks.pfnAlloc(instance->alloc_callbacks.pUserData, size, 4, alloc_type);
117 }
118 return malloc(size);
119}
120
121void* loader_aligned_heap_alloc(
122 struct loader_instance *instance,
123 size_t size,
124 size_t alignment,
125 VkSystemAllocType alloc_type)
126{
127 if (!instance && instance->alloc_callbacks.pfnAlloc) {
128 return instance->alloc_callbacks.pfnAlloc(instance->alloc_callbacks.pUserData, size, alignment, alloc_type);
129 }
130 return aligned_alloc(size, alignment);
131}
132
133void loader_heap_free(
134 struct loader_instance *instance,
135 void *pMem)
136{
137 if (!instance && instance->alloc_callbacks.pfnFree) {
138 return instance->alloc_callbacks.pfnFree(instance->alloc_callbacks.pUserData, pMem);
139 }
140 return free(pMem);
141}
142
Jon Ashburnffad94d2015-06-30 14:46:22 -0700143static void loader_log(VkFlags msg_type, int32_t msg_code,
144 const char *format, ...)
145{
146 char msg[256];
147 va_list ap;
148 int ret;
149
150 if (!(msg_type & g_loader_log_msgs)) {
151 return;
152 }
153
154 va_start(ap, format);
155 ret = vsnprintf(msg, sizeof(msg), format, ap);
156 if ((ret >= (int) sizeof(msg)) || ret < 0) {
157 msg[sizeof(msg)-1] = '\0';
158 }
159 va_end(ap);
160
Ian Elliott4470a302015-02-17 10:33:47 -0700161#if defined(WIN32)
Jon Ashburnffad94d2015-06-30 14:46:22 -0700162 OutputDebugString(msg);
163#endif
164 fputs(msg, stderr);
165 fputc('\n', stderr);
166}
167
168#if defined(WIN32)
169/**
170* Find the list of registry files (names within a key) in key "location".
171*
172* This function looks in the registry (hive = DEFAULT_VK_REGISTRY_HIVE) key as given in "location"
173* for a list or name/values which are added to a returned list (function return value).
174* The DWORD values within the key must be 0 or they are skipped.
175* Function return is a string with a ';' seperated list of filenames.
176* Function return is NULL if no valid name/value pairs are found in the key,
177* or the key is not found.
178*
179* \returns
180* A string list of filenames as pointer.
181* When done using the returned string list, pointer should be freed.
182*/
183static char *loader_get_registry_files(const char *location)
184{
185 LONG rtn_value;
186 HKEY hive, key;
187 DWORD access_flags = KEY_QUERY_VALUE;
188 char name[2048];
189 char *out = NULL;
190
191 hive = DEFAULT_VK_REGISTRY_HIVE;
192 rtn_value = RegOpenKeyEx(hive, location, 0, access_flags, &key);
193 if (rtn_value != ERROR_SUCCESS) {
194 // We didn't find the key. Try the 32-bit hive (where we've seen the
195 // key end up on some people's systems):
196 access_flags |= KEY_WOW64_32KEY;
197 rtn_value = RegOpenKeyEx(hive, location, 0, access_flags, &key);
198 if (rtn_value != ERROR_SUCCESS) {
199 // We still couldn't find the key, so give up:
200 return NULL;
201 }
202 }
203
204 DWORD idx = 0;
205 DWORD name_size = sizeof(name);
206 DWORD value;
207 DWORD total_size = 4096;
208 DWORD value_size = sizeof(value);
209 while((rtn_value = RegEnumValue(key, idx++, name, &name_size, NULL, NULL, (LPBYTE) &value, &value_size)) == ERROR_SUCCESS) {
210 if (value_size == sizeof(value) && value == 0) {
211 if (out == NULL) {
212 out = malloc(total_size);
213 out[0] = '\0';
214 }
215 else if (strlen(out) + name_size + 1 > total_size) {
216 out = realloc(out, total_size * 2);
217 total_size *= 2;
218 }
219 if (out == NULL) {
220 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory, failed loader_get_registry_files");
221 return NULL;
222 }
223 if (strlen(out) == 0)
224 snprintf(out, name_size + 1, "%s", name);
225 else
226 snprintf(out + strlen(out), name_size + 1, "%c%s", PATH_SEPERATOR, name);
227 }
228 }
229 return out;
230}
231
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600232char *loader_get_registry_string(const HKEY hive,
233 const LPCTSTR sub_key,
234 const char *value)
235{
236 DWORD access_flags = KEY_QUERY_VALUE;
237 DWORD value_type;
238 HKEY key;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700239 LONG rtn_value;
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600240 char *rtn_str = NULL;
Tony Barbour18f71552015-04-22 11:36:22 -0600241 DWORD rtn_len = 0;
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600242 size_t allocated_len = 0;
243
244 rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
245 if (rtn_value != ERROR_SUCCESS) {
246 // We didn't find the key. Try the 32-bit hive (where we've seen the
247 // key end up on some people's systems):
248 access_flags |= KEY_WOW64_32KEY;
249 rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
250 if (rtn_value != ERROR_SUCCESS) {
251 // We still couldn't find the key, so give up:
252 return NULL;
253 }
254 }
255
256 rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
Ian Elliottf851ddf2015-04-28 15:57:32 -0600257 (PVOID) rtn_str, (LPDWORD) &rtn_len);
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600258 if (rtn_value == ERROR_SUCCESS) {
259 // If we get to here, we found the key, and need to allocate memory
260 // large enough for rtn_str, and query again:
261 allocated_len = rtn_len + 4;
262 rtn_str = malloc(allocated_len);
263 rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
Ian Elliottf851ddf2015-04-28 15:57:32 -0600264 (PVOID) rtn_str, (LPDWORD) &rtn_len);
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600265 if (rtn_value == ERROR_SUCCESS) {
266 // We added 4 extra bytes to rtn_str, so that we can ensure that
267 // the string is NULL-terminated (albeit, in a brute-force manner):
268 rtn_str[allocated_len-1] = '\0';
269 } else {
270 // This should never occur, but in case it does, clean up:
271 free(rtn_str);
272 rtn_str = NULL;
273 }
274 } // else - shouldn't happen, but if it does, return rtn_str, which is NULL
275
276 // Close the registry key that was opened:
277 RegCloseKey(key);
278
279 return rtn_str;
280}
281
282
Ian Elliott4470a302015-02-17 10:33:47 -0700283// For ICD developers, look in the registry, and look for an environment
284// variable for a path(s) where to find the ICD(s):
285static char *loader_get_registry_and_env(const char *env_var,
286 const char *registry_value)
287{
288 char *env_str = getenv(env_var);
289 size_t env_len = (env_str == NULL) ? 0 : strlen(env_str);
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600290 char *registry_str = NULL;
Tony Barbour18f71552015-04-22 11:36:22 -0600291 size_t registry_len = 0;
Ian Elliott4470a302015-02-17 10:33:47 -0700292 char *rtn_str = NULL;
293 size_t rtn_len;
294
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600295 registry_str = loader_get_registry_string(HKEY_LOCAL_MACHINE,
Ian Elliott06ebd752015-04-09 18:07:15 -0600296 "Software\\Vulkan",
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600297 registry_value);
Ian Elliottf851ddf2015-04-28 15:57:32 -0600298 registry_len = (registry_str) ? (DWORD) strlen(registry_str) : 0;
Ian Elliott4470a302015-02-17 10:33:47 -0700299
300 rtn_len = env_len + registry_len + 1;
301 if (rtn_len <= 2) {
302 // We found neither the desired registry value, nor the environment
303 // variable; return NULL:
304 return NULL;
305 } else {
306 // We found something, and so we need to allocate memory for the string
307 // to return:
308 rtn_str = malloc(rtn_len);
309 }
310
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600311 if (registry_len == 0) {
Ian Elliott4470a302015-02-17 10:33:47 -0700312 // We didn't find the desired registry value, and so we must have found
313 // only the environment variable:
314 _snprintf(rtn_str, rtn_len, "%s", env_str);
315 } else if (env_str != NULL) {
316 // We found both the desired registry value and the environment
317 // variable, so concatenate them both:
318 _snprintf(rtn_str, rtn_len, "%s;%s", registry_str, env_str);
319 } else {
320 // We must have only found the desired registry value:
321 _snprintf(rtn_str, rtn_len, "%s", registry_str);
322 }
323
Ian Elliott2de26bc2015-04-03 13:13:01 -0600324 if (registry_str) {
325 free(registry_str);
326 }
Ian Elliott4470a302015-02-17 10:33:47 -0700327
328 return(rtn_str);
329}
330#endif // WIN32
331
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600332bool compare_vk_extension_properties(const VkExtensionProperties *op1, const VkExtensionProperties *op2)
333{
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600334 return strcmp(op1->extName, op2->extName) == 0 ? true : false;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600335}
336
337/*
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600338 * Search the given ext_array for an extension
339 * matching the given vk_ext_prop
340 */
341bool has_vk_extension_property_array(
342 const VkExtensionProperties *vk_ext_prop,
343 const uint32_t count,
344 const VkExtensionProperties *ext_array)
345{
346 for (uint32_t i = 0; i < count; i++) {
347 if (compare_vk_extension_properties(vk_ext_prop, &ext_array[i]))
348 return true;
349 }
350 return false;
351}
352
353/*
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600354 * Search the given ext_list for an extension
355 * matching the given vk_ext_prop
356 */
357bool has_vk_extension_property(
358 const VkExtensionProperties *vk_ext_prop,
359 const struct loader_extension_list *ext_list)
360{
361 for (uint32_t i = 0; i < ext_list->count; i++) {
362 if (compare_vk_extension_properties(&ext_list->list[i].info, vk_ext_prop))
363 return true;
364 }
365 return false;
366}
367
368/*
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600369 * Search the given layer list for a layer
370 * matching the given layer name
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600371 */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600372static struct loader_layer_properties *get_layer_property(
373 const char *name,
374 const struct loader_layer_list *layer_list)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600375{
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600376 for (uint32_t i = 0; i < layer_list->count; i++) {
377 const VkLayerProperties *item = &layer_list->list[i].info;
378 if (strcmp(name, item->layerName) == 0)
379 return &layer_list->list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600380 }
381 return NULL;
382}
383
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600384static void loader_add_global_extensions(
Tony Barbour59a47322015-06-24 16:06:58 -0600385 const PFN_vkGetGlobalExtensionProperties fp_get_props,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600386 const char *lib_name,
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600387 const loader_platform_dl_handle lib_handle,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600388 const enum extension_origin origin,
389 struct loader_extension_list *ext_list)
390{
391 uint32_t i, count;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600392 struct loader_extension_property ext_props;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600393 VkExtensionProperties *extension_properties;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600394 VkResult res;
395
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600396 res = fp_get_props(NULL, &count, NULL);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600397 if (res != VK_SUCCESS) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600398 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extension count from %s", lib_name);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600399 return;
400 }
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600401
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600402 extension_properties = loader_stack_alloc(count * sizeof(VkExtensionProperties));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600403
404 res = fp_get_props(NULL, &count, extension_properties);
405 if (res != VK_SUCCESS) {
406 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extensions from %s", lib_name);
407 return;
408 }
Tony Barbour59a47322015-06-24 16:06:58 -0600409
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600410 for (i = 0; i < count; i++) {
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600411 memset(&ext_props, 0, sizeof(ext_props));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600412 memcpy(&ext_props.info, &extension_properties[i], sizeof(VkExtensionProperties));
413 //TODO eventually get this from the layer config file
414 ext_props.origin = origin;
415 ext_props.lib_name = lib_name;
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600416
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600417 char spec_version[64], version[64];
418
419 snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
420 VK_MAJOR(ext_props.info.specVersion),
421 VK_MINOR(ext_props.info.specVersion),
422 VK_PATCH(ext_props.info.specVersion));
423 snprintf(version, sizeof(version), "%d.%d.%d",
424 VK_MAJOR(ext_props.info.version),
425 VK_MINOR(ext_props.info.version),
426 VK_PATCH(ext_props.info.version));
427
428 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
429 "Global Extension: %s (%s) version %s, Vulkan version %s",
430 ext_props.info.extName, lib_name, version, spec_version);
431 loader_add_to_ext_list(ext_list, 1, &ext_props);
432 }
433
434 return;
435}
436
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600437/* TODO: Need to use loader_heap_alloc or loader_stack_alloc */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600438static void loader_add_global_layer_properties(
439 const char *lib_name,
440 const loader_platform_dl_handle lib_handle,
441 struct loader_layer_list *layer_list)
442{
443 uint32_t i, count;
444 VkLayerProperties *layer_properties;
445 PFN_vkGetGlobalExtensionProperties fp_get_ext_props;
446 PFN_vkGetGlobalLayerProperties fp_get_layer_props;
447 VkResult res;
448
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600449 /*
450 * A layer must export GetGlobalLayerProperties if it has any global extensions.
451 * If a layer does not export a vkGetGlobalLayerProperties then it may
452 * only support vkGetPhysicalDeviceLayerProperties and nothing needs to
453 * be done here.
454 */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600455 fp_get_layer_props = loader_platform_get_proc_address(lib_handle, "vkGetGlobalLayerProperties");
456 if (!fp_get_layer_props) {
457 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
458 "Couldn't dlsym vkGetGlobalLayerProperties from library %s",
459 lib_name);
460 return;
461 }
462
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600463 fp_get_ext_props = loader_platform_get_proc_address(lib_handle, "vkGetGlobalExtensionProperties");
464 if (!fp_get_ext_props) {
465 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
466 "Couldn't dlsym vkGetGlobalExtensionProperties from library %s",
467 lib_name);
468 }
469
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600470 res = fp_get_layer_props(&count, NULL);
471 if (res != VK_SUCCESS) {
472 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global layer count from %s", lib_name);
473 return;
474 }
475
476 if (count == 0) {
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600477 /*
478 * Layer exported vkGetGlobalLayerProperties but didn't have any to report,
479 * nothing to do here.
480 */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600481 return;
482 }
483
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600484 layer_properties = loader_stack_alloc(count * sizeof(VkLayerProperties));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600485
486 res = fp_get_layer_props(&count, layer_properties);
487 if (res != VK_SUCCESS) {
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600488 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Error getting %d global layer properties from %s. %s line %d",
489 count, lib_name, __FILE__, __LINE__);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600490 return;
491 }
492
493 for (i = 0; i < count; i++) {
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600494 struct loader_layer_properties layer;
495
496 memset(&layer, 0, sizeof(layer));
497
498 layer.lib_info.lib_name = malloc(strlen(lib_name) + 1);
499 if (layer.lib_info.lib_name == NULL) {
500 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "out of memory: layer library %s: %s line %d",
501 lib_name, __FILE__, __LINE__);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600502 return;
503 }
504
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600505 strcpy(layer.lib_info.lib_name, lib_name);
506 memcpy(&layer.info, &layer_properties[i], sizeof(VkLayerProperties));
507 loader_init_ext_list(&layer.instance_extension_list);
508 loader_init_ext_list(&layer.device_extension_list);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600509 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Collecting global extensions for layer %s (%s)",
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600510 layer.info.layerName, layer.info.description);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600511
512 loader_add_global_extensions(
513 fp_get_ext_props,
514 lib_name,
515 lib_handle,
516 VK_EXTENSION_ORIGIN_LAYER,
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600517 &layer.instance_extension_list);
518
519 loader_add_to_layer_list(layer_list, 1, &layer);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600520 }
521
522 return;
523}
524
525static void loader_add_physical_device_extensions(
526 PFN_vkGetPhysicalDeviceExtensionProperties get_phys_dev_ext_props,
527 VkPhysicalDevice physical_device,
528 const enum extension_origin origin,
529 const char *lib_name,
530 struct loader_extension_list *ext_list)
531{
532 uint32_t i, count;
533 VkResult res;
534 struct loader_extension_property ext_props;
535 VkExtensionProperties *extension_properties;
536
537 memset(&ext_props, 0, sizeof(ext_props));
538 ext_props.origin = origin;
539 ext_props.lib_name = lib_name;
540
541 if (get_phys_dev_ext_props) {
542 res = get_phys_dev_ext_props(physical_device, NULL, &count, NULL);
543 if (res == VK_SUCCESS && count > 0) {
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600544
545 extension_properties = loader_stack_alloc(count * sizeof(VkExtensionProperties));
546
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600547 res = get_phys_dev_ext_props(physical_device, NULL, &count, extension_properties);
548 for (i = 0; i < count; i++) {
549 char spec_version[64], version[64];
550
551 memcpy(&ext_props.info, &extension_properties[i], sizeof(VkExtensionProperties));
552
553 snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
554 VK_MAJOR(ext_props.info.specVersion),
555 VK_MINOR(ext_props.info.specVersion),
556 VK_PATCH(ext_props.info.specVersion));
557 snprintf(version, sizeof(version), "%d.%d.%d",
558 VK_MAJOR(ext_props.info.version),
559 VK_MINOR(ext_props.info.version),
560 VK_PATCH(ext_props.info.version));
561
562 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
563 "PhysicalDevice Extension: %s (%s) version %s, Vulkan version %s",
564 ext_props.info.extName, lib_name, version, spec_version);
565 loader_add_to_ext_list(ext_list, 1, &ext_props);
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600566 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600567 } else {
568 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Error getting physical device extension info count from Layer %s", ext_props.lib_name);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600569 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600570 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600571
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600572 return;
573}
574
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600575static void loader_add_physical_device_layer_properties(
576 struct loader_icd *icd,
577 char *lib_name,
578 const loader_platform_dl_handle lib_handle)
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600579{
580 uint32_t i, count;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600581 VkLayerProperties *layer_properties;
582 PFN_vkGetPhysicalDeviceExtensionProperties fp_get_ext_props;
583 PFN_vkGetPhysicalDeviceLayerProperties fp_get_layer_props;
584 VkPhysicalDevice gpu = icd->gpus[0];
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600585 VkResult res;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600586
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600587 fp_get_ext_props = loader_platform_get_proc_address(lib_handle, "vkGetPhysicalDeviceExtensionProperties");
588 if (!fp_get_ext_props) {
589 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
590 "Couldn't dlsym vkGetPhysicalDeviceExtensionProperties from library %s",
591 lib_name);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600592 return;
593 }
594
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600595 fp_get_layer_props = loader_platform_get_proc_address(lib_handle, "vkGetPhysicalDeviceLayerProperties");
596 if (!fp_get_layer_props) {
597 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
598 "Couldn't dlsym vkGetPhysicalDeviceLayerProperties from library %s",
599 lib_name);
600 return;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600601 }
602
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600603 /*
604 * NOTE: We assume that all GPUs of an ICD support the same PhysicalDevice
605 * layers and extensions. Thus only ask for info about the first gpu.
606 */
607 res = fp_get_layer_props(gpu, &count, NULL);
608 if (res != VK_SUCCESS) {
609 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Error getting PhysicalDevice layer count from %s", lib_name);
610 return;
611 }
612
613 if (count == 0) {
614 return;
615 }
616
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600617 layer_properties = loader_stack_alloc(count * sizeof(VkLayerProperties));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600618
619 res = fp_get_layer_props(gpu, &count, layer_properties);
620 if (res != VK_SUCCESS) {
621 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Error getting %d PhysicalDevice layer properties from %s",
622 count, lib_name);
623 return;
624 }
625
626 for (i = 0; i < count; i++) {
627 struct loader_layer_properties layer;
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600628
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600629 memset(&layer, 0, sizeof(struct loader_layer_properties));
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600630
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600631 layer.lib_info.lib_name = lib_name;
632 memcpy(&layer.info, &layer_properties[i], sizeof(VkLayerProperties));
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600633
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600634 loader_init_ext_list(&layer.instance_extension_list);
635 loader_init_ext_list(&layer.device_extension_list);
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600636
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600637 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Collecting PhysicalDevice extensions for layer %s (%s)",
638 layer.info.layerName, layer.info.description);
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600639
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600640 loader_add_physical_device_extensions(
641 fp_get_ext_props,
642 icd->gpus[i],
643 VK_EXTENSION_ORIGIN_LAYER,
644 lib_name,
645 &layer.device_extension_list);
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600646
647 loader_add_to_layer_list(&icd->layer_properties_cache, 1, &layer);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600648 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600649 return;
650}
651
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600652static bool loader_init_ext_list(struct loader_extension_list *ext_info)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600653{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600654 ext_info->capacity = 32 * sizeof(struct loader_extension_property);
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600655 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600656 ext_info->list = malloc(ext_info->capacity);
657 if (ext_info->list == NULL) {
658 return false;
659 }
660 memset(ext_info->list, 0, ext_info->capacity);
661 ext_info->count = 0;
662 return true;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600663}
664
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -0600665void loader_destroy_ext_list(struct loader_extension_list *ext_info)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600666{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600667 free(ext_info->list);
668 ext_info->count = 0;
669 ext_info->capacity = 0;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600670}
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600671
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600672/**
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600673 * Search the given search_list for any layers in the props list.
674 * Add these to the output layer_list. Don't add duplicates to the output layer_list.
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600675 */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600676static void loader_add_layer_names_to_list(
677 struct loader_layer_list *output_list,
678 uint32_t name_count,
679 const char * const *names,
680 const struct loader_layer_list *search_list)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600681{
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600682 struct loader_layer_properties *layer_prop;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600683
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600684 for (uint32_t i = 0; i < name_count; i++) {
685 const char *search_target = names[i];
686 layer_prop = get_layer_property(search_target, search_list);
687 if (!layer_prop) {
688 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unable to find extension %s", search_target);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600689 continue;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600690 }
691
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600692 loader_add_to_layer_list(output_list, 1, layer_prop);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600693 }
694}
695
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600696/*
697 * Append non-duplicate extension properties defined in prop_list
698 * to the given ext_info list
699 */
700void loader_add_to_ext_list(
701 struct loader_extension_list *ext_list,
702 uint32_t prop_list_count,
703 const struct loader_extension_property *props)
704{
705 uint32_t i;
706 struct loader_extension_property *cur_ext;
707
708 if (ext_list->list == NULL || ext_list->capacity == 0) {
709 loader_init_ext_list(ext_list);
710 }
711
712 if (ext_list->list == NULL)
713 return;
714
715 for (i = 0; i < prop_list_count; i++) {
716 cur_ext = (struct loader_extension_property *) &props[i];
717
718 // look for duplicates
719 if (has_vk_extension_property(&cur_ext->info, ext_list)) {
720 continue;
721 }
722
723 // add to list at end
724 // check for enough capacity
725 if (ext_list->count * sizeof(struct loader_extension_property)
726 >= ext_list->capacity) {
727 // double capacity
728 ext_list->capacity *= 2;
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600729 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600730 ext_list->list = realloc(ext_list->list, ext_list->capacity);
731 }
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600732
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600733 memcpy(&ext_list->list[ext_list->count], cur_ext, sizeof(struct loader_extension_property));
734 ext_list->count++;
735 }
736}
737
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600738/*
739 * Manage lists of VkLayerProperties
740 */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600741static bool loader_init_layer_list(struct loader_layer_list *list)
742{
743 list->capacity = 32 * sizeof(struct loader_layer_properties);
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600744 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600745 list->list = malloc(list->capacity);
746 if (list->list == NULL) {
747 return false;
748 }
749 memset(list->list, 0, list->capacity);
750 list->count = 0;
751 return true;
752}
753
754void loader_destroy_layer_list(struct loader_layer_list *layer_list)
755{
756 free(layer_list->list);
757 layer_list->count = 0;
758 layer_list->capacity = 0;
759}
760
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600761/*
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600762 * Manage list of layer libraries (loader_lib_info)
763 */
764static bool loader_init_layer_library_list(struct loader_layer_library_list *list)
765{
766 list->capacity = 32 * sizeof(struct loader_lib_info);
767 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
768 list->list = malloc(list->capacity);
769 if (list->list == NULL) {
770 return false;
771 }
772 memset(list->list, 0, list->capacity);
773 list->count = 0;
774 return true;
775}
776
777void loader_destroy_layer_library_list(struct loader_layer_library_list *list)
778{
779 for (uint32_t i = 0; i < list->count; i++) {
780 free(list->list[i].lib_name);
781 }
782 free(list->list);
783 list->count = 0;
784 list->capacity = 0;
785}
786
787void loader_add_to_layer_library_list(
788 struct loader_layer_library_list *list,
789 uint32_t item_count,
790 const struct loader_lib_info *new_items)
791{
792 uint32_t i;
793 struct loader_lib_info *item;
794
795 if (list->list == NULL || list->capacity == 0) {
796 loader_init_layer_library_list(list);
797 }
798
799 if (list->list == NULL)
800 return;
801
802 for (i = 0; i < item_count; i++) {
803 item = (struct loader_lib_info *) &new_items[i];
804
805 // look for duplicates
806 for (uint32_t j = 0; j < list->count; j++) {
807 if (strcmp(list->list[i].lib_name, new_items->lib_name) == 0) {
808 continue;
809 }
810 }
811
812 // add to list at end
813 // check for enough capacity
814 if (list->count * sizeof(struct loader_lib_info)
815 >= list->capacity) {
816 // double capacity
817 list->capacity *= 2;
818 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
819 list->list = realloc(list->list, list->capacity);
820 }
821
822 memcpy(&list->list[list->count], item, sizeof(struct loader_lib_info));
823 list->count++;
824 }
825}
826
827/*
828 * Add's library indicated by lib_name to list if it
829 * implements vkGetGlobalLayerProperties or
830 * vkGetPhysicalDeviceLayerProperties.
831 */
832static void loader_add_layer_library(
833 struct loader_instance *instance,
834 const char *lib_name,
835 const loader_platform_dl_handle lib_handle,
836 struct loader_layer_library_list *list)
837{
838 struct loader_lib_info *library_info;
839 PFN_vkGetPhysicalDeviceLayerProperties fp_get_phydev_props;
840 PFN_vkGetGlobalLayerProperties fp_get_layer_props;
841
842 fp_get_layer_props = loader_platform_get_proc_address(lib_handle, "vkGetGlobalLayerProperties");
843 fp_get_phydev_props = loader_platform_get_proc_address(lib_handle, "vkGetPhysicalDeviceLayerProperties");
844
845 if (!fp_get_layer_props && !fp_get_phydev_props)
846 return;
847
848 /*
849 * Allocate enough space for the library name to
850 * immediately follow the loader_lib_info structure
851 */
852 library_info = loader_heap_alloc(instance, sizeof(struct loader_lib_info) + strlen(lib_name) + 1, VK_SYSTEM_ALLOC_TYPE_INTERNAL);
853 if (!library_info) {
854 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
855 "Malloc for layer library list failed: %s line: %d", __FILE__, __LINE__);
856 return;
857 }
858 memset(library_info, 0, sizeof(struct loader_lib_info));
859 library_info->lib_name = (char *) &library_info[1];
860 strcpy(library_info->lib_name, lib_name);
861
862 loader_add_to_layer_library_list(list, 1, library_info);
863}
864
865/*
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600866 * Search the given layer list for a list
867 * matching the given VkLayerProperties
868 */
869bool has_vk_layer_property(
870 const VkLayerProperties *vk_layer_prop,
871 const struct loader_layer_list *list)
872{
873 for (uint32_t i = 0; i < list->count; i++) {
874 if (strcmp(vk_layer_prop->layerName, list->list[i].info.layerName) == 0)
875 return true;
876 }
877 return false;
878}
879
880/*
881 * Search the given layer list for a layer
882 * matching the given name
883 */
884bool has_layer_name(
885 const char *name,
886 const struct loader_layer_list *list)
887{
888 for (uint32_t i = 0; i < list->count; i++) {
889 if (strcmp(name, list->list[i].info.layerName) == 0)
890 return true;
891 }
892 return false;
893}
894
895/*
896 * Append non-duplicate layer properties defined in prop_list
897 * to the given layer_info list
898 */
899void loader_add_to_layer_list(
900 struct loader_layer_list *list,
901 uint32_t prop_list_count,
902 const struct loader_layer_properties *props)
903{
904 uint32_t i;
905 struct loader_layer_properties *layer;
906
907 if (list->list == NULL || list->capacity == 0) {
908 loader_init_layer_list(list);
909 }
910
911 if (list->list == NULL)
912 return;
913
914 for (i = 0; i < prop_list_count; i++) {
915 layer = (struct loader_layer_properties *) &props[i];
916
917 // look for duplicates
918 if (has_vk_layer_property(&layer->info, list)) {
919 continue;
920 }
921
922 // add to list at end
923 // check for enough capacity
924 if (list->count * sizeof(struct loader_layer_properties)
925 >= list->capacity) {
926 // double capacity
927 list->capacity *= 2;
928 list->list = realloc(list->list, list->capacity);
929 }
930
931 memcpy(&list->list[list->count], layer, sizeof(struct loader_layer_properties));
932 list->count++;
933 }
934}
935
936/*
937 * Search the search_list for any layer with
938 * a name that matches the given layer_name.
939 * Add all matching layers to the found_list
940 * Do not add if found VkLayerProperties is already
941 * on the found_list.
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600942 */
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600943static void loader_find_layer_name_add_list(
944 const char *name,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600945 const struct loader_layer_list *search_list,
946 struct loader_layer_list *found_list)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600947{
948 for (uint32_t i = 0; i < search_list->count; i++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600949 struct loader_layer_properties *layer_prop = &search_list->list[i];
950 if (0 == strcmp(layer_prop->info.layerName, name)) {
951 /* Found a layer with the same name, add to found_list */
952 loader_add_to_layer_list(found_list, 1, layer_prop);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600953 }
954 }
955}
956
957bool loader_is_extension_scanned(const VkExtensionProperties *ext_prop)
Jon Ashburnfc2e38c2015-04-14 09:15:32 -0600958{
959 uint32_t i;
960
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600961 for (i = 0; i < loader.global_extensions.count; i++) {
962 if (compare_vk_extension_properties(&loader.global_extensions.list[i].info, ext_prop))
Jon Ashburnfc2e38c2015-04-14 09:15:32 -0600963 return true;
964 }
965 return false;
966}
967
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600968/*
969 * For global exenstions implemented within the loader (i.e. DEBUG_REPORT
970 * the extension must provide two entry points for the loader to use:
971 * - "trampoline" entry point - this is the address returned by GetProcAddr
972 * and will always do what's necessary to support a global call.
973 * - "terminator" function - this function will be put at the end of the
974 * instance chain and will contain the necessary logica to call / process
975 * the extension for the appropriate ICDs that are available.
976 * There is no generic mechanism for including these functions, the references
977 * must be placed into the appropriate loader entry points.
978 * GetInstanceProcAddr: call extension GetInstanceProcAddr to check for GetProcAddr requests
979 * loader_coalesce_extensions(void) - add extension records to the list of global
980 * extension available to the app.
981 * instance_disp - add function pointer for terminator function to this array.
982 * The extension itself should be in a separate file that will be
983 * linked directly with the loader.
984 */
Jon Ashburn27cd5842015-05-12 17:26:48 -0600985void loader_coalesce_extensions(void)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600986{
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600987 struct loader_scanned_icds *icd_list = loader.scanned_icd_list;
988
989 // traverse scanned icd list adding non-duplicate extensions to the list
990 while (icd_list != NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600991 loader_add_to_ext_list(&loader.global_extensions,
992 icd_list->global_extension_list.count,
993 icd_list->global_extension_list.list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600994 icd_list = icd_list->next;
995 };
996
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600997 // Traverse loader's extensions, adding non-duplicate extensions to the list
998 debug_report_add_instance_extensions(&loader.global_extensions);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600999}
1000
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001001static struct loader_icd *loader_get_icd_and_device(const VkDevice device,
1002 struct loader_device **found_dev)
1003{
1004 *found_dev = NULL;
1005 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
1006 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
1007 for (struct loader_device *dev = icd->logical_device_list; dev; dev = dev->next)
1008 if (dev->device == device) {
1009 *found_dev = dev;
1010 return icd;
1011 }
1012 }
1013 }
1014 return NULL;
1015}
1016
1017static void loader_destroy_logical_device(struct loader_device *dev)
1018{
1019 free(dev->app_extension_props);
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001020 if (dev->activated_layer_list.count)
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001021 loader_destroy_layer_list(&dev->activated_layer_list);
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001022 free(dev);
1023}
1024
1025static struct loader_device *loader_add_logical_device(const VkDevice dev, struct loader_device **device_list)
1026{
1027 struct loader_device *new_dev;
1028
1029 new_dev = malloc(sizeof(struct loader_device));
1030 if (!new_dev) {
1031 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc struct laoder-device");
1032 return NULL;
1033 }
1034
1035 memset(new_dev, 0, sizeof(struct loader_device));
1036
1037 new_dev->next = *device_list;
1038 new_dev->device = dev;
1039 *device_list = new_dev;
1040 return new_dev;
1041}
1042
1043void loader_remove_logical_device(VkDevice device)
1044{
1045 struct loader_device *found_dev, *dev, *prev_dev;
1046 struct loader_icd *icd;
1047 icd = loader_get_icd_and_device(device, &found_dev);
1048
1049 if (!icd || !found_dev)
1050 return;
1051
1052 prev_dev = NULL;
1053 dev = icd->logical_device_list;
1054 while (dev && dev != found_dev) {
1055 prev_dev = dev;
1056 dev = dev->next;
1057 }
1058
1059 if (prev_dev)
1060 prev_dev->next = found_dev->next;
1061 else
1062 icd->logical_device_list = found_dev->next;
1063 loader_destroy_logical_device(found_dev);
1064}
1065
1066
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001067static void loader_icd_destroy(
1068 struct loader_instance *ptr_inst,
1069 struct loader_icd *icd)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001070{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001071 ptr_inst->total_icd_count--;
Jon Ashburn128f9422015-05-28 19:16:58 -06001072 free(icd->gpus);
Courtney Goeltzenleuchter1f157ac2015-06-14 19:57:15 -06001073 for (struct loader_device *dev = icd->logical_device_list; dev; ) {
1074 struct loader_device *next_dev = dev->next;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001075 loader_destroy_logical_device(dev);
Courtney Goeltzenleuchter1f157ac2015-06-14 19:57:15 -06001076 dev = next_dev;
1077 }
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001078
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001079 free(icd);
1080}
1081
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001082static struct loader_icd * loader_icd_create(const struct loader_scanned_icds *scanned)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001083{
1084 struct loader_icd *icd;
1085
1086 icd = malloc(sizeof(*icd));
1087 if (!icd)
1088 return NULL;
1089
Courtney Goeltzenleuchter55001bb2014-10-28 10:29:27 -06001090 memset(icd, 0, sizeof(*icd));
1091
Jon Ashburn46d1f582015-01-28 11:01:35 -07001092 icd->scanned_icds = scanned;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001093
1094 return icd;
1095}
1096
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001097static struct loader_icd *loader_icd_add(
1098 struct loader_instance *ptr_inst,
1099 const struct loader_scanned_icds *scanned)
Chia-I Wu13a61a52014-08-04 11:18:20 +08001100{
1101 struct loader_icd *icd;
1102
Jon Ashburn46d1f582015-01-28 11:01:35 -07001103 icd = loader_icd_create(scanned);
Chia-I Wu13a61a52014-08-04 11:18:20 +08001104 if (!icd)
1105 return NULL;
1106
Chia-I Wu13a61a52014-08-04 11:18:20 +08001107 /* prepend to the list */
Jon Ashburn46888392015-01-29 15:45:51 -07001108 icd->next = ptr_inst->icds;
1109 ptr_inst->icds = icd;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001110 ptr_inst->total_icd_count++;
Chia-I Wu13a61a52014-08-04 11:18:20 +08001111
1112 return icd;
1113}
1114
Jon Ashburn46d1f582015-01-28 11:01:35 -07001115static void loader_scanned_icd_add(const char *filename)
1116{
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001117 loader_platform_dl_handle handle;
Jon Ashburn3da71f22015-05-14 12:43:38 -06001118 void *fp_create_inst;
Tony Barbour59a47322015-06-24 16:06:58 -06001119 void *fp_get_global_ext_props;
Tony Barbour59a47322015-06-24 16:06:58 -06001120 void *fp_get_device_ext_props;
Jon Ashburn953bb3c2015-06-10 16:11:42 -06001121 PFN_vkGPA fp_get_proc_addr;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001122 struct loader_scanned_icds *new_node;
1123
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001124 // Used to call: dlopen(filename, RTLD_LAZY);
1125 handle = loader_platform_open_library(filename);
Jon Ashburn46d1f582015-01-28 11:01:35 -07001126 if (!handle) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001127 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_open_library_error(filename));
Jon Ashburn46d1f582015-01-28 11:01:35 -07001128 return;
1129 }
1130
1131#define LOOKUP(func_ptr, func) do { \
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06001132 func_ptr = (PFN_vk ##func) loader_platform_get_proc_address(handle, "vk" #func); \
Jon Ashburn46d1f582015-01-28 11:01:35 -07001133 if (!func_ptr) { \
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001134 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
Jon Ashburn46d1f582015-01-28 11:01:35 -07001135 return; \
1136 } \
1137} while (0)
1138
Jon Ashburn46888392015-01-29 15:45:51 -07001139 LOOKUP(fp_create_inst, CreateInstance);
Tony Barbour59a47322015-06-24 16:06:58 -06001140 LOOKUP(fp_get_global_ext_props, GetGlobalExtensionProperties);
Tony Barbour59a47322015-06-24 16:06:58 -06001141 LOOKUP(fp_get_device_ext_props, GetPhysicalDeviceExtensionProperties);
Jon Ashburn953bb3c2015-06-10 16:11:42 -06001142 LOOKUP(fp_get_proc_addr, GetDeviceProcAddr);
Jon Ashburn46d1f582015-01-28 11:01:35 -07001143#undef LOOKUP
1144
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001145 new_node = (struct loader_scanned_icds *) malloc(sizeof(struct loader_scanned_icds)
1146 + strlen(filename) + 1);
Jon Ashburn46d1f582015-01-28 11:01:35 -07001147 if (!new_node) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001148 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
Jon Ashburn46d1f582015-01-28 11:01:35 -07001149 return;
1150 }
1151
1152 new_node->handle = handle;
Jon Ashburn46888392015-01-29 15:45:51 -07001153 new_node->CreateInstance = fp_create_inst;
Tony Barbour59a47322015-06-24 16:06:58 -06001154 new_node->GetGlobalExtensionProperties = fp_get_global_ext_props;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001155 loader_init_ext_list(&new_node->global_extension_list);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001156 loader_init_ext_list(&new_node->device_extension_list);
Jon Ashburn46d1f582015-01-28 11:01:35 -07001157 new_node->next = loader.scanned_icd_list;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001158
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001159 new_node->lib_name = (char *) (new_node + 1);
1160 if (!new_node->lib_name) {
1161 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
1162 return;
1163 }
1164 strcpy(new_node->lib_name, filename);
1165
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001166 loader.scanned_icd_list = new_node;
1167
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001168 loader_add_global_extensions(
Tony Barbour59a47322015-06-24 16:06:58 -06001169 (PFN_vkGetGlobalExtensionProperties) fp_get_global_ext_props,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001170 new_node->lib_name,
Jon Ashburn953bb3c2015-06-10 16:11:42 -06001171 handle,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001172 VK_EXTENSION_ORIGIN_ICD,
1173 &new_node->global_extension_list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001174}
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001175
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001176static struct loader_extension_list *loader_global_extensions(const char *pLayerName)
1177{
1178 if (pLayerName == NULL || (strlen(pLayerName) == 0)) {
1179 return &loader.global_extensions;
1180 }
1181
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06001182 /* Find and return global extension list for given layer */
1183 for (uint32_t i = 0; i < loader.global_layer_list.count; i++) {
1184 struct loader_layer_properties *work_layer = &loader.global_layer_list.list[i];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001185 if (strcmp(work_layer->info.layerName, pLayerName) == 0) {
1186 return &work_layer->instance_extension_list;
1187 }
1188 }
1189
1190 return NULL;
1191}
1192
1193static struct loader_layer_list *loader_global_layers()
1194{
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06001195 return &loader.global_layer_list;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001196}
1197
1198static void loader_physical_device_layers(
1199 struct loader_icd *icd,
1200 uint32_t *count,
1201 struct loader_layer_list **list)
1202{
1203 *count = icd->layer_properties_cache.count;
1204 *list = &icd->layer_properties_cache;
1205}
1206
1207static void loader_physical_device_extensions(
1208 struct loader_icd *icd,
1209 uint32_t gpu_idx,
1210 const char *layer_name,
1211 uint32_t *count,
1212 struct loader_extension_list **list)
1213{
1214 if (layer_name == NULL || (strlen(layer_name) == 0)) {
1215 *count = icd->device_extension_cache[gpu_idx].count;
1216 *list = &icd->device_extension_cache[gpu_idx];
1217 return;
1218 }
1219 for (uint32_t i = 0; i < icd->layer_properties_cache.count; i++) {
1220 if (strcmp(layer_name, icd->layer_properties_cache.list[i].info.layerName) == 0) {
1221 *count = icd->layer_properties_cache.list[i].device_extension_list.count;
1222 *list = &icd->layer_properties_cache.list[i].device_extension_list;
1223 }
1224 }
1225}
1226
Jon Ashburn3da71f22015-05-14 12:43:38 -06001227static void loader_icd_init_entrys(struct loader_icd *icd,
1228 struct loader_scanned_icds *scanned_icds)
1229{
1230 /* initialize entrypoint function pointers */
1231
1232 #define LOOKUP(func) do { \
1233 icd->func = (PFN_vk ##func) loader_platform_get_proc_address(scanned_icds->handle, "vk" #func); \
1234 if (!icd->func) { \
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001235 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
Jon Ashburn3da71f22015-05-14 12:43:38 -06001236 return; \
1237 } \
1238 } while (0)
1239
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001240 /* could change this to use GetInstanceProcAddr in driver instead of dlsym */
1241 LOOKUP(GetDeviceProcAddr);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001242 LOOKUP(DestroyInstance);
1243 LOOKUP(EnumeratePhysicalDevices);
Chris Forbesbc0bb772015-06-21 22:55:02 +12001244 LOOKUP(GetPhysicalDeviceFeatures);
1245 LOOKUP(GetPhysicalDeviceFormatInfo);
1246 LOOKUP(GetPhysicalDeviceLimits);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001247 LOOKUP(CreateDevice);
Tony Barbour59a47322015-06-24 16:06:58 -06001248 LOOKUP(GetPhysicalDeviceProperties);
1249 LOOKUP(GetPhysicalDeviceMemoryProperties);
1250 LOOKUP(GetPhysicalDevicePerformance);
1251 LOOKUP(GetPhysicalDeviceQueueCount);
1252 LOOKUP(GetPhysicalDeviceQueueProperties);
1253 LOOKUP(GetPhysicalDeviceExtensionProperties);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001254 LOOKUP(DbgCreateMsgCallback);
1255 LOOKUP(DbgDestroyMsgCallback);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001256#undef LOOKUP
1257
1258 return;
1259}
1260
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001261static void loader_debug_init(void)
1262{
1263 const char *env;
1264
1265 if (g_loader_debug > 0)
1266 return;
1267
1268 g_loader_debug = 0;
1269
1270 /* parse comma-separated debug options */
1271 env = getenv("LOADER_DEBUG");
1272 while (env) {
1273 const char *p = strchr(env, ',');
1274 size_t len;
1275
1276 if (p)
1277 len = p - env;
1278 else
1279 len = strlen(env);
1280
1281 if (len > 0) {
1282 if (strncmp(env, "warn", len) == 0) {
1283 g_loader_debug |= LOADER_WARN_BIT;
1284 g_loader_log_msgs |= VK_DBG_REPORT_WARN_BIT;
1285 } else if (strncmp(env, "info", len) == 0) {
1286 g_loader_debug |= LOADER_INFO_BIT;
1287 g_loader_log_msgs |= VK_DBG_REPORT_INFO_BIT;
1288 } else if (strncmp(env, "perf", len) == 0) {
1289 g_loader_debug |= LOADER_PERF_BIT;
1290 g_loader_log_msgs |= VK_DBG_REPORT_PERF_WARN_BIT;
1291 } else if (strncmp(env, "error", len) == 0) {
1292 g_loader_debug |= LOADER_ERROR_BIT;
1293 g_loader_log_msgs |= VK_DBG_REPORT_ERROR_BIT;
1294 } else if (strncmp(env, "debug", len) == 0) {
1295 g_loader_debug |= LOADER_DEBUG_BIT;
1296 g_loader_log_msgs |= VK_DBG_REPORT_DEBUG_BIT;
1297 }
1298 }
1299
1300 if (!p)
1301 break;
1302
1303 env = p + 1;
1304 }
1305}
1306
Jon Ashburn2077e382015-06-29 11:25:34 -06001307struct loader_manifest_files {
1308 uint32_t count;
1309 char **filename_list;
1310};
1311
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001312/**
Jon Ashburn2077e382015-06-29 11:25:34 -06001313 * Get next file or dirname given a string list or registry key path
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001314 *
1315 * \returns
Jon Ashburn2077e382015-06-29 11:25:34 -06001316 * A pointer to first char in the next path.
1317 * The next path (or NULL) in the list is returned in next_path.
1318 * Note: input string is modified in some cases. PASS IN A COPY!
1319 */
Jon Ashburn2077e382015-06-29 11:25:34 -06001320static char *loader_get_next_path(char *path)
1321{
1322 uint32_t len;
1323 char *next;
1324
1325 if (path == NULL)
1326 return NULL;
1327 next = strchr(path, PATH_SEPERATOR);
1328 if (next == NULL) {
1329 len = (uint32_t) strlen(path);
1330 next = path + len;
1331 }
1332 else {
1333 *next = '\0';
1334 next++;
1335 }
1336
1337 return next;
1338}
1339
1340/**
1341 * Given a filename (file) and a list of paths (dir), try to find an existing
1342 * file in the paths. If filename already is a path then no
1343 * searching in the given paths.
1344 *
1345 * \returns
1346 * A string in out_fullpath of either the full path or file.
1347 * Side effect is that dir string maybe modified.
1348 */
1349static void loader_get_fullpath(const char *file,
1350 char *dir,
1351 size_t out_size,
1352 char *out_fullpath)
1353{
1354 char *next_dir;
1355 if (strchr(file,DIRECTORY_SYMBOL) == NULL) {
1356 //find file exists with prepending given path
1357 while (*dir) {
1358 next_dir = loader_get_next_path(dir);
1359 snprintf(out_fullpath, out_size, "%s%c%s",
1360 dir, DIRECTORY_SYMBOL, file);
1361 if (loader_platform_file_exists(out_fullpath)) {
1362 return;
1363 }
1364 dir = next_dir;
1365 }
1366 }
1367 snprintf(out_fullpath, out_size, "%s", file);
1368}
1369
1370/**
1371 * Read a JSON file into a buffer.
1372 *
1373 * \returns
1374 * A pointer to a cJSON object representing the JSON parse tree.
1375 * This returned buffer should be freed by caller.
1376 */
1377static cJSON *loader_get_json(const char *filename)
1378{
1379 FILE *file;
1380 char *json_buf;
1381 cJSON *json;
1382 uint64_t len;
1383 file = fopen(filename,"rb");
1384 fseek(file, 0, SEEK_END);
1385 len = ftell(file);
1386 fseek(file, 0, SEEK_SET);
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -06001387 json_buf = (char*) loader_stack_alloc(len+1);
Jon Ashburn2077e382015-06-29 11:25:34 -06001388 if (json_buf == NULL) {
1389 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get JSON file");
1390 fclose(file);
1391 return NULL;
1392 }
1393 if (fread(json_buf, sizeof(char), len, file) != len) {
1394 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "fread failed can't get JSON file");
1395 fclose(file);
1396 return NULL;
1397 }
1398 fclose(file);
1399 json_buf[len] = '\0';
1400
1401 //parse text from file
1402 json = cJSON_Parse(json_buf);
1403 if (json == NULL)
1404 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Can't parse JSON file %s", filename);
1405 return json;
1406}
1407
1408/**
1409 * Find the Vulkan library manifest files.
1410 *
1411 * This function scans the location or env_override directories/files
1412 * for a list of JSON manifest files. If env_override is non-NULL
1413 * and has a valid value. Then the location is ignored. Otherwise
1414 * location is used to look for manifest files. The location
1415 * is interpreted as Registry path on Windows and a directory path(s)
1416 * on Linux.
1417 *
1418 * \returns
1419 * A string list of manifest files to be opened in out_files param.
1420 * List has a pointer to string for each manifest filename.
1421 * When done using the list in out_files, pointers should be freed.
Jon Ashburnffad94d2015-06-30 14:46:22 -07001422 * Location or override string lists can be either files or directories as follows:
1423 * | location | override
1424 * --------------------------------
1425 * Win ICD | files | files
1426 * Win Layer | files | dirs
1427 * Linux ICD | dirs | files
1428 * Linux Layer| dirs | dirs
Jon Ashburn2077e382015-06-29 11:25:34 -06001429 */
1430static void loader_get_manifest_files(const char *env_override,
Jon Ashburnffad94d2015-06-30 14:46:22 -07001431 bool is_layer,
1432 const char *location,
1433 struct loader_manifest_files *out_files)
Jon Ashburn2077e382015-06-29 11:25:34 -06001434{
1435 char *override = NULL;
1436 char *loc;
1437 char *file, *next_file, *name;
1438 size_t alloced_count = 64;
1439 char full_path[2048];
1440 DIR *sysdir = NULL;
Jon Ashburnffad94d2015-06-30 14:46:22 -07001441 bool list_is_dirs = false;
Jon Ashburn2077e382015-06-29 11:25:34 -06001442 struct dirent *dent;
1443
1444 out_files->count = 0;
1445 out_files->filename_list = NULL;
1446
Jon Ashburn2077e382015-06-29 11:25:34 -06001447 if (env_override != NULL && (override = getenv(env_override))) {
1448#if defined(__linux__)
1449 if (geteuid() != getuid()) {
Jon Ashburnffad94d2015-06-30 14:46:22 -07001450 /* Don't allow setuid apps to use the env var: */
Jon Ashburn2077e382015-06-29 11:25:34 -06001451 override = NULL;
1452 }
1453#endif
1454 }
1455
1456 if (location == NULL) {
1457 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
Jon Ashburnffad94d2015-06-30 14:46:22 -07001458 "Can't get manifest files with NULL location, env_override=%s",
1459 env_override);
Jon Ashburn2077e382015-06-29 11:25:34 -06001460 return;
1461 }
1462
Jon Ashburnffad94d2015-06-30 14:46:22 -07001463#if defined(__linux__)
1464 list_is_dirs = (override == NULL || is_layer) ? true : false;
1465#else //WIN32
1466 list_is_dirs = (is_layer && override != NULL) ? true : false;
1467#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06001468 // Make a copy of the input we are using so it is not modified
Jon Ashburnffad94d2015-06-30 14:46:22 -07001469 // Also handle getting the location(s) from registry on Windows
1470 if (override == NULL) {
1471#if defined (_WIN32)
1472 loc = loader_get_registry_files(location);
1473 if (loc == NULL) {
1474 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Registry lookup failed can't get manifest files");
1475 return;
1476 }
1477#else
Jon Ashburn2077e382015-06-29 11:25:34 -06001478 loc = alloca(strlen(location) + 1);
Jon Ashburnffad94d2015-06-30 14:46:22 -07001479 if (loc == NULL) {
1480 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1481 return;
1482 }
1483 strcpy(loc, location);
1484#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06001485 }
Jon Ashburnffad94d2015-06-30 14:46:22 -07001486 else {
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -06001487 loc = loader_stack_alloc(strlen(override) + 1);
Jon Ashburnffad94d2015-06-30 14:46:22 -07001488 if (loc == NULL) {
1489 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1490 return;
1491 }
1492 strcpy(loc, override);
1493 }
Jon Ashburn2077e382015-06-29 11:25:34 -06001494
1495 file = loc;
1496 while (*file) {
1497 next_file = loader_get_next_path(file);
Jon Ashburnffad94d2015-06-30 14:46:22 -07001498 if (list_is_dirs) {
Jon Ashburn2077e382015-06-29 11:25:34 -06001499 sysdir = opendir(file);
1500 name = NULL;
1501 if (sysdir) {
1502 dent = readdir(sysdir);
1503 if (dent == NULL)
1504 break;
1505 name = &(dent->d_name[0]);
1506 loader_get_fullpath(name, file, sizeof(full_path), full_path);
1507 name = full_path;
1508 }
1509 }
1510 else {
Jon Ashburnffad94d2015-06-30 14:46:22 -07001511#if defined(__linux__)
1512 // only Linux has relative paths
Jon Ashburn2077e382015-06-29 11:25:34 -06001513 char *dir;
1514 // make a copy of location so it isn't modified
1515 dir = alloca(strlen(location) + 1);
1516 if (dir == NULL) {
1517 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1518 return;
1519 }
1520 strcpy(dir, location);
1521
1522 loader_get_fullpath(file, dir, sizeof(full_path), full_path);
1523
1524 name = full_path;
Jon Ashburnffad94d2015-06-30 14:46:22 -07001525#else // WIN32
1526 name = file;
1527#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06001528 }
1529 while (name) {
1530 /* Look for files ending with ".json" suffix */
1531 uint32_t nlen = (uint32_t) strlen(name);
1532 const char *suf = name + nlen - 5;
1533 if ((nlen > 5) && !strncmp(suf, ".json", 5)) {
1534 if (out_files->count == 0) {
1535 out_files->filename_list = malloc(alloced_count * sizeof(char *));
1536 }
1537 else if (out_files->count == alloced_count) {
1538 out_files->filename_list = realloc(out_files->filename_list,
1539 alloced_count * sizeof(char *) * 2);
1540 alloced_count *= 2;
1541 }
1542 if (out_files->filename_list == NULL) {
1543 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't alloc manifest file list");
1544 return;
1545 }
1546 out_files->filename_list[out_files->count] = malloc(strlen(name) + 1);
1547 if (out_files->filename_list[out_files->count] == NULL) {
1548 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1549 return;
1550 }
1551 strcpy(out_files->filename_list[out_files->count], name);
1552 out_files->count++;
Jon Ashburnf70f3612015-07-02 10:08:47 -06001553 } else if (!list_is_dirs) {
1554 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Skipping manifest file %s, file name must end in .json", name);
Jon Ashburn2077e382015-06-29 11:25:34 -06001555 }
Jon Ashburnffad94d2015-06-30 14:46:22 -07001556 if (list_is_dirs) {
Jon Ashburn2077e382015-06-29 11:25:34 -06001557 dent = readdir(sysdir);
1558 if (dent == NULL)
1559 break;
1560 name = &(dent->d_name[0]);
1561 loader_get_fullpath(name, file, sizeof(full_path), full_path);
1562 name = full_path;
1563 }
1564 else {
1565 break;
1566 }
1567 }
1568 if (sysdir)
1569 closedir(sysdir);
1570 file = next_file;
1571 }
1572 return;
1573}
1574
1575/**
1576 * Try to find the Vulkan ICD driver(s).
1577 *
1578 * This function scans the default system loader path(s) or path
1579 * specified by the \c VK_ICD_FILENAMES environment variable in
1580 * order to find loadable VK ICDs manifest files. From these
1581 * manifest files it finds the ICD libraries.
1582 *
1583 * \returns
Jon Ashburn3a37aee2015-06-30 16:44:28 -06001584 * void
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001585 */
Jon Ashburn27cd5842015-05-12 17:26:48 -06001586void loader_icd_scan(void)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001587{
Jon Ashburn2077e382015-06-29 11:25:34 -06001588 char *file_str;
1589 struct loader_manifest_files manifest_files;
1590
Jon Ashburn6301a0f2015-05-29 13:15:39 -06001591
1592 // convenient place to initialize a mutex
1593 loader_platform_thread_create_mutex(&loader_lock);
1594
Jon Ashburn2077e382015-06-29 11:25:34 -06001595 // convenient place to initialize logging
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001596 loader_debug_init();
1597
Jon Ashburn2077e382015-06-29 11:25:34 -06001598 // Get a list of manifest files for ICDs
1599 loader_get_manifest_files("VK_ICD_FILENAMES", false, DEFAULT_VK_DRIVERS_INFO,
1600 &manifest_files);
1601 for (uint32_t i = 0; i < manifest_files.count; i++) {
1602 file_str = manifest_files.filename_list[i];
1603 if (file_str == NULL)
1604 continue;
1605
1606 cJSON *json, *icd_json;
1607 json = loader_get_json(file_str);
1608 icd_json = cJSON_GetObjectItem(json, "ICD");
1609 if (icd_json != NULL) {
1610 icd_json = cJSON_GetObjectItem(icd_json, "library_path");
1611 if (icd_json != NULL) {
1612 char *icd_filename = cJSON_PrintUnformatted(icd_json);
1613 char *icd_file = icd_filename;
1614 if (icd_filename != NULL) {
Jon Ashburn2077e382015-06-29 11:25:34 -06001615 char def_dir[] = DEFAULT_VK_DRIVERS_PATH;
1616 char *dir = def_dir;
1617 // strip off extra quotes
1618 if (icd_filename[strlen(icd_filename) - 1] == '"')
1619 icd_filename[strlen(icd_filename) - 1] = '\0';
1620 if (icd_filename[0] == '"')
1621 icd_filename++;
Jon Ashburnffad94d2015-06-30 14:46:22 -07001622#if defined(__linux__)
1623 char full_path[2048];
Jon Ashburn2077e382015-06-29 11:25:34 -06001624 loader_get_fullpath(icd_filename, dir, sizeof(full_path), full_path);
1625 loader_scanned_icd_add(full_path);
Jon Ashburnffad94d2015-06-30 14:46:22 -07001626#else // WIN32
1627 loader_scanned_icd_add(icd_filename);
1628#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06001629 free(icd_file);
1630 }
1631 }
1632 else
1633 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"library_path\" in ICD JSON file %s, skipping", file_str);
1634 }
1635 else
1636 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"ICD\" object in ICD JSON file %s, skipping", file_str);
1637
1638 free(file_str);
1639 cJSON_Delete(json);
1640 }
1641 free(manifest_files.filename_list);
1642
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001643}
1644
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001645
Jon Ashburn5ef20602015-07-02 09:40:15 -06001646void loader_layer_scan(void)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001647{
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06001648 uint32_t len;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001649 const char *p, *next;
Ian Elliott4470a302015-02-17 10:33:47 -07001650 char *libPaths = NULL;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001651 DIR *curdir;
1652 struct dirent *dent;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001653 char temp_str[1024];
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001654
Ian Elliott4470a302015-02-17 10:33:47 -07001655#if defined(WIN32)
1656 bool must_free_libPaths;
1657 libPaths = loader_get_registry_and_env(LAYERS_PATH_ENV,
1658 LAYERS_PATH_REGISTRY_VALUE);
1659 if (libPaths != NULL) {
1660 must_free_libPaths = true;
1661 } else {
1662 must_free_libPaths = false;
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001663 libPaths = DEFAULT_VK_LAYERS_PATH;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001664 }
Ian Elliott4470a302015-02-17 10:33:47 -07001665#else // WIN32
1666 if (geteuid() == getuid()) {
Jon Ashburn2077e382015-06-29 11:25:34 -06001667 /* Don't allow setuid apps to use the LAYERS_PATH_ENV env var: */
Courtney Goeltzenleuchter66b72f92015-02-18 20:03:02 -07001668 libPaths = getenv(LAYERS_PATH_ENV);
Ian Elliott4470a302015-02-17 10:33:47 -07001669 }
1670 if (libPaths == NULL) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001671 libPaths = DEFAULT_VK_LAYERS_PATH;
Ian Elliott4470a302015-02-17 10:33:47 -07001672 }
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001673#endif // WIN32
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001674
Ian Elliott4470a302015-02-17 10:33:47 -07001675 if (libPaths == NULL) {
1676 // Have no paths to search:
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -07001677 return;
1678 }
Ian Elliott4470a302015-02-17 10:33:47 -07001679 len = strlen(libPaths);
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -07001680 loader.layer_dirs = malloc(len+1);
Ian Elliott4470a302015-02-17 10:33:47 -07001681 if (loader.layer_dirs == NULL) {
Jon Ashburn90c6a0e2015-06-04 15:30:58 -06001682 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add layer directories");
1683
Ian Elliott4470a302015-02-17 10:33:47 -07001684 free(libPaths);
Courtney Goeltzenleuchtera66265b2014-12-02 18:12:51 -07001685 return;
Ian Elliott4470a302015-02-17 10:33:47 -07001686 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001687 // Alloc passed, so we know there is enough space to hold the string
Ian Elliott4470a302015-02-17 10:33:47 -07001688 strcpy(loader.layer_dirs, libPaths);
1689#if defined(WIN32)
1690 // Free any allocated memory:
1691 if (must_free_libPaths) {
1692 free(libPaths);
1693 must_free_libPaths = false;
1694 }
1695#endif // WIN32
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -07001696 libPaths = loader.layer_dirs;
1697
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06001698 /*
1699 * We need a list of the layer libraries, not just a list of
1700 * the layer properties (a layer library could expose more than
1701 * one layer property). This list of scanned layers would be
1702 * used to check for global and physicaldevice layer properties.
1703 */
1704 if (!loader_init_layer_library_list(&loader.scanned_layer_libraries)) {
1705 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1706 "Malloc for layer list failed: %s line: %d", __FILE__, __LINE__);
1707 return;
Jon Ashburn5ef20602015-07-02 09:40:15 -06001708 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001709
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001710 for (p = libPaths; *p; p = next) {
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001711 next = strchr(p, PATH_SEPERATOR);
1712 if (next == NULL) {
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001713 len = (uint32_t) strlen(p);
1714 next = p + len;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001715 }
1716 else {
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001717 len = (uint32_t) (next - p);
1718 *(char *) next = '\0';
1719 next++;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001720 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001721
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001722 curdir = opendir(p);
1723 if (curdir) {
1724 dent = readdir(curdir);
1725 while (dent) {
1726 /* Look for layers starting with VK_LAYER_LIBRARY_PREFIX and
1727 * ending with VK_LIBRARY_SUFFIX
1728 */
1729 if (!strncmp(dent->d_name,
1730 VK_LAYER_LIBRARY_PREFIX,
1731 VK_LAYER_LIBRARY_PREFIX_LEN)) {
1732 uint32_t nlen = (uint32_t) strlen(dent->d_name);
1733 const char *suf = dent->d_name + nlen - VK_LIBRARY_SUFFIX_LEN;
1734 if ((nlen > VK_LIBRARY_SUFFIX_LEN) &&
1735 !strncmp(suf,
1736 VK_LIBRARY_SUFFIX,
1737 VK_LIBRARY_SUFFIX_LEN)) {
1738 loader_platform_dl_handle handle;
1739 snprintf(temp_str, sizeof(temp_str),
Jon Ashburn2077e382015-06-29 11:25:34 -06001740 "%s%c%s",p, DIRECTORY_SYMBOL, dent->d_name);
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001741 // Used to call: dlopen(temp_str, RTLD_LAZY)
1742 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter1e4602f2015-06-09 09:44:13 -06001743 "Attempt to open library: %s", temp_str);
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001744 if ((handle = loader_platform_open_library(temp_str)) == NULL) {
Courtney Goeltzenleuchter1e4602f2015-06-09 09:44:13 -06001745 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "open library failed");
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001746 dent = readdir(curdir);
1747 continue;
1748 }
1749 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter1e4602f2015-06-09 09:44:13 -06001750 "Opened library: %s", temp_str);
Courtney Goeltzenleuchtera9e4af42015-06-01 14:49:17 -06001751
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06001752 /* TODO: Need instance pointer here */
1753 loader_add_layer_library(NULL, temp_str, handle, &loader.scanned_layer_libraries);
1754
1755 loader_add_global_layer_properties(temp_str, handle, &loader.global_layer_list);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001756
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001757 loader_platform_close_library(handle);
1758 }
1759 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001760
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001761 dent = readdir(curdir);
1762 } // while (dir_entry)
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001763 closedir(curdir);
1764 } // if (curdir))
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001765 } // for (libpaths)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001766}
1767
Jon Ashburn27cd5842015-05-12 17:26:48 -06001768static void* VKAPI loader_gpa_instance_internal(VkInstance inst, const char * pName)
1769{
1770 // inst is not wrapped
1771 if (inst == VK_NULL_HANDLE) {
1772 return NULL;
1773 }
1774 VkLayerInstanceDispatchTable* disp_table = * (VkLayerInstanceDispatchTable **) inst;
1775 void *addr;
1776
Jon Ashburn8fd08252015-05-28 16:25:02 -06001777 if (!strcmp(pName, "vkGetInstanceProcAddr"))
1778 return (void *) loader_gpa_instance_internal;
1779
Jon Ashburn27cd5842015-05-12 17:26:48 -06001780 if (disp_table == NULL)
1781 return NULL;
1782
1783 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001784 if (addr) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06001785 return addr;
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001786 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001787
1788 if (disp_table->GetInstanceProcAddr == NULL) {
1789 return NULL;
1790 }
1791 return disp_table->GetInstanceProcAddr(inst, pName);
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001792}
1793
Jon Ashburn128f9422015-05-28 19:16:58 -06001794struct loader_icd * loader_get_icd(const VkPhysicalDevice gpu, uint32_t *gpu_index)
Jon Ashburn876b1ac2014-10-17 15:09:07 -06001795{
Jon Ashburn128f9422015-05-28 19:16:58 -06001796
Jon Ashburn98bd4542015-01-29 16:44:24 -07001797 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
1798 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
1799 for (uint32_t i = 0; i < icd->gpu_count; i++)
Jon Ashburn128f9422015-05-28 19:16:58 -06001800 if (icd->gpus[i] == gpu) {
Jon Ashburn98bd4542015-01-29 16:44:24 -07001801 *gpu_index = i;
1802 return icd;
1803 }
1804 }
Jon Ashburn876b1ac2014-10-17 15:09:07 -06001805 }
1806 return NULL;
1807}
1808
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001809static loader_platform_dl_handle loader_add_layer_lib(
Jon Ashburn4f67d742015-05-27 13:19:22 -06001810 const char *chain_type,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001811 struct loader_layer_properties *layer_prop)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001812{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001813 struct loader_lib_info *new_layer_lib_list, *my_lib;
1814
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06001815 /*
1816 * TODO: We can now track this information in the
1817 * scanned_layer_libraries list.
1818 */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001819 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001820 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, layer_prop->lib_info.lib_name) == 0) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001821 /* Have already loaded this library, just increment ref count */
1822 loader.loaded_layer_lib_list[i].ref_count++;
Courtney Goeltzenleuchterca8c81a2015-06-14 11:59:07 -06001823 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001824 "%s Chain: Increment layer reference count for layer library %s",
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001825 chain_type, layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001826 return loader.loaded_layer_lib_list[i].lib_handle;
1827 }
1828 }
1829
1830 /* Haven't seen this library so load it */
1831 new_layer_lib_list = realloc(loader.loaded_layer_lib_list,
1832 (loader.loaded_layer_lib_count + 1) * sizeof(struct loader_lib_info));
1833 if (!new_layer_lib_list) {
1834 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1835 return NULL;
1836 }
1837
1838 my_lib = &new_layer_lib_list[loader.loaded_layer_lib_count];
1839
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001840 /* NOTE: We require that the layer property be immutable */
1841 my_lib->lib_name = (char *) layer_prop->lib_info.lib_name;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001842 my_lib->ref_count = 0;
1843 my_lib->lib_handle = NULL;
1844
1845 if ((my_lib->lib_handle = loader_platform_open_library(my_lib->lib_name)) == NULL) {
1846 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1847 loader_platform_open_library_error(my_lib->lib_name));
1848 return NULL;
1849 } else {
Courtney Goeltzenleuchterca8c81a2015-06-14 11:59:07 -06001850 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001851 "Chain: %s: Loading layer library %s",
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001852 chain_type, layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001853 }
1854 loader.loaded_layer_lib_count++;
1855 loader.loaded_layer_lib_list = new_layer_lib_list;
1856 my_lib->ref_count++;
1857
1858 return my_lib->lib_handle;
1859}
1860
1861static void loader_remove_layer_lib(
1862 struct loader_instance *inst,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001863 struct loader_layer_properties *layer_prop)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001864{
1865 uint32_t idx;
1866 struct loader_lib_info *new_layer_lib_list, *my_lib;
1867
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001868 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001869 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, layer_prop->lib_info.lib_name) == 0) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001870 /* found matching library */
1871 idx = i;
1872 my_lib = &loader.loaded_layer_lib_list[i];
1873 break;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001874 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001875 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001876
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001877 my_lib->ref_count--;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001878 if (my_lib->ref_count > 0) {
Courtney Goeltzenleuchterca8c81a2015-06-14 11:59:07 -06001879 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001880 "Decrement reference count for layer library %s", layer_prop->lib_info.lib_name);
Jon Ashburn27cd5842015-05-12 17:26:48 -06001881 return;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001882 }
Jon Ashburn19c25022015-04-14 14:14:48 -06001883
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001884 loader_platform_close_library(my_lib->lib_handle);
Courtney Goeltzenleuchterca8c81a2015-06-14 11:59:07 -06001885 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001886 "Unloading layer library %s", layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001887
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001888 /* Need to remove unused library from list */
1889 new_layer_lib_list = malloc((loader.loaded_layer_lib_count - 1) * sizeof(struct loader_lib_info));
1890 if (!new_layer_lib_list) {
1891 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1892 return;
1893 }
1894
1895 if (idx > 0) {
1896 /* Copy records before idx */
1897 memcpy(new_layer_lib_list, &loader.loaded_layer_lib_list[0],
1898 sizeof(struct loader_lib_info) * idx);
1899 }
1900 if (idx < (loader.loaded_layer_lib_count - 1)) {
1901 /* Copy records after idx */
1902 memcpy(&new_layer_lib_list[idx], &loader.loaded_layer_lib_list[idx+1],
1903 sizeof(struct loader_lib_info) * (loader.loaded_layer_lib_count - idx - 1));
1904 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001905
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001906 free(loader.loaded_layer_lib_list);
1907 loader.loaded_layer_lib_count--;
1908 loader.loaded_layer_lib_list = new_layer_lib_list;
Jon Ashburnb8358052014-11-18 09:06:04 -07001909}
1910
Jon Ashburn0c26e712015-07-02 16:10:32 -06001911static void loader_add_layer_implicit(
1912 const enum layer_type type,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001913 struct loader_layer_list *list,
1914 struct loader_layer_list *search_list)
Jon Ashburn0c26e712015-07-02 16:10:32 -06001915{
1916 uint32_t i;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001917 for (i = 0; i < search_list->count; i++) {
1918 const struct loader_layer_properties *prop = &search_list->list[i];
Jon Ashburn0c26e712015-07-02 16:10:32 -06001919 if (prop->type & type) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001920 /* Found an layer with the same type, add to layer_list */
1921 loader_add_to_layer_list(list, 1, prop);
Jon Ashburn0c26e712015-07-02 16:10:32 -06001922 }
1923 }
1924
1925}
1926
1927/**
1928 * Get the layer name(s) from the env_name environment variable. If layer
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001929 * is found in search_list then add it to layer_list.
Jon Ashburn0c26e712015-07-02 16:10:32 -06001930 */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001931static void loader_add_layer_env(
Jon Ashburneb6d5682015-07-02 14:10:53 -06001932 const char *env_name,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001933 struct loader_layer_list *layer_list,
1934 const struct loader_layer_list *search_list)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001935{
Ian Elliott4470a302015-02-17 10:33:47 -07001936 char *layerEnv;
Jon Ashburneb6d5682015-07-02 14:10:53 -06001937 char *next, *name;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001938
Jon Ashburneb6d5682015-07-02 14:10:53 -06001939 layerEnv = getenv(env_name);
Ian Elliott4470a302015-02-17 10:33:47 -07001940 if (layerEnv == NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001941 return;
Ian Elliott4470a302015-02-17 10:33:47 -07001942 }
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -06001943 name = loader_stack_alloc(strlen(layerEnv) + 1);
Jon Ashburneb6d5682015-07-02 14:10:53 -06001944 if (name == NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001945 return;
Ian Elliott4470a302015-02-17 10:33:47 -07001946 }
Jon Ashburneb6d5682015-07-02 14:10:53 -06001947 strcpy(name, layerEnv);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001948
Jon Ashburneb6d5682015-07-02 14:10:53 -06001949 while (name && *name ) {
1950 next = loader_get_next_path(name);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001951 loader_find_layer_name_add_list(name, search_list, layer_list);
Jon Ashburneb6d5682015-07-02 14:10:53 -06001952 name = next;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001953 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001954
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001955 return;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001956}
1957
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -06001958void loader_deactivate_instance_layers(struct loader_instance *instance)
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001959{
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001960 if (!instance->activated_layer_list.count) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001961 return;
1962 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001963
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001964 /* Create instance chain of enabled layers */
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -06001965 for (uint32_t i = 0; i < instance->activated_layer_list.count; i++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001966 struct loader_layer_properties *layer_prop = &instance->activated_layer_list.list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001967
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001968 loader_remove_layer_lib(instance, layer_prop);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001969 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001970 loader_destroy_layer_list(&instance->activated_layer_list);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001971}
1972
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001973void loader_enable_instance_layers(
1974 struct loader_instance *inst,
1975 const VkInstanceCreateInfo *pCreateInfo)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001976{
1977 if (inst == NULL)
1978 return;
1979
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001980 if (!loader_init_layer_list(&inst->activated_layer_list)) {
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001981 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance activated layer list");
1982 return;
1983 }
1984
Jon Ashburn0c26e712015-07-02 16:10:32 -06001985 /* Add any implicit layers first */
1986 loader_add_layer_implicit(
1987 VK_LAYER_TYPE_INSTANCE_IMPLICIT,
1988 &inst->activated_layer_list,
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06001989 &loader.global_layer_list);
Jon Ashburn0c26e712015-07-02 16:10:32 -06001990
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001991 /* Add any layers specified via environment variable first */
Jon Ashburneb6d5682015-07-02 14:10:53 -06001992 loader_add_layer_env(
1993 "VK_INSTANCE_LAYERS",
1994 &inst->activated_layer_list,
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06001995 &loader.global_layer_list);
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001996
1997 /* Add layers specified by the application */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001998 loader_add_layer_names_to_list(
1999 &inst->activated_layer_list,
2000 pCreateInfo->layerCount,
2001 pCreateInfo->ppEnabledLayerNames,
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06002002 &loader.global_layer_list);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002003}
2004
Jon Ashburn27cd5842015-05-12 17:26:48 -06002005uint32_t loader_activate_instance_layers(struct loader_instance *inst)
2006{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002007 uint32_t layer_idx;
Jon Ashburn128f9422015-05-28 19:16:58 -06002008 VkBaseLayerObject *wrappedInstance;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002009
David Pinedoa0a8a242015-06-24 15:29:18 -06002010 if (inst == NULL) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06002011 return 0;
David Pinedoa0a8a242015-06-24 15:29:18 -06002012 }
Jon Ashburn27cd5842015-05-12 17:26:48 -06002013
2014 // NOTE inst is unwrapped at this point in time
2015 VkObject baseObj = (VkObject) inst;
2016 VkObject nextObj = (VkObject) inst;
2017 VkBaseLayerObject *nextInstObj;
2018 PFN_vkGetInstanceProcAddr nextGPA = loader_gpa_instance_internal;
2019
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002020 if (!inst->activated_layer_list.count) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06002021 return 0;
2022 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002023
Courtney Goeltzenleuchter6f460c52015-07-06 09:04:55 -06002024 wrappedInstance = loader_stack_alloc(sizeof(VkBaseLayerObject)
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002025 * inst->activated_layer_list.count);
Jon Ashburn128f9422015-05-28 19:16:58 -06002026 if (!wrappedInstance) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002027 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance objects for layer");
2028 return 0;
2029 }
2030
2031 /* Create instance chain of enabled layers */
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002032 layer_idx = inst->activated_layer_list.count - 1;
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06002033 for (int32_t i = inst->activated_layer_list.count - 1; i >= 0; i--) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002034 struct loader_layer_properties *layer_prop = &inst->activated_layer_list.list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002035 loader_platform_dl_handle lib_handle;
2036
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002037 /*
Courtney Goeltzenleuchteree3b16a2015-06-01 14:12:42 -06002038 * Note: An extension's Get*ProcAddr should not return a function pointer for
2039 * any extension entry points until the extension has been enabled.
2040 * To do this requires a different behavior from Get*ProcAddr functions implemented
2041 * in layers.
2042 * The very first call to a layer will be it's Get*ProcAddr function requesting
2043 * the layer's vkGet*ProcAddr. The layer should intialize it's internal dispatch table
2044 * with the wrapped object given (either Instance or Device) and return the layer's
2045 * Get*ProcAddr function. The layer should also use this opportunity to record the
2046 * baseObject so that it can find the correct local dispatch table on future calls.
2047 * Subsequent calls to Get*ProcAddr, CreateInstance, CreateDevice
2048 * will not use a wrapped object and must look up their local dispatch table from
2049 * the given baseObject.
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002050 */
Jon Ashburn128f9422015-05-28 19:16:58 -06002051 nextInstObj = (wrappedInstance + layer_idx);
Jon Ashburn27cd5842015-05-12 17:26:48 -06002052 nextInstObj->pGPA = nextGPA;
2053 nextInstObj->baseObject = baseObj;
2054 nextInstObj->nextObject = nextObj;
2055 nextObj = (VkObject) nextInstObj;
2056
2057 char funcStr[256];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002058 snprintf(funcStr, 256, "%sGetInstanceProcAddr", layer_prop->info.layerName);
2059 lib_handle = loader_add_layer_lib("instance", layer_prop);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002060 if ((nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
2061 nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
Jon Ashburn27cd5842015-05-12 17:26:48 -06002062 if (!nextGPA) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002063 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to find vkGetInstanceProcAddr in layer %s", layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchtera9e4af42015-06-01 14:49:17 -06002064
2065 /* TODO: Should we return nextObj, nextGPA to previous? */
Jon Ashburn27cd5842015-05-12 17:26:48 -06002066 continue;
2067 }
2068
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002069 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002070 "Insert instance layer %s (%s)",
2071 layer_prop->info.layerName,
2072 layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002073
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002074 layer_idx--;
Jon Ashburn27cd5842015-05-12 17:26:48 -06002075 }
2076
Jon Ashburn8fd08252015-05-28 16:25:02 -06002077 loader_init_instance_core_dispatch_table(inst->disp, nextGPA, (VkInstance) nextObj, (VkInstance) baseObj);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002078
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002079 return inst->activated_layer_list.count;
Jon Ashburn27cd5842015-05-12 17:26:48 -06002080}
2081
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002082void loader_activate_instance_layer_extensions(struct loader_instance *inst)
2083{
2084
2085 loader_init_instance_extension_dispatch_table(inst->disp,
2086 inst->disp->GetInstanceProcAddr,
Jon Ashburn128f9422015-05-28 19:16:58 -06002087 (VkInstance) inst);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002088}
2089
Courtney Goeltzenleuchtera6628c22015-06-25 16:27:24 -06002090static void loader_enable_device_layers(
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06002091 struct loader_icd *icd,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002092 struct loader_device *dev,
2093 const VkDeviceCreateInfo *pCreateInfo)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002094{
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002095 if (dev == NULL)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002096 return;
2097
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002098 if (dev->activated_layer_list.list == NULL || dev->activated_layer_list.capacity == 0) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002099 loader_init_layer_list(&dev->activated_layer_list);
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002100 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002101
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002102 if (dev->activated_layer_list.list == NULL) {
2103 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc device activated layer list");
2104 return;
2105 }
2106
Jon Ashburn0c26e712015-07-02 16:10:32 -06002107 /* Add any implicit layers first */
2108 loader_add_layer_implicit(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002109 VK_LAYER_TYPE_DEVICE_IMPLICIT,
2110 &dev->activated_layer_list,
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06002111 &icd->layer_properties_cache);
Jon Ashburn0c26e712015-07-02 16:10:32 -06002112
2113 /* Add any layers specified via environment variable next */
Jon Ashburneb6d5682015-07-02 14:10:53 -06002114 loader_add_layer_env(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002115 "VK_DEVICE_LAYERS",
2116 &dev->activated_layer_list,
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06002117 &icd->layer_properties_cache);
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002118
2119 /* Add layers specified by the application */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002120 loader_add_layer_names_to_list(
2121 &dev->activated_layer_list,
2122 pCreateInfo->layerCount,
2123 pCreateInfo->ppEnabledLayerNames,
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06002124 &icd->layer_properties_cache);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002125}
2126
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002127/*
2128 * This function terminates the device chain fro CreateDevice.
2129 * CreateDevice is a special case and so the loader call's
2130 * the ICD's CreateDevice before creating the chain. Since
2131 * we can't call CreateDevice twice we must terminate the
2132 * device chain with something else.
2133 */
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002134static VkResult scratch_vkCreateDevice(
2135 VkPhysicalDevice gpu,
2136 const VkDeviceCreateInfo *pCreateInfo,
2137 VkDevice *pDevice)
2138{
2139 return VK_SUCCESS;
2140}
2141
2142static void * VKAPI loader_GetDeviceChainProcAddr(VkDevice device, const char * name)
2143{
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002144 if (!strcmp(name, "vkGetDeviceProcAddr"))
2145 return (void *) loader_GetDeviceChainProcAddr;
2146 if (!strcmp(name, "vkCreateDevice"))
2147 return (void *) scratch_vkCreateDevice;
2148
Courtney Goeltzenleuchter3e029d12015-06-29 16:09:23 -06002149 struct loader_device *found_dev;
2150 struct loader_icd *icd = loader_get_icd_and_device(device, &found_dev);
2151 return icd->GetDeviceProcAddr(device, name);
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002152}
2153
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002154static uint32_t loader_activate_device_layers(
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06002155 struct loader_icd *icd,
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002156 struct loader_device *dev,
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06002157 VkDevice device)
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002158{
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002159 if (!icd)
2160 return 0;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002161
David Pinedoa0a8a242015-06-24 15:29:18 -06002162 if (!dev) {
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002163 return 0;
David Pinedoa0a8a242015-06-24 15:29:18 -06002164 }
Jon Ashburn94e70492015-06-10 10:13:10 -06002165
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002166 /* activate any layer libraries */
Jon Ashburn94e70492015-06-10 10:13:10 -06002167 VkObject nextObj = (VkObject) device;
2168 VkObject baseObj = nextObj;
2169 VkBaseLayerObject *nextGpuObj;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002170 PFN_vkGetDeviceProcAddr nextGPA = loader_GetDeviceChainProcAddr;
Jon Ashburn94e70492015-06-10 10:13:10 -06002171 VkBaseLayerObject *wrappedGpus;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002172
Jon Ashburn94e70492015-06-10 10:13:10 -06002173 if (!dev->activated_layer_list.count)
2174 return 0;
2175
2176 wrappedGpus = malloc(sizeof (VkBaseLayerObject) * dev->activated_layer_list.count);
2177 if (!wrappedGpus) {
2178 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Gpu objects for layer");
2179 return 0;
2180 }
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002181
Jon Ashburn94e70492015-06-10 10:13:10 -06002182 for (int32_t i = dev->activated_layer_list.count - 1; i >= 0; i--) {
2183
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002184 struct loader_layer_properties *layer_prop = &dev->activated_layer_list.list[i];
Jon Ashburn94e70492015-06-10 10:13:10 -06002185 loader_platform_dl_handle lib_handle;
2186
Jon Ashburn94e70492015-06-10 10:13:10 -06002187 nextGpuObj = (wrappedGpus + i);
2188 nextGpuObj->pGPA = nextGPA;
2189 nextGpuObj->baseObject = baseObj;
2190 nextGpuObj->nextObject = nextObj;
2191 nextObj = (VkObject) nextGpuObj;
2192
2193 char funcStr[256];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002194 snprintf(funcStr, 256, "%sGetDeviceProcAddr", layer_prop->info.layerName);
2195 lib_handle = loader_add_layer_lib("device", layer_prop);
Jon Ashburn94e70492015-06-10 10:13:10 -06002196 if ((nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
2197 nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr");
2198 if (!nextGPA) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002199 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to find vkGetDeviceProcAddr in layer %s", layer_prop->info.layerName);
Jon Ashburn94e70492015-06-10 10:13:10 -06002200 continue;
2201 }
2202
2203 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002204 "Insert device layer library %s (%s)",
2205 layer_prop->info.layerName,
2206 layer_prop->lib_info.lib_name);
Jon Ashburn94e70492015-06-10 10:13:10 -06002207
2208 }
2209
2210 loader_init_device_dispatch_table(&dev->loader_dispatch, nextGPA,
2211 (VkPhysicalDevice) nextObj, (VkPhysicalDevice) baseObj);
2212 free(wrappedGpus);
2213
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002214 return dev->activated_layer_list.count;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002215}
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002216
Jon Ashburn27cd5842015-05-12 17:26:48 -06002217VkResult loader_CreateInstance(
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002218 const VkInstanceCreateInfo* pCreateInfo,
2219 VkInstance* pInstance)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002220{
Jon Ashburneed0c002015-05-21 17:42:17 -06002221 struct loader_instance *ptr_instance = *(struct loader_instance **) pInstance;
Jon Ashburn46888392015-01-29 15:45:51 -07002222 struct loader_scanned_icds *scanned_icds;
2223 struct loader_icd *icd;
Jon Ashburn27cd5842015-05-12 17:26:48 -06002224 VkResult res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002225
Jon Ashburn46888392015-01-29 15:45:51 -07002226 scanned_icds = loader.scanned_icd_list;
2227 while (scanned_icds) {
2228 icd = loader_icd_add(ptr_instance, scanned_icds);
2229 if (icd) {
Jon Ashburnb317fad2015-04-04 14:52:07 -06002230 res = scanned_icds->CreateInstance(pCreateInfo,
Jon Ashburn3da71f22015-05-14 12:43:38 -06002231 &(icd->instance));
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06002232 if (res != VK_SUCCESS)
Jon Ashburn46888392015-01-29 15:45:51 -07002233 {
2234 ptr_instance->icds = ptr_instance->icds->next;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002235 loader_icd_destroy(ptr_instance, icd);
Jon Ashburn3da71f22015-05-14 12:43:38 -06002236 icd->instance = VK_NULL_HANDLE;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002237 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Jon Ashburn46888392015-01-29 15:45:51 -07002238 "ICD ignored: failed to CreateInstance on device");
Jon Ashburn3da71f22015-05-14 12:43:38 -06002239 } else
2240 {
2241 loader_icd_init_entrys(icd, scanned_icds);
Jon Ashburn46888392015-01-29 15:45:51 -07002242 }
2243 }
2244 scanned_icds = scanned_icds->next;
2245 }
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002246
Ian Elliotteb450762015-02-05 15:19:15 -07002247 if (ptr_instance->icds == NULL) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06002248 return VK_ERROR_INCOMPATIBLE_DRIVER;
Ian Elliotteb450762015-02-05 15:19:15 -07002249 }
Jon Ashburn46888392015-01-29 15:45:51 -07002250
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002251 return res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002252}
2253
Jon Ashburn27cd5842015-05-12 17:26:48 -06002254VkResult loader_DestroyInstance(
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06002255 VkInstance instance)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002256{
Courtney Goeltzenleuchterdeceded2015-06-08 15:04:02 -06002257 struct loader_instance *ptr_instance = loader_instance(instance);
Jon Ashburn3da71f22015-05-14 12:43:38 -06002258 struct loader_icd *icds = ptr_instance->icds;
Jon Ashburna6fd2612015-06-16 14:43:19 -06002259 struct loader_icd *next_icd;
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06002260 VkResult res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002261
2262 // Remove this instance from the list of instances:
2263 struct loader_instance *prev = NULL;
2264 struct loader_instance *next = loader.instances;
2265 while (next != NULL) {
2266 if (next == ptr_instance) {
2267 // Remove this instance from the list:
2268 if (prev)
2269 prev->next = next->next;
Jon Ashburnc5c49602015-02-03 09:26:59 -07002270 else
2271 loader.instances = next->next;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002272 break;
2273 }
2274 prev = next;
2275 next = next->next;
2276 }
2277 if (next == NULL) {
2278 // This must be an invalid instance handle or empty list
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06002279 return VK_ERROR_INVALID_HANDLE;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002280 }
2281
Jon Ashburn3da71f22015-05-14 12:43:38 -06002282 while (icds) {
2283 if (icds->instance) {
2284 res = icds->DestroyInstance(icds->instance);
Tony Barbourf20f87b2015-04-22 09:02:32 -06002285 if (res != VK_SUCCESS)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002286 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Tony Barbourf20f87b2015-04-22 09:02:32 -06002287 "ICD ignored: failed to DestroyInstance on device");
2288 }
Jon Ashburna6fd2612015-06-16 14:43:19 -06002289 next_icd = icds->next;
Jon Ashburn3da71f22015-05-14 12:43:38 -06002290 icds->instance = VK_NULL_HANDLE;
Jon Ashburna6fd2612015-06-16 14:43:19 -06002291 loader_icd_destroy(ptr_instance, icds);
2292
2293 icds = next_icd;
Jon Ashburn46888392015-01-29 15:45:51 -07002294 }
2295
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002296
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06002297 return VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002298}
2299
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002300VkResult loader_init_physical_device_info(
2301 struct loader_instance *ptr_instance)
2302{
2303 struct loader_icd *icd;
2304 uint32_t n, count = 0;
2305 VkResult res = VK_ERROR_UNKNOWN;
2306
2307 icd = ptr_instance->icds;
2308 while (icd) {
2309 res = icd->EnumeratePhysicalDevices(icd->instance, &n, NULL);
2310 if (res != VK_SUCCESS)
2311 return res;
2312 icd->gpu_count = n;
2313 count += n;
2314 icd = icd->next;
2315 }
2316
2317 ptr_instance->total_gpu_count = count;
2318
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002319 icd = ptr_instance->icds;
2320 while (icd) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002321
2322 n = icd->gpu_count;
Jon Ashburn128f9422015-05-28 19:16:58 -06002323 icd->gpus = (VkPhysicalDevice *) malloc(n * sizeof(VkPhysicalDevice));
2324 if (!icd->gpus) {
2325 /* TODO: Add cleanup code here */
2326 return VK_ERROR_OUT_OF_HOST_MEMORY;
2327 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002328 res = icd->EnumeratePhysicalDevices(
2329 icd->instance,
2330 &n,
Jon Ashburn128f9422015-05-28 19:16:58 -06002331 icd->gpus);
2332 if ((res == VK_SUCCESS) && (n == icd->gpu_count)) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002333
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002334 for (unsigned int i = 0; i < n; i++) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002335
Jon Ashburn128f9422015-05-28 19:16:58 -06002336 loader_init_dispatch(icd->gpus[i], ptr_instance->disp);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002337
2338 if (!loader_init_ext_list(&icd->device_extension_cache[i])) {
2339 /* TODO: Add cleanup code here */
2340 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2341 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002342 if (res == VK_SUCCESS) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002343
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002344 loader_add_physical_device_extensions(
2345 icd->GetPhysicalDeviceExtensionProperties,
2346 icd->gpus[0],
2347 VK_EXTENSION_ORIGIN_ICD,
2348 icd->scanned_icds->lib_name,
2349 &icd->device_extension_cache[i]);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002350
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06002351 for (uint32_t l = 0; l < loader.scanned_layer_libraries.count; l++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002352 loader_platform_dl_handle lib_handle;
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06002353 char *lib_name = loader.scanned_layer_libraries.list[l].lib_name;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002354
2355 lib_handle = loader_platform_open_library(lib_name);
2356 if (lib_handle == NULL) {
2357 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "open library failed: %s", lib_name);
2358 continue;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002359 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002360 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
2361 "library: %s", lib_name);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002362
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002363 loader_add_physical_device_layer_properties(
2364 icd, lib_name, lib_handle);
2365
2366 loader_platform_close_library(lib_handle);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002367 }
2368 }
2369
2370 if (res != VK_SUCCESS) {
2371 /* clean up any extension lists previously created before this request failed */
2372 for (uint32_t j = 0; j < i; j++) {
2373 loader_destroy_ext_list(&icd->device_extension_cache[i]);
2374 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002375
2376 loader_destroy_layer_list(&icd->layer_properties_cache);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002377 return res;
2378 }
2379 }
2380
2381 count += n;
2382 }
2383
2384 icd = icd->next;
2385 }
2386
2387 return VK_SUCCESS;
2388}
2389
Jon Ashburn27cd5842015-05-12 17:26:48 -06002390VkResult loader_EnumeratePhysicalDevices(
Courtney Goeltzenleuchter5e41f1d2015-04-20 12:48:54 -06002391 VkInstance instance,
2392 uint32_t* pPhysicalDeviceCount,
2393 VkPhysicalDevice* pPhysicalDevices)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002394{
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002395 uint32_t index = 0;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07002396 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002397 struct loader_icd *icd = ptr_instance->icds;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07002398
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002399 if (ptr_instance->total_gpu_count == 0) {
2400 loader_init_physical_device_info(ptr_instance);
Jon Ashburn4c392fb2015-01-28 19:57:09 -07002401 }
2402
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002403 *pPhysicalDeviceCount = ptr_instance->total_gpu_count;
2404 if (!pPhysicalDevices) {
2405 return VK_SUCCESS;
2406 }
Jon Ashburn4c392fb2015-01-28 19:57:09 -07002407
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002408 while (icd) {
2409 assert((index + icd->gpu_count) <= *pPhysicalDeviceCount);
Jon Ashburn128f9422015-05-28 19:16:58 -06002410 memcpy(&pPhysicalDevices[index], icd->gpus, icd->gpu_count * sizeof(VkPhysicalDevice));
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002411 index += icd->gpu_count;
2412 icd = icd->next;
2413 }
2414
2415 return VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002416}
2417
Tony Barbour59a47322015-06-24 16:06:58 -06002418VkResult loader_GetPhysicalDeviceProperties(
Jon Ashburn3da71f22015-05-14 12:43:38 -06002419 VkPhysicalDevice gpu,
Tony Barbour59a47322015-06-24 16:06:58 -06002420 VkPhysicalDeviceProperties* pProperties)
Jon Ashburn3da71f22015-05-14 12:43:38 -06002421{
2422 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06002423 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburn3da71f22015-05-14 12:43:38 -06002424 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2425
Tony Barbour59a47322015-06-24 16:06:58 -06002426 if (icd->GetPhysicalDeviceProperties)
2427 res = icd->GetPhysicalDeviceProperties(gpu, pProperties);
2428
2429 return res;
2430}
2431
2432VkResult loader_GetPhysicalDevicePerformance(
2433 VkPhysicalDevice gpu,
2434 VkPhysicalDevicePerformance* pPerformance)
2435{
2436 uint32_t gpu_index;
2437 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2438 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2439
2440 if (icd->GetPhysicalDevicePerformance)
2441 res = icd->GetPhysicalDevicePerformance(gpu, pPerformance);
2442
2443 return res;
2444}
2445
2446VkResult loader_GetPhysicalDeviceQueueCount(
2447 VkPhysicalDevice gpu,
2448 uint32_t* pCount)
2449{
2450 uint32_t gpu_index;
2451 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2452 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2453
2454 if (icd->GetPhysicalDeviceQueueCount)
2455 res = icd->GetPhysicalDeviceQueueCount(gpu, pCount);
2456
2457 return res;
2458}
2459
2460VkResult loader_GetPhysicalDeviceQueueProperties (
2461 VkPhysicalDevice gpu,
2462 uint32_t count,
2463 VkPhysicalDeviceQueueProperties * pProperties)
2464{
2465 uint32_t gpu_index;
2466 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2467 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2468
2469 if (icd->GetPhysicalDeviceQueueProperties)
2470 res = icd->GetPhysicalDeviceQueueProperties(gpu, count, pProperties);
2471
2472 return res;
2473}
2474
2475VkResult loader_GetPhysicalDeviceMemoryProperties (
2476 VkPhysicalDevice gpu,
2477 VkPhysicalDeviceMemoryProperties* pProperties)
2478{
2479 uint32_t gpu_index;
2480 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2481 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2482
2483 if (icd->GetPhysicalDeviceMemoryProperties)
2484 res = icd->GetPhysicalDeviceMemoryProperties(gpu, pProperties);
Jon Ashburn3da71f22015-05-14 12:43:38 -06002485
2486 return res;
2487}
2488
Chris Forbesbc0bb772015-06-21 22:55:02 +12002489VkResult loader_GetPhysicalDeviceFeatures(
2490 VkPhysicalDevice physicalDevice,
2491 VkPhysicalDeviceFeatures* pFeatures)
2492{
2493 uint32_t gpu_index;
2494 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2495 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2496
2497 if (icd->GetPhysicalDeviceFeatures)
2498 res = icd->GetPhysicalDeviceFeatures(physicalDevice, pFeatures);
2499
2500 return res;
2501}
2502
2503VkResult loader_GetPhysicalDeviceFormatInfo(
2504 VkPhysicalDevice physicalDevice,
2505 VkFormat format,
2506 VkFormatProperties* pFormatInfo)
2507{
2508 uint32_t gpu_index;
2509 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2510 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2511
2512 if (icd->GetPhysicalDeviceFormatInfo)
2513 res = icd->GetPhysicalDeviceFormatInfo(physicalDevice, format, pFormatInfo);
2514
2515 return res;
2516}
2517
2518VkResult loader_GetPhysicalDeviceLimits(
2519 VkPhysicalDevice physicalDevice,
2520 VkPhysicalDeviceLimits* pLimits)
2521{
2522 uint32_t gpu_index;
2523 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2524 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2525
2526 if (icd->GetPhysicalDeviceLimits)
2527 res = icd->GetPhysicalDeviceLimits(physicalDevice, pLimits);
2528
2529 return res;
2530}
2531
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002532VkResult loader_CreateDevice(
2533 VkPhysicalDevice gpu,
2534 const VkDeviceCreateInfo* pCreateInfo,
2535 VkDevice* pDevice)
2536{
2537 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06002538 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002539 struct loader_device *dev;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002540 VkResult res;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002541
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002542 if (!icd->CreateDevice) {
2543 return VK_ERROR_INITIALIZATION_FAILED;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002544 }
2545
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002546 /*
2547 * TODO: Must filter CreateInfo extension list to only
2548 * those extensions supported by the ICD.
2549 * TODO: Probably should verify that every extension is
2550 * covered by either the ICD or some layer.
2551 */
2552
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002553 res = icd->CreateDevice(gpu, pCreateInfo, pDevice);
2554 if (res != VK_SUCCESS) {
2555 return res;
2556 }
2557
2558 dev = loader_add_logical_device(*pDevice, &icd->logical_device_list);
2559 if (dev == NULL) {
2560 return VK_ERROR_OUT_OF_HOST_MEMORY;
2561 }
2562 PFN_vkGetDeviceProcAddr get_proc_addr = icd->GetDeviceProcAddr;
2563 loader_init_device_dispatch_table(&dev->loader_dispatch, get_proc_addr,
2564 icd->gpus[gpu_index], icd->gpus[gpu_index]);
2565
2566 dev->loader_dispatch.CreateDevice = scratch_vkCreateDevice;
2567 loader_init_dispatch(*pDevice, &dev->loader_dispatch);
2568
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002569 /*
2570 * Put together the complete list of extensions to enable
2571 * This includes extensions requested via environment variables.
2572 */
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06002573 loader_enable_device_layers(icd, dev, pCreateInfo);
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002574
2575 /*
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002576 * Load the libraries and build the device chain
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002577 * terminating with the selected device.
2578 */
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06002579 loader_activate_device_layers(icd, dev, *pDevice);
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002580
2581 res = dev->loader_dispatch.CreateDevice(gpu, pCreateInfo, pDevice);
2582
2583 dev->loader_dispatch.CreateDevice = icd->CreateDevice;
2584
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002585 return res;
2586}
2587
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -06002588static void * VKAPI loader_GetInstanceProcAddr(VkInstance instance, const char * pName)
Jon Ashburnb0fbe912015-05-06 10:15:07 -06002589{
Jon Ashburn07daee72015-05-21 18:13:33 -06002590 if (instance == VK_NULL_HANDLE)
2591 return NULL;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002592
Jon Ashburn07daee72015-05-21 18:13:33 -06002593 void *addr;
2594 /* get entrypoint addresses that are global (in the loader)*/
2595 addr = globalGetProcAddr(pName);
2596 if (addr)
2597 return addr;
Jon Ashburnb0fbe912015-05-06 10:15:07 -06002598
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002599 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
2600
Jon Ashburn922c8f62015-06-18 09:05:37 -06002601 /* return any extension global entrypoints */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002602 addr = debug_report_instance_gpa(ptr_instance, pName);
2603 if (addr) {
2604 return addr;
2605 }
2606
Jon Ashburn922c8f62015-06-18 09:05:37 -06002607 /* TODO Remove this once WSI has no loader special code */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002608 addr = wsi_lunarg_GetInstanceProcAddr(instance, pName);
David Pinedoa0a8a242015-06-24 15:29:18 -06002609 if (addr) {
Jon Ashburn922c8f62015-06-18 09:05:37 -06002610 return addr;
David Pinedoa0a8a242015-06-24 15:29:18 -06002611 }
Jon Ashburn07daee72015-05-21 18:13:33 -06002612
2613 /* return the instance dispatch table entrypoint for extensions */
2614 const VkLayerInstanceDispatchTable *disp_table = * (VkLayerInstanceDispatchTable **) instance;
2615 if (disp_table == NULL)
2616 return NULL;
2617
2618 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
2619 if (addr)
2620 return addr;
Jon Ashburnb0fbe912015-05-06 10:15:07 -06002621
2622 return NULL;
2623}
2624
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -06002625LOADER_EXPORT void * VKAPI vkGetInstanceProcAddr(VkInstance instance, const char * pName)
2626{
2627 return loader_GetInstanceProcAddr(instance, pName);
2628}
2629
2630static void * VKAPI loader_GetDeviceProcAddr(VkDevice device, const char * pName)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002631{
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06002632 if (device == VK_NULL_HANDLE) {
2633 return NULL;
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07002634 }
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002635
Chia-I Wuf46b81a2015-01-04 11:12:47 +08002636 void *addr;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002637
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002638 /* for entrypoints that loader must handle (ie non-dispatchable or create object)
2639 make sure the loader entrypoint is returned */
2640 addr = loader_non_passthrough_gpa(pName);
Ian Elliotte19c9152015-04-15 12:53:19 -06002641 if (addr) {
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002642 return addr;
Ian Elliotte19c9152015-04-15 12:53:19 -06002643 }
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002644
Jon Ashburn07daee72015-05-21 18:13:33 -06002645 /* return any extension device entrypoints the loader knows about */
Jon Ashburn922c8f62015-06-18 09:05:37 -06002646 /* TODO once WSI has no loader special code remove this */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002647 addr = wsi_lunarg_GetDeviceProcAddr(device, pName);
David Pinedoa0a8a242015-06-24 15:29:18 -06002648 if (addr) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002649 return addr;
David Pinedoa0a8a242015-06-24 15:29:18 -06002650 }
Jon Ashburn07daee72015-05-21 18:13:33 -06002651
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002652 /* return the dispatch table entrypoint for the fastest case */
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06002653 const VkLayerDispatchTable *disp_table = * (VkLayerDispatchTable **) device;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002654 if (disp_table == NULL)
2655 return NULL;
2656
Jon Ashburn27cd5842015-05-12 17:26:48 -06002657 addr = loader_lookup_device_dispatch_table(disp_table, pName);
Chia-I Wuf46b81a2015-01-04 11:12:47 +08002658 if (addr)
2659 return addr;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002660 else {
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06002661 if (disp_table->GetDeviceProcAddr == NULL)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002662 return NULL;
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06002663 return disp_table->GetDeviceProcAddr(device, pName);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002664 }
2665}
2666
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -06002667LOADER_EXPORT void * VKAPI vkGetDeviceProcAddr(VkDevice device, const char * pName)
2668{
2669 return loader_GetDeviceProcAddr(device, pName);
2670}
2671
Tony Barbour59a47322015-06-24 16:06:58 -06002672LOADER_EXPORT VkResult VKAPI vkGetGlobalExtensionProperties(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002673 const char* pLayerName,
2674 uint32_t* pCount,
2675 VkExtensionProperties* pProperties)
2676{
2677 struct loader_extension_list *global_extension_list;
2678
2679 /* Scan/discover all ICD libraries in a single-threaded manner */
2680 loader_platform_thread_once(&once_icd, loader_icd_scan);
2681
2682 /* get layer libraries in a single-threaded manner */
2683 loader_platform_thread_once(&once_layer, loader_layer_scan);
2684
2685 /* merge any duplicate extensions */
2686 loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
2687
2688 uint32_t copy_size;
2689
2690 if (pCount == NULL) {
2691 return VK_ERROR_INVALID_POINTER;
2692 }
2693
2694 loader_platform_thread_lock_mutex(&loader_lock);
2695
2696 global_extension_list = loader_global_extensions(pLayerName);
2697 if (global_extension_list == NULL) {
2698 loader_platform_thread_unlock_mutex(&loader_lock);
2699 return VK_ERROR_INVALID_LAYER;
2700 }
2701
2702 if (pProperties == NULL) {
2703 *pCount = global_extension_list->count;
2704 loader_platform_thread_unlock_mutex(&loader_lock);
2705 return VK_SUCCESS;
2706 }
2707
2708 copy_size = *pCount < global_extension_list->count ? *pCount : global_extension_list->count;
2709 for (uint32_t i = 0; i < copy_size; i++) {
2710 memcpy(&pProperties[i],
2711 &global_extension_list->list[i].info,
2712 sizeof(VkExtensionProperties));
2713 }
2714 *pCount = copy_size;
2715
2716 loader_platform_thread_unlock_mutex(&loader_lock);
2717
2718 if (copy_size < global_extension_list->count) {
2719 return VK_INCOMPLETE;
2720 }
2721
2722 return VK_SUCCESS;
2723}
2724
2725LOADER_EXPORT VkResult VKAPI vkGetGlobalLayerProperties(
2726 uint32_t* pCount,
2727 VkLayerProperties* pProperties)
Tony Barbour59a47322015-06-24 16:06:58 -06002728{
Jon Ashburn6301a0f2015-05-29 13:15:39 -06002729
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06002730 /* Scan/discover all ICD libraries in a single-threaded manner */
2731 loader_platform_thread_once(&once_icd, loader_icd_scan);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07002732
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06002733 /* get layer libraries in a single-threaded manner */
Jon Ashburn5ef20602015-07-02 09:40:15 -06002734 loader_platform_thread_once(&once_layer, loader_layer_scan);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07002735
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06002736 /* merge any duplicate extensions */
2737 loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
2738
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002739 uint32_t copy_size;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06002740
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002741 if (pCount == NULL) {
2742 return VK_ERROR_INVALID_POINTER;
2743 }
2744
2745 /* TODO: do we still need to lock */
Jon Ashburn6301a0f2015-05-29 13:15:39 -06002746 loader_platform_thread_lock_mutex(&loader_lock);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002747
2748 struct loader_layer_list *layer_list;
2749 layer_list = loader_global_layers();
2750
2751 if (pProperties == NULL) {
2752 *pCount = layer_list->count;
2753 loader_platform_thread_unlock_mutex(&loader_lock);
2754 return VK_SUCCESS;
2755 }
2756
2757 copy_size = *pCount < layer_list->count ? *pCount : layer_list->count;
2758 for (uint32_t i = 0; i < copy_size; i++) {
2759 memcpy(&pProperties[i], &layer_list->list[i].info, sizeof(VkLayerProperties));
2760 }
2761 *pCount = copy_size;
Tony Barbour59a47322015-06-24 16:06:58 -06002762
Jon Ashburn6301a0f2015-05-29 13:15:39 -06002763 loader_platform_thread_unlock_mutex(&loader_lock);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002764
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002765 if (copy_size < layer_list->count) {
2766 return VK_INCOMPLETE;
2767 }
Tony Barbour59a47322015-06-24 16:06:58 -06002768
2769 return VK_SUCCESS;
2770}
2771
2772VkResult loader_GetPhysicalDeviceExtensionProperties(
2773 VkPhysicalDevice gpu,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002774 const char* pLayerName,
2775 uint32_t* pCount,
Tony Barbour59a47322015-06-24 16:06:58 -06002776 VkExtensionProperties* pProperties)
2777{
2778 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06002779 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002780 uint32_t copy_size;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07002781
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002782 if (pCount == NULL) {
2783 return VK_ERROR_INVALID_POINTER;
2784 }
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002785
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002786 uint32_t count;
2787 struct loader_extension_list *list;
2788 loader_physical_device_extensions(icd, gpu_index, pLayerName, &count, &list);
2789
2790 if (pProperties == NULL) {
2791 *pCount = count;
2792 return VK_SUCCESS;
2793 }
2794
2795 copy_size = *pCount < count ? *pCount : count;
2796 for (uint32_t i = 0; i < copy_size; i++) {
2797 memcpy(&pProperties[i],
2798 &list->list[i].info,
2799 sizeof(VkExtensionProperties));
2800 }
2801 *pCount = copy_size;
2802
2803 if (copy_size < count) {
2804 return VK_INCOMPLETE;
2805 }
2806
2807 return VK_SUCCESS;
2808}
2809
2810VkResult loader_GetPhysicalDeviceLayerProperties(
2811 VkPhysicalDevice gpu,
2812 uint32_t* pCount,
2813 VkLayerProperties* pProperties)
2814{
2815 uint32_t gpu_index;
2816 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2817 uint32_t copy_size;
2818
2819 if (pCount == NULL) {
2820 return VK_ERROR_INVALID_POINTER;
2821 }
2822
2823 uint32_t count;
2824 struct loader_layer_list *layer_list;
2825 loader_physical_device_layers(icd, &count, &layer_list);
2826
2827 if (pProperties == NULL) {
2828 *pCount = count;
2829 return VK_SUCCESS;
2830 }
2831
2832 copy_size = *pCount < count ? *pCount : count;
2833 for (uint32_t i = 0; i < copy_size; i++) {
2834 memcpy(&pProperties[i],
2835 &layer_list->list[i].info,
2836 sizeof(VkLayerProperties));
2837 }
2838 *pCount = copy_size;
2839
2840 if (copy_size < count) {
2841 return VK_INCOMPLETE;
2842 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002843
2844 return VK_SUCCESS;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002845}