blob: 834986f404d2228d6246a31fdf200bb8bb9b0ac3 [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 Ashburn27cd5842015-05-12 17:26:48 -060045#include "gpa_helper.h"
46#include "table_ops.h"
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060047#include "debug_report.h"
Tobin Ehlis0c6f9ee2015-07-03 09:42:57 -060048#include "vk_icd.h"
Jon Ashburn2077e382015-06-29 11:25:34 -060049#include "cJSON.h"
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080050
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060051void loader_add_to_ext_list(
52 struct loader_extension_list *ext_list,
53 uint32_t prop_list_count,
54 const struct loader_extension_property *prop_list);
55
Courtney Goeltzenleuchtered488302015-06-01 14:09:34 -060056static loader_platform_dl_handle loader_add_layer_lib(
57 const char *chain_type,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -060058 struct loader_layer_properties *layer_prop);
Courtney Goeltzenleuchtered488302015-06-01 14:09:34 -060059
60static void loader_remove_layer_lib(
61 struct loader_instance *inst,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -060062 struct loader_layer_properties *layer_prop);
Courtney Goeltzenleuchtered488302015-06-01 14:09:34 -060063
Jon Ashburn27cd5842015-05-12 17:26:48 -060064struct loader_struct loader = {0};
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080065
Courtney Goeltzenleuchter2d3ba632015-07-12 14:35:22 -060066static PFN_vkVoidFunction VKAPI loader_GetInstanceProcAddr(VkInstance instance, const char * pName);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -060067static bool loader_init_ext_list(struct loader_extension_list *ext_info);
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -060068
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -060069enum loader_debug {
Courtney Goeltzenleuchterf3387652015-07-08 18:41:08 -060070 LOADER_INFO_BIT = 0x01,
71 LOADER_WARN_BIT = 0x02,
72 LOADER_PERF_BIT = 0x04,
73 LOADER_ERROR_BIT = 0x08,
74 LOADER_DEBUG_BIT = 0x10,
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -060075};
76
77uint32_t g_loader_debug = 0;
78uint32_t g_loader_log_msgs = 0;
79
Jon Ashburn6301a0f2015-05-29 13:15:39 -060080//thread safety lock for accessing global data structures such as "loader"
81// all entrypoints on the instance chain need to be locked except GPA
Jon Ashburn2077e382015-06-29 11:25:34 -060082// additionally CreateDevice and DestroyDevice needs to be locked
Jon Ashburn6301a0f2015-05-29 13:15:39 -060083loader_platform_thread_mutex loader_lock;
84
Ian Elliottd3ef02f2015-07-06 14:36:13 -060085// This table contains the loader's instance dispatch table, which contains
86// default functions if no instance layers are activated. This contains
87// pointers to "terminator functions".
Jon Ashburn6301a0f2015-05-29 13:15:39 -060088const VkLayerInstanceDispatchTable instance_disp = {
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -060089 .GetInstanceProcAddr = loader_GetInstanceProcAddr,
Jon Ashburn27cd5842015-05-12 17:26:48 -060090 .CreateInstance = loader_CreateInstance,
91 .DestroyInstance = loader_DestroyInstance,
92 .EnumeratePhysicalDevices = loader_EnumeratePhysicalDevices,
Chris Forbesbc0bb772015-06-21 22:55:02 +120093 .GetPhysicalDeviceFeatures = loader_GetPhysicalDeviceFeatures,
Courtney Goeltzenleuchter2caec862015-07-12 12:52:09 -060094 .GetPhysicalDeviceFormatProperties = loader_GetPhysicalDeviceFormatProperties,
Chris Forbesbc0bb772015-06-21 22:55:02 +120095 .GetPhysicalDeviceLimits = loader_GetPhysicalDeviceLimits,
Tony Barbour59a47322015-06-24 16:06:58 -060096 .GetPhysicalDeviceProperties = loader_GetPhysicalDeviceProperties,
Tony Barbour59a47322015-06-24 16:06:58 -060097 .GetPhysicalDeviceQueueCount = loader_GetPhysicalDeviceQueueCount,
98 .GetPhysicalDeviceQueueProperties = loader_GetPhysicalDeviceQueueProperties,
99 .GetPhysicalDeviceMemoryProperties = loader_GetPhysicalDeviceMemoryProperties,
Tony Barbour59a47322015-06-24 16:06:58 -0600100 .GetPhysicalDeviceExtensionProperties = loader_GetPhysicalDeviceExtensionProperties,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600101 .GetPhysicalDeviceLayerProperties = loader_GetPhysicalDeviceLayerProperties,
Mark Lobodzinski16e8bef2015-07-03 15:58:09 -0600102 .GetPhysicalDeviceSparseImageFormatProperties = loader_GetPhysicalDeviceSparseImageFormatProperties,
Ian Elliottd3ef02f2015-07-06 14:36:13 -0600103 .GetPhysicalDeviceSurfaceSupportWSI = loader_GetPhysicalDeviceSurfaceSupportWSI,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600104 .DbgCreateMsgCallback = loader_DbgCreateMsgCallback,
105 .DbgDestroyMsgCallback = loader_DbgDestroyMsgCallback,
Jon Ashburn27cd5842015-05-12 17:26:48 -0600106};
107
108LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_icd);
109LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_layer);
110LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_exts);
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700111
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600112void* loader_heap_alloc(
113 struct loader_instance *instance,
114 size_t size,
115 VkSystemAllocType alloc_type)
116{
117 if (instance && instance->alloc_callbacks.pfnAlloc) {
118 /* TODO: What should default alignment be? 1, 4, 8, other? */
119 return instance->alloc_callbacks.pfnAlloc(instance->alloc_callbacks.pUserData, size, 4, alloc_type);
120 }
121 return malloc(size);
122}
123
124void* loader_aligned_heap_alloc(
125 struct loader_instance *instance,
126 size_t size,
127 size_t alignment,
128 VkSystemAllocType alloc_type)
129{
130 if (!instance && instance->alloc_callbacks.pfnAlloc) {
131 return instance->alloc_callbacks.pfnAlloc(instance->alloc_callbacks.pUserData, size, alignment, alloc_type);
132 }
Cody Northrop33fa0412015-07-08 16:48:37 -0600133#if defined(_WIN32)
134 return _aligned_malloc(alignment, size);
135#else
136 return aligned_alloc(alignment, size);
137#endif
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600138}
139
140void loader_heap_free(
141 struct loader_instance *instance,
142 void *pMem)
143{
144 if (!instance && instance->alloc_callbacks.pfnFree) {
Courtney Goeltzenleuchter922e1452015-07-10 17:39:59 -0600145 instance->alloc_callbacks.pfnFree(instance->alloc_callbacks.pUserData, pMem);
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600146 }
Courtney Goeltzenleuchter922e1452015-07-10 17:39:59 -0600147 free(pMem);
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600148}
149
Jon Ashburnffad94d2015-06-30 14:46:22 -0700150static void loader_log(VkFlags msg_type, int32_t msg_code,
151 const char *format, ...)
152{
153 char msg[256];
154 va_list ap;
155 int ret;
156
157 if (!(msg_type & g_loader_log_msgs)) {
158 return;
159 }
160
161 va_start(ap, format);
162 ret = vsnprintf(msg, sizeof(msg), format, ap);
163 if ((ret >= (int) sizeof(msg)) || ret < 0) {
164 msg[sizeof(msg)-1] = '\0';
165 }
166 va_end(ap);
167
Ian Elliott4470a302015-02-17 10:33:47 -0700168#if defined(WIN32)
Jon Ashburnffad94d2015-06-30 14:46:22 -0700169 OutputDebugString(msg);
170#endif
171 fputs(msg, stderr);
172 fputc('\n', stderr);
173}
174
175#if defined(WIN32)
176/**
177* Find the list of registry files (names within a key) in key "location".
178*
179* This function looks in the registry (hive = DEFAULT_VK_REGISTRY_HIVE) key as given in "location"
180* for a list or name/values which are added to a returned list (function return value).
181* The DWORD values within the key must be 0 or they are skipped.
182* Function return is a string with a ';' seperated list of filenames.
183* Function return is NULL if no valid name/value pairs are found in the key,
184* or the key is not found.
185*
186* \returns
187* A string list of filenames as pointer.
188* When done using the returned string list, pointer should be freed.
189*/
190static char *loader_get_registry_files(const char *location)
191{
192 LONG rtn_value;
193 HKEY hive, key;
194 DWORD access_flags = KEY_QUERY_VALUE;
195 char name[2048];
196 char *out = NULL;
197
198 hive = DEFAULT_VK_REGISTRY_HIVE;
199 rtn_value = RegOpenKeyEx(hive, location, 0, access_flags, &key);
200 if (rtn_value != ERROR_SUCCESS) {
201 // We didn't find the key. Try the 32-bit hive (where we've seen the
202 // key end up on some people's systems):
203 access_flags |= KEY_WOW64_32KEY;
204 rtn_value = RegOpenKeyEx(hive, location, 0, access_flags, &key);
205 if (rtn_value != ERROR_SUCCESS) {
206 // We still couldn't find the key, so give up:
207 return NULL;
208 }
209 }
210
211 DWORD idx = 0;
212 DWORD name_size = sizeof(name);
213 DWORD value;
214 DWORD total_size = 4096;
215 DWORD value_size = sizeof(value);
216 while((rtn_value = RegEnumValue(key, idx++, name, &name_size, NULL, NULL, (LPBYTE) &value, &value_size)) == ERROR_SUCCESS) {
217 if (value_size == sizeof(value) && value == 0) {
218 if (out == NULL) {
219 out = malloc(total_size);
220 out[0] = '\0';
221 }
222 else if (strlen(out) + name_size + 1 > total_size) {
223 out = realloc(out, total_size * 2);
224 total_size *= 2;
225 }
226 if (out == NULL) {
227 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory, failed loader_get_registry_files");
228 return NULL;
229 }
230 if (strlen(out) == 0)
231 snprintf(out, name_size + 1, "%s", name);
232 else
233 snprintf(out + strlen(out), name_size + 1, "%c%s", PATH_SEPERATOR, name);
234 }
235 }
236 return out;
237}
238
Ian Elliott4470a302015-02-17 10:33:47 -0700239#endif // WIN32
240
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600241bool compare_vk_extension_properties(const VkExtensionProperties *op1, const VkExtensionProperties *op2)
242{
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600243 return strcmp(op1->extName, op2->extName) == 0 ? true : false;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600244}
245
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -0600246/**
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600247 * Search the given ext_array for an extension
248 * matching the given vk_ext_prop
249 */
250bool has_vk_extension_property_array(
251 const VkExtensionProperties *vk_ext_prop,
252 const uint32_t count,
253 const VkExtensionProperties *ext_array)
254{
255 for (uint32_t i = 0; i < count; i++) {
256 if (compare_vk_extension_properties(vk_ext_prop, &ext_array[i]))
257 return true;
258 }
259 return false;
260}
261
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -0600262/**
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600263 * Search the given ext_list for an extension
264 * matching the given vk_ext_prop
265 */
266bool has_vk_extension_property(
267 const VkExtensionProperties *vk_ext_prop,
268 const struct loader_extension_list *ext_list)
269{
270 for (uint32_t i = 0; i < ext_list->count; i++) {
271 if (compare_vk_extension_properties(&ext_list->list[i].info, vk_ext_prop))
272 return true;
273 }
274 return false;
275}
276
277/*
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -0600278 * Search the given layer list for a layer matching the given layer name
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600279 */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600280static struct loader_layer_properties *get_layer_property(
281 const char *name,
282 const struct loader_layer_list *layer_list)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600283{
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600284 for (uint32_t i = 0; i < layer_list->count; i++) {
285 const VkLayerProperties *item = &layer_list->list[i].info;
286 if (strcmp(name, item->layerName) == 0)
287 return &layer_list->list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600288 }
289 return NULL;
290}
291
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600292static void loader_add_global_extensions(
Tony Barbour59a47322015-06-24 16:06:58 -0600293 const PFN_vkGetGlobalExtensionProperties fp_get_props,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600294 const char *lib_name,
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600295 const loader_platform_dl_handle lib_handle,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600296 const enum extension_origin origin,
297 struct loader_extension_list *ext_list)
298{
299 uint32_t i, count;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600300 struct loader_extension_property ext_props;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600301 VkExtensionProperties *extension_properties;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600302 VkResult res;
303
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -0600304 if (!fp_get_props) {
305 /* No GetGlobalExtensionProperties defined */
306 return;
307 }
308
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600309 res = fp_get_props(NULL, &count, NULL);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600310 if (res != VK_SUCCESS) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600311 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extension count from %s", lib_name);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600312 return;
313 }
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600314
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -0600315 if (count == 0) {
316 /* No ExtensionProperties to report */
317 return;
318 }
319
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600320 extension_properties = loader_stack_alloc(count * sizeof(VkExtensionProperties));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600321
322 res = fp_get_props(NULL, &count, extension_properties);
323 if (res != VK_SUCCESS) {
324 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extensions from %s", lib_name);
325 return;
326 }
Tony Barbour59a47322015-06-24 16:06:58 -0600327
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600328 for (i = 0; i < count; i++) {
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600329 memset(&ext_props, 0, sizeof(ext_props));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600330 memcpy(&ext_props.info, &extension_properties[i], sizeof(VkExtensionProperties));
331 //TODO eventually get this from the layer config file
332 ext_props.origin = origin;
333 ext_props.lib_name = lib_name;
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600334
Courtney Goeltzenleuchter53043732015-07-12 13:20:05 -0600335 char spec_version[64];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600336
337 snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
338 VK_MAJOR(ext_props.info.specVersion),
339 VK_MINOR(ext_props.info.specVersion),
340 VK_PATCH(ext_props.info.specVersion));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600341
342 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter53043732015-07-12 13:20:05 -0600343 "Global Extension: %s (%s) version %s",
344 ext_props.info.extName, lib_name, spec_version);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600345 loader_add_to_ext_list(ext_list, 1, &ext_props);
346 }
347
348 return;
349}
350
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600351static void loader_add_physical_device_extensions(
352 PFN_vkGetPhysicalDeviceExtensionProperties get_phys_dev_ext_props,
353 VkPhysicalDevice physical_device,
354 const enum extension_origin origin,
355 const char *lib_name,
356 struct loader_extension_list *ext_list)
357{
358 uint32_t i, count;
359 VkResult res;
360 struct loader_extension_property ext_props;
361 VkExtensionProperties *extension_properties;
362
363 memset(&ext_props, 0, sizeof(ext_props));
364 ext_props.origin = origin;
365 ext_props.lib_name = lib_name;
366
367 if (get_phys_dev_ext_props) {
368 res = get_phys_dev_ext_props(physical_device, NULL, &count, NULL);
369 if (res == VK_SUCCESS && count > 0) {
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600370
371 extension_properties = loader_stack_alloc(count * sizeof(VkExtensionProperties));
372
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600373 res = get_phys_dev_ext_props(physical_device, NULL, &count, extension_properties);
374 for (i = 0; i < count; i++) {
Courtney Goeltzenleuchter53043732015-07-12 13:20:05 -0600375 char spec_version[64];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600376
377 memcpy(&ext_props.info, &extension_properties[i], sizeof(VkExtensionProperties));
378
379 snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
380 VK_MAJOR(ext_props.info.specVersion),
381 VK_MINOR(ext_props.info.specVersion),
382 VK_PATCH(ext_props.info.specVersion));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600383
384 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter53043732015-07-12 13:20:05 -0600385 "PhysicalDevice Extension: %s (%s) version %s",
386 ext_props.info.extName, lib_name, spec_version);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600387 loader_add_to_ext_list(ext_list, 1, &ext_props);
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600388 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600389 } else {
390 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 -0600391 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600392 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600393
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600394 return;
395}
396
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600397static void loader_add_physical_device_layer_properties(
398 struct loader_icd *icd,
399 char *lib_name,
400 const loader_platform_dl_handle lib_handle)
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600401{
402 uint32_t i, count;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600403 VkLayerProperties *layer_properties;
404 PFN_vkGetPhysicalDeviceExtensionProperties fp_get_ext_props;
405 PFN_vkGetPhysicalDeviceLayerProperties fp_get_layer_props;
406 VkPhysicalDevice gpu = icd->gpus[0];
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600407 VkResult res;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600408
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600409 fp_get_ext_props = loader_platform_get_proc_address(lib_handle, "vkGetPhysicalDeviceExtensionProperties");
410 if (!fp_get_ext_props) {
411 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
412 "Couldn't dlsym vkGetPhysicalDeviceExtensionProperties from library %s",
413 lib_name);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600414 }
415
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600416 fp_get_layer_props = loader_platform_get_proc_address(lib_handle, "vkGetPhysicalDeviceLayerProperties");
417 if (!fp_get_layer_props) {
418 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
419 "Couldn't dlsym vkGetPhysicalDeviceLayerProperties from library %s",
420 lib_name);
421 return;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600422 }
423
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600424 /*
425 * NOTE: We assume that all GPUs of an ICD support the same PhysicalDevice
426 * layers and extensions. Thus only ask for info about the first gpu.
427 */
428 res = fp_get_layer_props(gpu, &count, NULL);
429 if (res != VK_SUCCESS) {
430 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Error getting PhysicalDevice layer count from %s", lib_name);
431 return;
432 }
433
434 if (count == 0) {
435 return;
436 }
437
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600438 layer_properties = loader_stack_alloc(count * sizeof(VkLayerProperties));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600439
440 res = fp_get_layer_props(gpu, &count, layer_properties);
441 if (res != VK_SUCCESS) {
442 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Error getting %d PhysicalDevice layer properties from %s",
443 count, lib_name);
444 return;
445 }
446
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -0600447 //TODO get layer properties from manifest file
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600448 for (i = 0; i < count; i++) {
449 struct loader_layer_properties layer;
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600450
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600451 memset(&layer, 0, sizeof(struct loader_layer_properties));
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600452
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600453 layer.lib_info.lib_name = lib_name;
454 memcpy(&layer.info, &layer_properties[i], sizeof(VkLayerProperties));
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600455
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600456 loader_init_ext_list(&layer.instance_extension_list);
457 loader_init_ext_list(&layer.device_extension_list);
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600458
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600459 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Collecting PhysicalDevice extensions for layer %s (%s)",
460 layer.info.layerName, layer.info.description);
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600461
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600462 loader_add_physical_device_extensions(
463 fp_get_ext_props,
464 icd->gpus[i],
465 VK_EXTENSION_ORIGIN_LAYER,
466 lib_name,
467 &layer.device_extension_list);
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600468
469 loader_add_to_layer_list(&icd->layer_properties_cache, 1, &layer);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600470 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600471 return;
472}
473
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600474static bool loader_init_ext_list(struct loader_extension_list *ext_info)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600475{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600476 ext_info->capacity = 32 * sizeof(struct loader_extension_property);
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600477 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600478 ext_info->list = malloc(ext_info->capacity);
479 if (ext_info->list == NULL) {
480 return false;
481 }
482 memset(ext_info->list, 0, ext_info->capacity);
483 ext_info->count = 0;
484 return true;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600485}
486
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -0600487void loader_destroy_ext_list(struct loader_extension_list *ext_info)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600488{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600489 free(ext_info->list);
490 ext_info->count = 0;
491 ext_info->capacity = 0;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600492}
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600493
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600494/**
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600495 * Search the given search_list for any layers in the props list.
496 * Add these to the output layer_list. Don't add duplicates to the output layer_list.
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600497 */
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -0600498static VkResult loader_add_layer_names_to_list(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600499 struct loader_layer_list *output_list,
500 uint32_t name_count,
501 const char * const *names,
502 const struct loader_layer_list *search_list)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600503{
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600504 struct loader_layer_properties *layer_prop;
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -0600505 VkResult err = VK_SUCCESS;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600506
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600507 for (uint32_t i = 0; i < name_count; i++) {
508 const char *search_target = names[i];
509 layer_prop = get_layer_property(search_target, search_list);
510 if (!layer_prop) {
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -0600511 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Unable to find layer %s", search_target);
512 err = VK_ERROR_INVALID_LAYER;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600513 continue;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600514 }
515
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600516 loader_add_to_layer_list(output_list, 1, layer_prop);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600517 }
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -0600518
519 return err;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600520}
521
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600522/*
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -0600523 * Append non-duplicate extension properties defined in props
524 * to the given ext_list.
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600525 */
526void loader_add_to_ext_list(
527 struct loader_extension_list *ext_list,
528 uint32_t prop_list_count,
529 const struct loader_extension_property *props)
530{
531 uint32_t i;
532 struct loader_extension_property *cur_ext;
533
534 if (ext_list->list == NULL || ext_list->capacity == 0) {
535 loader_init_ext_list(ext_list);
536 }
537
538 if (ext_list->list == NULL)
539 return;
540
541 for (i = 0; i < prop_list_count; i++) {
542 cur_ext = (struct loader_extension_property *) &props[i];
543
544 // look for duplicates
545 if (has_vk_extension_property(&cur_ext->info, ext_list)) {
546 continue;
547 }
548
549 // add to list at end
550 // check for enough capacity
551 if (ext_list->count * sizeof(struct loader_extension_property)
552 >= ext_list->capacity) {
553 // double capacity
554 ext_list->capacity *= 2;
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600555 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600556 ext_list->list = realloc(ext_list->list, ext_list->capacity);
557 }
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600558
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600559 memcpy(&ext_list->list[ext_list->count], cur_ext, sizeof(struct loader_extension_property));
560 ext_list->count++;
561 }
562}
563
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600564/*
565 * Manage lists of VkLayerProperties
566 */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600567static bool loader_init_layer_list(struct loader_layer_list *list)
568{
569 list->capacity = 32 * sizeof(struct loader_layer_properties);
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600570 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600571 list->list = malloc(list->capacity);
572 if (list->list == NULL) {
573 return false;
574 }
575 memset(list->list, 0, list->capacity);
576 list->count = 0;
577 return true;
578}
579
580void loader_destroy_layer_list(struct loader_layer_list *layer_list)
581{
582 free(layer_list->list);
583 layer_list->count = 0;
584 layer_list->capacity = 0;
585}
586
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600587/*
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600588 * Manage list of layer libraries (loader_lib_info)
589 */
590static bool loader_init_layer_library_list(struct loader_layer_library_list *list)
591{
592 list->capacity = 32 * sizeof(struct loader_lib_info);
593 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
594 list->list = malloc(list->capacity);
595 if (list->list == NULL) {
596 return false;
597 }
598 memset(list->list, 0, list->capacity);
599 list->count = 0;
600 return true;
601}
602
603void loader_destroy_layer_library_list(struct loader_layer_library_list *list)
604{
605 for (uint32_t i = 0; i < list->count; i++) {
606 free(list->list[i].lib_name);
607 }
608 free(list->list);
609 list->count = 0;
610 list->capacity = 0;
611}
612
613void loader_add_to_layer_library_list(
614 struct loader_layer_library_list *list,
615 uint32_t item_count,
616 const struct loader_lib_info *new_items)
617{
618 uint32_t i;
619 struct loader_lib_info *item;
620
621 if (list->list == NULL || list->capacity == 0) {
622 loader_init_layer_library_list(list);
623 }
624
625 if (list->list == NULL)
626 return;
627
628 for (i = 0; i < item_count; i++) {
629 item = (struct loader_lib_info *) &new_items[i];
630
631 // look for duplicates
632 for (uint32_t j = 0; j < list->count; j++) {
633 if (strcmp(list->list[i].lib_name, new_items->lib_name) == 0) {
634 continue;
635 }
636 }
637
638 // add to list at end
639 // check for enough capacity
640 if (list->count * sizeof(struct loader_lib_info)
641 >= list->capacity) {
642 // double capacity
643 list->capacity *= 2;
644 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
645 list->list = realloc(list->list, list->capacity);
646 }
647
648 memcpy(&list->list[list->count], item, sizeof(struct loader_lib_info));
649 list->count++;
650 }
651}
652
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -0600653#if 0
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600654/*
655 * Add's library indicated by lib_name to list if it
656 * implements vkGetGlobalLayerProperties or
657 * vkGetPhysicalDeviceLayerProperties.
658 */
659static void loader_add_layer_library(
660 struct loader_instance *instance,
661 const char *lib_name,
662 const loader_platform_dl_handle lib_handle,
663 struct loader_layer_library_list *list)
664{
665 struct loader_lib_info *library_info;
666 PFN_vkGetPhysicalDeviceLayerProperties fp_get_phydev_props;
667 PFN_vkGetGlobalLayerProperties fp_get_layer_props;
668
669 fp_get_layer_props = loader_platform_get_proc_address(lib_handle, "vkGetGlobalLayerProperties");
670 fp_get_phydev_props = loader_platform_get_proc_address(lib_handle, "vkGetPhysicalDeviceLayerProperties");
671
672 if (!fp_get_layer_props && !fp_get_phydev_props)
673 return;
674
675 /*
676 * Allocate enough space for the library name to
677 * immediately follow the loader_lib_info structure
678 */
679 library_info = loader_heap_alloc(instance, sizeof(struct loader_lib_info) + strlen(lib_name) + 1, VK_SYSTEM_ALLOC_TYPE_INTERNAL);
680 if (!library_info) {
681 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
682 "Malloc for layer library list failed: %s line: %d", __FILE__, __LINE__);
683 return;
684 }
685 memset(library_info, 0, sizeof(struct loader_lib_info));
686 library_info->lib_name = (char *) &library_info[1];
687 strcpy(library_info->lib_name, lib_name);
688
689 loader_add_to_layer_library_list(list, 1, library_info);
690}
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -0600691#endif
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600692/*
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600693 * Search the given layer list for a list
694 * matching the given VkLayerProperties
695 */
696bool has_vk_layer_property(
697 const VkLayerProperties *vk_layer_prop,
698 const struct loader_layer_list *list)
699{
700 for (uint32_t i = 0; i < list->count; i++) {
701 if (strcmp(vk_layer_prop->layerName, list->list[i].info.layerName) == 0)
702 return true;
703 }
704 return false;
705}
706
707/*
708 * Search the given layer list for a layer
709 * matching the given name
710 */
711bool has_layer_name(
712 const char *name,
713 const struct loader_layer_list *list)
714{
715 for (uint32_t i = 0; i < list->count; i++) {
716 if (strcmp(name, list->list[i].info.layerName) == 0)
717 return true;
718 }
719 return false;
720}
721
722/*
723 * Append non-duplicate layer properties defined in prop_list
724 * to the given layer_info list
725 */
726void loader_add_to_layer_list(
727 struct loader_layer_list *list,
728 uint32_t prop_list_count,
729 const struct loader_layer_properties *props)
730{
731 uint32_t i;
732 struct loader_layer_properties *layer;
733
734 if (list->list == NULL || list->capacity == 0) {
735 loader_init_layer_list(list);
736 }
737
738 if (list->list == NULL)
739 return;
740
741 for (i = 0; i < prop_list_count; i++) {
742 layer = (struct loader_layer_properties *) &props[i];
743
744 // look for duplicates
745 if (has_vk_layer_property(&layer->info, list)) {
746 continue;
747 }
748
749 // add to list at end
750 // check for enough capacity
751 if (list->count * sizeof(struct loader_layer_properties)
752 >= list->capacity) {
753 // double capacity
754 list->capacity *= 2;
755 list->list = realloc(list->list, list->capacity);
756 }
757
758 memcpy(&list->list[list->count], layer, sizeof(struct loader_layer_properties));
759 list->count++;
760 }
761}
762
Jon Ashburnbd332cc2015-07-07 10:27:45 -0600763/**
764 * Search the search_list for any layer with a name
765 * that matches the given name and a type that matches the given type
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600766 * Add all matching layers to the found_list
Jon Ashburnbd332cc2015-07-07 10:27:45 -0600767 * Do not add if found loader_layer_properties is already
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600768 * on the found_list.
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600769 */
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600770static void loader_find_layer_name_add_list(
771 const char *name,
Jon Ashburnbd332cc2015-07-07 10:27:45 -0600772 const enum layer_type type,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600773 const struct loader_layer_list *search_list,
774 struct loader_layer_list *found_list)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600775{
776 for (uint32_t i = 0; i < search_list->count; i++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600777 struct loader_layer_properties *layer_prop = &search_list->list[i];
Jon Ashburnbd332cc2015-07-07 10:27:45 -0600778 if (0 == strcmp(layer_prop->info.layerName, name) &&
779 (layer_prop->type & type)) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600780 /* Found a layer with the same name, add to found_list */
781 loader_add_to_layer_list(found_list, 1, layer_prop);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600782 }
783 }
784}
785
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -0600786static struct loader_extension_property *get_extension_property(
787 const char *name,
788 const struct loader_extension_list *list)
Jon Ashburnfc2e38c2015-04-14 09:15:32 -0600789{
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -0600790 for (uint32_t i = 0; i < list->count; i++) {
791 const VkExtensionProperties *item = &list->list[i].info;
792 if (strcmp(name, item->extName) == 0)
793 return &list->list[i];
Jon Ashburnfc2e38c2015-04-14 09:15:32 -0600794 }
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -0600795 return NULL;
Jon Ashburnfc2e38c2015-04-14 09:15:32 -0600796}
797
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600798/*
799 * For global exenstions implemented within the loader (i.e. DEBUG_REPORT
800 * the extension must provide two entry points for the loader to use:
801 * - "trampoline" entry point - this is the address returned by GetProcAddr
802 * and will always do what's necessary to support a global call.
803 * - "terminator" function - this function will be put at the end of the
804 * instance chain and will contain the necessary logica to call / process
805 * the extension for the appropriate ICDs that are available.
806 * There is no generic mechanism for including these functions, the references
807 * must be placed into the appropriate loader entry points.
808 * GetInstanceProcAddr: call extension GetInstanceProcAddr to check for GetProcAddr requests
809 * loader_coalesce_extensions(void) - add extension records to the list of global
810 * extension available to the app.
811 * instance_disp - add function pointer for terminator function to this array.
812 * The extension itself should be in a separate file that will be
813 * linked directly with the loader.
814 */
Jon Ashburn27cd5842015-05-12 17:26:48 -0600815void loader_coalesce_extensions(void)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600816{
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600817 struct loader_scanned_icds *icd_list = loader.scanned_icd_list;
818
819 // traverse scanned icd list adding non-duplicate extensions to the list
820 while (icd_list != NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600821 loader_add_to_ext_list(&loader.global_extensions,
822 icd_list->global_extension_list.count,
823 icd_list->global_extension_list.list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600824 icd_list = icd_list->next;
825 };
826
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600827 // Traverse loader's extensions, adding non-duplicate extensions to the list
Ian Elliottd3ef02f2015-07-06 14:36:13 -0600828 wsi_swapchain_add_instance_extensions(&loader.global_extensions);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600829 debug_report_add_instance_extensions(&loader.global_extensions);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600830}
831
Jon Ashburndc6fcad2015-06-10 10:06:06 -0600832static struct loader_icd *loader_get_icd_and_device(const VkDevice device,
833 struct loader_device **found_dev)
834{
835 *found_dev = NULL;
836 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
837 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
838 for (struct loader_device *dev = icd->logical_device_list; dev; dev = dev->next)
839 if (dev->device == device) {
840 *found_dev = dev;
841 return icd;
842 }
843 }
844 }
845 return NULL;
846}
847
848static void loader_destroy_logical_device(struct loader_device *dev)
849{
850 free(dev->app_extension_props);
Jon Ashburndc6fcad2015-06-10 10:06:06 -0600851 if (dev->activated_layer_list.count)
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600852 loader_destroy_layer_list(&dev->activated_layer_list);
Jon Ashburndc6fcad2015-06-10 10:06:06 -0600853 free(dev);
854}
855
856static struct loader_device *loader_add_logical_device(const VkDevice dev, struct loader_device **device_list)
857{
858 struct loader_device *new_dev;
859
860 new_dev = malloc(sizeof(struct loader_device));
861 if (!new_dev) {
862 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc struct laoder-device");
863 return NULL;
864 }
865
866 memset(new_dev, 0, sizeof(struct loader_device));
867
868 new_dev->next = *device_list;
869 new_dev->device = dev;
870 *device_list = new_dev;
871 return new_dev;
872}
873
874void loader_remove_logical_device(VkDevice device)
875{
876 struct loader_device *found_dev, *dev, *prev_dev;
877 struct loader_icd *icd;
878 icd = loader_get_icd_and_device(device, &found_dev);
879
880 if (!icd || !found_dev)
881 return;
882
883 prev_dev = NULL;
884 dev = icd->logical_device_list;
885 while (dev && dev != found_dev) {
886 prev_dev = dev;
887 dev = dev->next;
888 }
889
890 if (prev_dev)
891 prev_dev->next = found_dev->next;
892 else
893 icd->logical_device_list = found_dev->next;
894 loader_destroy_logical_device(found_dev);
895}
896
897
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600898static void loader_icd_destroy(
899 struct loader_instance *ptr_inst,
900 struct loader_icd *icd)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800901{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600902 ptr_inst->total_icd_count--;
Jon Ashburn128f9422015-05-28 19:16:58 -0600903 free(icd->gpus);
Courtney Goeltzenleuchter1f157ac2015-06-14 19:57:15 -0600904 for (struct loader_device *dev = icd->logical_device_list; dev; ) {
905 struct loader_device *next_dev = dev->next;
Jon Ashburndc6fcad2015-06-10 10:06:06 -0600906 loader_destroy_logical_device(dev);
Courtney Goeltzenleuchter1f157ac2015-06-14 19:57:15 -0600907 dev = next_dev;
908 }
Jon Ashburndc6fcad2015-06-10 10:06:06 -0600909
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800910 free(icd);
911}
912
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600913static struct loader_icd * loader_icd_create(const struct loader_scanned_icds *scanned)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800914{
915 struct loader_icd *icd;
916
917 icd = malloc(sizeof(*icd));
918 if (!icd)
919 return NULL;
920
Courtney Goeltzenleuchter55001bb2014-10-28 10:29:27 -0600921 memset(icd, 0, sizeof(*icd));
922
Jon Ashburn46d1f582015-01-28 11:01:35 -0700923 icd->scanned_icds = scanned;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800924
925 return icd;
926}
927
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600928static struct loader_icd *loader_icd_add(
929 struct loader_instance *ptr_inst,
930 const struct loader_scanned_icds *scanned)
Chia-I Wu13a61a52014-08-04 11:18:20 +0800931{
932 struct loader_icd *icd;
933
Jon Ashburn46d1f582015-01-28 11:01:35 -0700934 icd = loader_icd_create(scanned);
Chia-I Wu13a61a52014-08-04 11:18:20 +0800935 if (!icd)
936 return NULL;
937
Chia-I Wu13a61a52014-08-04 11:18:20 +0800938 /* prepend to the list */
Jon Ashburn46888392015-01-29 15:45:51 -0700939 icd->next = ptr_inst->icds;
940 ptr_inst->icds = icd;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600941 ptr_inst->total_icd_count++;
Chia-I Wu13a61a52014-08-04 11:18:20 +0800942
943 return icd;
944}
945
Jon Ashburn46d1f582015-01-28 11:01:35 -0700946static void loader_scanned_icd_add(const char *filename)
947{
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700948 loader_platform_dl_handle handle;
Tony Barbour1d2cd3f2015-07-03 10:33:54 -0600949 PFN_vkCreateInstance fp_create_inst;
950 PFN_vkGetGlobalExtensionProperties fp_get_global_ext_props;
951 PFN_vkGetPhysicalDeviceExtensionProperties fp_get_device_ext_props;
952 PFN_vkGetDeviceProcAddr fp_get_proc_addr;
Jon Ashburn46d1f582015-01-28 11:01:35 -0700953 struct loader_scanned_icds *new_node;
954
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700955 // Used to call: dlopen(filename, RTLD_LAZY);
956 handle = loader_platform_open_library(filename);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700957 if (!handle) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600958 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_open_library_error(filename));
Jon Ashburn46d1f582015-01-28 11:01:35 -0700959 return;
960 }
961
962#define LOOKUP(func_ptr, func) do { \
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600963 func_ptr = (PFN_vk ##func) loader_platform_get_proc_address(handle, "vk" #func); \
Jon Ashburn46d1f582015-01-28 11:01:35 -0700964 if (!func_ptr) { \
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600965 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
Jon Ashburn46d1f582015-01-28 11:01:35 -0700966 return; \
967 } \
968} while (0)
969
Jon Ashburn46888392015-01-29 15:45:51 -0700970 LOOKUP(fp_create_inst, CreateInstance);
Tony Barbour59a47322015-06-24 16:06:58 -0600971 LOOKUP(fp_get_global_ext_props, GetGlobalExtensionProperties);
Tony Barbour59a47322015-06-24 16:06:58 -0600972 LOOKUP(fp_get_device_ext_props, GetPhysicalDeviceExtensionProperties);
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600973 LOOKUP(fp_get_proc_addr, GetDeviceProcAddr);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700974#undef LOOKUP
975
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600976 new_node = (struct loader_scanned_icds *) malloc(sizeof(struct loader_scanned_icds)
977 + strlen(filename) + 1);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700978 if (!new_node) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600979 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
Jon Ashburn46d1f582015-01-28 11:01:35 -0700980 return;
981 }
982
983 new_node->handle = handle;
Jon Ashburn46888392015-01-29 15:45:51 -0700984 new_node->CreateInstance = fp_create_inst;
Tony Barbour59a47322015-06-24 16:06:58 -0600985 new_node->GetGlobalExtensionProperties = fp_get_global_ext_props;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600986 loader_init_ext_list(&new_node->global_extension_list);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600987 loader_init_ext_list(&new_node->device_extension_list);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700988 new_node->next = loader.scanned_icd_list;
Jon Ashburn46d1f582015-01-28 11:01:35 -0700989
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600990 new_node->lib_name = (char *) (new_node + 1);
991 if (!new_node->lib_name) {
992 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
993 return;
994 }
995 strcpy(new_node->lib_name, filename);
996
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600997 loader.scanned_icd_list = new_node;
998
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600999 loader_add_global_extensions(
Tony Barbour59a47322015-06-24 16:06:58 -06001000 (PFN_vkGetGlobalExtensionProperties) fp_get_global_ext_props,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001001 new_node->lib_name,
Jon Ashburn953bb3c2015-06-10 16:11:42 -06001002 handle,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001003 VK_EXTENSION_ORIGIN_ICD,
1004 &new_node->global_extension_list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001005}
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001006
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001007static struct loader_extension_list *loader_global_extensions(const char *pLayerName)
1008{
1009 if (pLayerName == NULL || (strlen(pLayerName) == 0)) {
1010 return &loader.global_extensions;
1011 }
1012
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06001013 /* Find and return global extension list for given layer */
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001014 for (uint32_t i = 0; i < loader.scanned_layers.count; i++) {
1015 struct loader_layer_properties *work_layer = &loader.scanned_layers.list[i];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001016 if (strcmp(work_layer->info.layerName, pLayerName) == 0) {
1017 return &work_layer->instance_extension_list;
1018 }
1019 }
1020
1021 return NULL;
1022}
1023
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001024static struct loader_layer_list *loader_scanned_layers()
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001025{
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001026 return &loader.scanned_layers;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001027}
1028
1029static void loader_physical_device_layers(
1030 struct loader_icd *icd,
1031 uint32_t *count,
1032 struct loader_layer_list **list)
1033{
1034 *count = icd->layer_properties_cache.count;
1035 *list = &icd->layer_properties_cache;
1036}
1037
1038static void loader_physical_device_extensions(
1039 struct loader_icd *icd,
1040 uint32_t gpu_idx,
1041 const char *layer_name,
1042 uint32_t *count,
1043 struct loader_extension_list **list)
1044{
Tony Barbourb5d2c942015-07-14 13:34:05 -06001045 *count = 0;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001046 if (layer_name == NULL || (strlen(layer_name) == 0)) {
1047 *count = icd->device_extension_cache[gpu_idx].count;
1048 *list = &icd->device_extension_cache[gpu_idx];
1049 return;
1050 }
1051 for (uint32_t i = 0; i < icd->layer_properties_cache.count; i++) {
1052 if (strcmp(layer_name, icd->layer_properties_cache.list[i].info.layerName) == 0) {
1053 *count = icd->layer_properties_cache.list[i].device_extension_list.count;
1054 *list = &icd->layer_properties_cache.list[i].device_extension_list;
Courtney Goeltzenleuchtercc44f2a2015-07-10 10:11:50 -06001055 break;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001056 }
1057 }
1058}
1059
Jon Ashburn3da71f22015-05-14 12:43:38 -06001060static void loader_icd_init_entrys(struct loader_icd *icd,
1061 struct loader_scanned_icds *scanned_icds)
1062{
1063 /* initialize entrypoint function pointers */
1064
1065 #define LOOKUP(func) do { \
1066 icd->func = (PFN_vk ##func) loader_platform_get_proc_address(scanned_icds->handle, "vk" #func); \
1067 if (!icd->func) { \
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001068 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
Jon Ashburn3da71f22015-05-14 12:43:38 -06001069 return; \
1070 } \
1071 } while (0)
1072
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001073 /* could change this to use GetInstanceProcAddr in driver instead of dlsym */
1074 LOOKUP(GetDeviceProcAddr);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001075 LOOKUP(DestroyInstance);
1076 LOOKUP(EnumeratePhysicalDevices);
Chris Forbesbc0bb772015-06-21 22:55:02 +12001077 LOOKUP(GetPhysicalDeviceFeatures);
Courtney Goeltzenleuchter2caec862015-07-12 12:52:09 -06001078 LOOKUP(GetPhysicalDeviceFormatProperties);
Chris Forbesbc0bb772015-06-21 22:55:02 +12001079 LOOKUP(GetPhysicalDeviceLimits);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001080 LOOKUP(CreateDevice);
Tony Barbour59a47322015-06-24 16:06:58 -06001081 LOOKUP(GetPhysicalDeviceProperties);
1082 LOOKUP(GetPhysicalDeviceMemoryProperties);
Tony Barbour59a47322015-06-24 16:06:58 -06001083 LOOKUP(GetPhysicalDeviceQueueCount);
1084 LOOKUP(GetPhysicalDeviceQueueProperties);
1085 LOOKUP(GetPhysicalDeviceExtensionProperties);
Mark Lobodzinski16e8bef2015-07-03 15:58:09 -06001086 LOOKUP(GetPhysicalDeviceSparseImageFormatProperties);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001087 LOOKUP(DbgCreateMsgCallback);
1088 LOOKUP(DbgDestroyMsgCallback);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001089#undef LOOKUP
1090
Ian Elliottd3ef02f2015-07-06 14:36:13 -06001091 icd->GetPhysicalDeviceSurfaceSupportWSI =
1092 (PFN_vkGetPhysicalDeviceSurfaceSupportWSI) loader_platform_get_proc_address(scanned_icds->handle,
1093 "vkGetPhysicalDeviceSurfaceSupportWSI");
1094
Jon Ashburn3da71f22015-05-14 12:43:38 -06001095 return;
1096}
1097
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001098static void loader_debug_init(void)
1099{
1100 const char *env;
1101
1102 if (g_loader_debug > 0)
1103 return;
1104
1105 g_loader_debug = 0;
1106
1107 /* parse comma-separated debug options */
1108 env = getenv("LOADER_DEBUG");
1109 while (env) {
1110 const char *p = strchr(env, ',');
1111 size_t len;
1112
1113 if (p)
1114 len = p - env;
1115 else
1116 len = strlen(env);
1117
1118 if (len > 0) {
1119 if (strncmp(env, "warn", len) == 0) {
1120 g_loader_debug |= LOADER_WARN_BIT;
1121 g_loader_log_msgs |= VK_DBG_REPORT_WARN_BIT;
1122 } else if (strncmp(env, "info", len) == 0) {
1123 g_loader_debug |= LOADER_INFO_BIT;
1124 g_loader_log_msgs |= VK_DBG_REPORT_INFO_BIT;
1125 } else if (strncmp(env, "perf", len) == 0) {
1126 g_loader_debug |= LOADER_PERF_BIT;
1127 g_loader_log_msgs |= VK_DBG_REPORT_PERF_WARN_BIT;
1128 } else if (strncmp(env, "error", len) == 0) {
1129 g_loader_debug |= LOADER_ERROR_BIT;
1130 g_loader_log_msgs |= VK_DBG_REPORT_ERROR_BIT;
1131 } else if (strncmp(env, "debug", len) == 0) {
1132 g_loader_debug |= LOADER_DEBUG_BIT;
1133 g_loader_log_msgs |= VK_DBG_REPORT_DEBUG_BIT;
1134 }
1135 }
1136
1137 if (!p)
1138 break;
1139
1140 env = p + 1;
1141 }
1142}
1143
Jon Ashburn2077e382015-06-29 11:25:34 -06001144struct loader_manifest_files {
1145 uint32_t count;
1146 char **filename_list;
1147};
1148
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001149/**
Jon Ashburn2077e382015-06-29 11:25:34 -06001150 * Get next file or dirname given a string list or registry key path
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001151 *
1152 * \returns
Jon Ashburn2077e382015-06-29 11:25:34 -06001153 * A pointer to first char in the next path.
1154 * The next path (or NULL) in the list is returned in next_path.
1155 * Note: input string is modified in some cases. PASS IN A COPY!
1156 */
Jon Ashburn2077e382015-06-29 11:25:34 -06001157static char *loader_get_next_path(char *path)
1158{
1159 uint32_t len;
1160 char *next;
1161
1162 if (path == NULL)
1163 return NULL;
1164 next = strchr(path, PATH_SEPERATOR);
1165 if (next == NULL) {
1166 len = (uint32_t) strlen(path);
1167 next = path + len;
1168 }
1169 else {
1170 *next = '\0';
1171 next++;
1172 }
1173
1174 return next;
1175}
1176
1177/**
Jon Ashburn15315172015-07-07 15:06:25 -06001178 * Given a path which is absolute or relative. Expand the path if relative otherwise
1179 * leave the path unmodified if absolute. The path which is relative from is
1180 * given in rel_base and should include trailing directory seperator '/'
1181 *
1182 * \returns
1183 * A string in out_fullpath of the full absolute path
1184 * Side effect is that dir string maybe modified.
1185 */
1186static void loader_expand_path(const char *path,
1187 const char *rel_base,
1188 size_t out_size,
1189 char *out_fullpath)
1190{
1191 if (loader_platform_is_path_absolute(path)) {
1192 strncpy(out_fullpath, path, out_size);
1193 out_fullpath[out_size - 1] = '\0';
1194 }
1195 else {
1196 // convert relative to absolute path based on rel_base
1197 size_t len = strlen(path);
1198 strncpy(out_fullpath, rel_base, out_size);
1199 out_fullpath[out_size - 1] = '\0';
1200 assert(out_size >= strlen(out_fullpath) + len + 1);
1201 strncat(out_fullpath, path, len);
1202 }
1203}
1204
1205/**
Jon Ashburn2077e382015-06-29 11:25:34 -06001206 * Given a filename (file) and a list of paths (dir), try to find an existing
1207 * file in the paths. If filename already is a path then no
1208 * searching in the given paths.
1209 *
1210 * \returns
1211 * A string in out_fullpath of either the full path or file.
1212 * Side effect is that dir string maybe modified.
1213 */
1214static void loader_get_fullpath(const char *file,
1215 char *dir,
1216 size_t out_size,
1217 char *out_fullpath)
1218{
1219 char *next_dir;
1220 if (strchr(file,DIRECTORY_SYMBOL) == NULL) {
1221 //find file exists with prepending given path
1222 while (*dir) {
1223 next_dir = loader_get_next_path(dir);
1224 snprintf(out_fullpath, out_size, "%s%c%s",
1225 dir, DIRECTORY_SYMBOL, file);
1226 if (loader_platform_file_exists(out_fullpath)) {
1227 return;
1228 }
1229 dir = next_dir;
1230 }
1231 }
1232 snprintf(out_fullpath, out_size, "%s", file);
1233}
1234
1235/**
1236 * Read a JSON file into a buffer.
1237 *
1238 * \returns
1239 * A pointer to a cJSON object representing the JSON parse tree.
1240 * This returned buffer should be freed by caller.
1241 */
1242static cJSON *loader_get_json(const char *filename)
1243{
1244 FILE *file;
1245 char *json_buf;
1246 cJSON *json;
1247 uint64_t len;
1248 file = fopen(filename,"rb");
1249 fseek(file, 0, SEEK_END);
1250 len = ftell(file);
1251 fseek(file, 0, SEEK_SET);
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -06001252 json_buf = (char*) loader_stack_alloc(len+1);
Jon Ashburn2077e382015-06-29 11:25:34 -06001253 if (json_buf == NULL) {
1254 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get JSON file");
1255 fclose(file);
1256 return NULL;
1257 }
1258 if (fread(json_buf, sizeof(char), len, file) != len) {
1259 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "fread failed can't get JSON file");
1260 fclose(file);
1261 return NULL;
1262 }
1263 fclose(file);
1264 json_buf[len] = '\0';
1265
1266 //parse text from file
1267 json = cJSON_Parse(json_buf);
1268 if (json == NULL)
1269 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Can't parse JSON file %s", filename);
1270 return json;
1271}
1272
1273/**
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001274 * Given a cJSON struct (json) of the top level JSON object from layer manifest
1275 * file, add entry to the layer_list.
1276 * Fill out the layer_properties in this list entry from the input cHJSON object.
1277 *
1278 * \returns
1279 * void
1280 * layer_list has a new entry and initialized accordingly.
1281 * If the json input object does not have all the required fields no entry
1282 * is added to the list.
1283 */
1284static void loader_add_layer_properties(struct loader_layer_list *layer_list,
1285 cJSON *json,
1286 bool is_implicit,
1287 char *filename)
1288{
1289 /* Fields in layer manifest file that are required:
1290 * (required) “file_format_version”
1291 * following are required in the "layer" object:
1292 * (required) "name"
1293 * (required) "type"
1294 * (required) “library_path”
1295 * (required) “abi_versions”
1296 * (required) “implementation_version”
1297 * (required) “description”
1298 * (required for implicit layers) “disable_environment”
1299 *
1300 * First get all required items and if any missing abort
1301 */
1302
1303 cJSON *item, *layer_node, *ext_item;
1304 char *temp;
1305 char *name, *type, *library_path, *abi_versions;
1306 char *implementation_version, *description;
1307 cJSON *disable_environment;
1308 int i;
1309 struct loader_extension_property ext_prop;
1310 item = cJSON_GetObjectItem(json, "file_format_version");
1311 if (item == NULL) {
1312 return;
1313 }
1314 char *file_vers = cJSON_PrintUnformatted(item);
1315 loader_log(VK_DBG_REPORT_INFO_BIT, 0, "Found manifest file %s, version %s",
1316 filename, file_vers);
1317 if (strcmp(file_vers, "\"0.9.0\"") != 0)
1318 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unexpected manifest file version (expected 1.0.0), may cause errors");
1319 free(file_vers);
1320
1321 //TODO handle multiple layer nodes in the file
1322 //TODO handle scanned libraries not one per layer property
1323 layer_node = cJSON_GetObjectItem(json, "layer");
1324 if (layer_node == NULL) {
1325 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"layer\" object in manifest JSON file, skipping");
1326 return;
1327 }
1328#define GET_JSON_OBJECT(node, var) { \
1329 var = cJSON_GetObjectItem(node, #var); \
1330 if (var == NULL) \
1331 return; \
1332 }
1333#define GET_JSON_ITEM(node, var) { \
1334 item = cJSON_GetObjectItem(node, #var); \
1335 if (item == NULL) \
1336 return; \
1337 temp = cJSON_Print(item); \
1338 temp[strlen(temp) - 1] = '\0'; \
1339 var = malloc(strlen(temp) + 1); \
1340 strcpy(var, &temp[1]); \
1341 free(temp); \
1342 }
1343 GET_JSON_ITEM(layer_node, name)
1344 GET_JSON_ITEM(layer_node, type)
1345 GET_JSON_ITEM(layer_node, library_path)
1346 GET_JSON_ITEM(layer_node, abi_versions)
1347 GET_JSON_ITEM(layer_node, implementation_version)
1348 GET_JSON_ITEM(layer_node, description)
1349 if (is_implicit) {
1350 GET_JSON_OBJECT(layer_node, disable_environment)
1351 }
1352#undef GET_JSON_ITEM
1353#undef GET_JSON_OBJECT
1354
1355 // add list entry
1356 assert((layer_list->count + 1) * sizeof(struct loader_layer_properties) <= layer_list->capacity);
1357 struct loader_layer_properties *props = &(layer_list->list[layer_list->count]);
Jon Ashburn15315172015-07-07 15:06:25 -06001358 strncpy(props->info.layerName, name, sizeof(props->info.layerName));
1359 props->info.layerName[sizeof(props->info.layerName) - 1] = '\0';
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001360 free(name);
Jon Ashburn15315172015-07-07 15:06:25 -06001361
Jon Ashburnbd332cc2015-07-07 10:27:45 -06001362 if (!strcmp(type, "DEVICE"))
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001363 props->type = (is_implicit) ? VK_LAYER_TYPE_DEVICE_IMPLICIT : VK_LAYER_TYPE_DEVICE_EXPLICIT;
Jon Ashburnbd332cc2015-07-07 10:27:45 -06001364 if (!strcmp(type, "INSTANCE"))
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001365 props->type = (is_implicit) ? VK_LAYER_TYPE_INSTANCE_IMPLICIT : VK_LAYER_TYPE_INSTANCE_EXPLICIT;
Jon Ashburnbd332cc2015-07-07 10:27:45 -06001366 if (!strcmp(type, "GLOBAL"))
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001367 props->type = (is_implicit) ? VK_LAYER_TYPE_GLOBAL_IMPLICIT : VK_LAYER_TYPE_GLOBAL_EXPLICIT;
1368 free(type);
Jon Ashburn15315172015-07-07 15:06:25 -06001369
1370 char *fullpath = malloc(2048);
1371 char *rel_base;
1372 if (strchr(library_path, DIRECTORY_SYMBOL) == NULL) {
1373 // a filename which is assumed in the system directory
Jon Ashburn5e1f63d2015-07-09 14:06:55 -06001374 char *def_path = loader_stack_alloc(strlen(DEFAULT_VK_LAYERS_PATH) + 1);
1375 strcpy(def_path, DEFAULT_VK_LAYERS_PATH);
1376 loader_get_fullpath(library_path, def_path, 2048, fullpath);
Jon Ashburn15315172015-07-07 15:06:25 -06001377 }
1378 else {
1379 // a relative or absolute path
1380 char *name_copy = loader_stack_alloc(strlen(filename) + 2);
1381 size_t len;
1382 strcpy(name_copy, filename);
1383 rel_base = loader_platform_dirname(name_copy);
1384 len = strlen(rel_base);
1385 rel_base[len] = DIRECTORY_SYMBOL;
1386 rel_base[len + 1] = '\0';
1387 loader_expand_path(library_path, rel_base, 2048, fullpath);
1388 }
1389 props->lib_info.lib_name = fullpath;
1390 free(library_path);
1391 //TODO merge the info with the versions and convert string to int
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001392 props->abi_version = abi_versions;
1393 props->impl_version = implementation_version;
Courtney Goeltzenleuchter53043732015-07-12 13:20:05 -06001394 strncpy((char *) props->info.description, description, sizeof(props->info.description));
Jon Ashburn15315172015-07-07 15:06:25 -06001395 props->info.description[sizeof(props->info.description) - 1] = '\0';
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001396 free(description);
1397 if (is_implicit) {
1398 props->disable_env_var.name = disable_environment->child->string;
1399 props->disable_env_var.value = disable_environment->child->valuestring;
1400 }
1401 layer_list->count++;
1402
1403 /**
1404 * Now get all optional items and objects and put in list:
1405 * functions
1406 * instance_extensions
1407 * device_extensions
1408 * enable_environment (implicit layers only)
1409 */
1410#define GET_JSON_OBJECT(node, var) { \
1411 var = cJSON_GetObjectItem(node, #var); \
1412 }
1413#define GET_JSON_ITEM(node, var) { \
1414 item = cJSON_GetObjectItem(node, #var); \
1415 if (item != NULL) \
1416 temp = cJSON_Print(item); \
1417 temp[strlen(temp) - 1] = '\0'; \
1418 var = malloc(strlen(temp) + 1); \
1419 strcpy(var, &temp[1]); \
1420 free(temp); \
1421 }
1422
1423 cJSON *instance_extensions, *device_extensions, *functions, *enable_environment;
1424 char *vkGetInstanceProcAddr, *vkGetDeviceProcAddr, *version;
1425 GET_JSON_OBJECT(layer_node, functions)
1426 if (functions != NULL) {
1427 GET_JSON_ITEM(functions, vkGetInstanceProcAddr)
1428 GET_JSON_ITEM(functions, vkGetDeviceProcAddr)
1429 props->functions.str_gipa = vkGetInstanceProcAddr;
1430 props->functions.str_gdpa = vkGetDeviceProcAddr;
1431 }
1432 GET_JSON_OBJECT(layer_node, instance_extensions)
1433 if (instance_extensions != NULL) {
1434 int count = cJSON_GetArraySize(instance_extensions);
1435 for (i = 0; i < count; i++) {
1436 ext_item = cJSON_GetArrayItem(instance_extensions, i);
1437 GET_JSON_ITEM(ext_item, name)
1438 GET_JSON_ITEM(ext_item, version)
1439 ext_prop.origin = VK_EXTENSION_ORIGIN_LAYER;
1440 ext_prop.lib_name = library_path;
1441 strcpy(ext_prop.info.extName, name);
1442 //TODO convert from string to int ext_prop.info.version = version;
1443 loader_add_to_ext_list(&props->instance_extension_list, 1, &ext_prop);
1444 }
1445 }
1446 GET_JSON_OBJECT(layer_node, device_extensions)
1447 if (device_extensions != NULL) {
1448 int count = cJSON_GetArraySize(device_extensions);
1449 for (i = 0; i < count; i++) {
1450 ext_item = cJSON_GetArrayItem(device_extensions, i);
1451 GET_JSON_ITEM(ext_item, name);
1452 GET_JSON_ITEM(ext_item, version);
1453 ext_prop.origin = VK_EXTENSION_ORIGIN_LAYER;
1454 ext_prop.lib_name = library_path;
1455 strcpy(ext_prop.info.extName, name);
1456 //TODO convert from string to int ext_prop.info.version = version;
1457 loader_add_to_ext_list(&props->device_extension_list, 1, &ext_prop);
1458 }
1459 }
1460 if (is_implicit) {
1461 GET_JSON_OBJECT(layer_node, enable_environment)
1462 props->enable_env_var.name = enable_environment->child->string;
1463 props->enable_env_var.value = enable_environment->child->valuestring;
1464 }
1465#undef GET_JSON_ITEM
1466#undef GET_JSON_OBJECT
1467
1468}
1469
1470/**
Jon Ashburn2077e382015-06-29 11:25:34 -06001471 * Find the Vulkan library manifest files.
1472 *
1473 * This function scans the location or env_override directories/files
1474 * for a list of JSON manifest files. If env_override is non-NULL
1475 * and has a valid value. Then the location is ignored. Otherwise
1476 * location is used to look for manifest files. The location
1477 * is interpreted as Registry path on Windows and a directory path(s)
1478 * on Linux.
1479 *
1480 * \returns
1481 * A string list of manifest files to be opened in out_files param.
1482 * List has a pointer to string for each manifest filename.
1483 * When done using the list in out_files, pointers should be freed.
Jon Ashburnffad94d2015-06-30 14:46:22 -07001484 * Location or override string lists can be either files or directories as follows:
1485 * | location | override
1486 * --------------------------------
1487 * Win ICD | files | files
1488 * Win Layer | files | dirs
1489 * Linux ICD | dirs | files
1490 * Linux Layer| dirs | dirs
Jon Ashburn2077e382015-06-29 11:25:34 -06001491 */
1492static void loader_get_manifest_files(const char *env_override,
Jon Ashburnffad94d2015-06-30 14:46:22 -07001493 bool is_layer,
1494 const char *location,
1495 struct loader_manifest_files *out_files)
Jon Ashburn2077e382015-06-29 11:25:34 -06001496{
1497 char *override = NULL;
1498 char *loc;
1499 char *file, *next_file, *name;
1500 size_t alloced_count = 64;
1501 char full_path[2048];
1502 DIR *sysdir = NULL;
Jon Ashburnffad94d2015-06-30 14:46:22 -07001503 bool list_is_dirs = false;
Jon Ashburn2077e382015-06-29 11:25:34 -06001504 struct dirent *dent;
1505
1506 out_files->count = 0;
1507 out_files->filename_list = NULL;
1508
Jon Ashburn2077e382015-06-29 11:25:34 -06001509 if (env_override != NULL && (override = getenv(env_override))) {
1510#if defined(__linux__)
1511 if (geteuid() != getuid()) {
Jon Ashburnffad94d2015-06-30 14:46:22 -07001512 /* Don't allow setuid apps to use the env var: */
Jon Ashburn2077e382015-06-29 11:25:34 -06001513 override = NULL;
1514 }
1515#endif
1516 }
1517
1518 if (location == NULL) {
1519 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
Jon Ashburnffad94d2015-06-30 14:46:22 -07001520 "Can't get manifest files with NULL location, env_override=%s",
1521 env_override);
Jon Ashburn2077e382015-06-29 11:25:34 -06001522 return;
1523 }
1524
Jon Ashburnffad94d2015-06-30 14:46:22 -07001525#if defined(__linux__)
1526 list_is_dirs = (override == NULL || is_layer) ? true : false;
1527#else //WIN32
1528 list_is_dirs = (is_layer && override != NULL) ? true : false;
1529#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06001530 // Make a copy of the input we are using so it is not modified
Jon Ashburnffad94d2015-06-30 14:46:22 -07001531 // Also handle getting the location(s) from registry on Windows
1532 if (override == NULL) {
1533#if defined (_WIN32)
1534 loc = loader_get_registry_files(location);
1535 if (loc == NULL) {
1536 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Registry lookup failed can't get manifest files");
1537 return;
1538 }
1539#else
Jon Ashburn2077e382015-06-29 11:25:34 -06001540 loc = alloca(strlen(location) + 1);
Jon Ashburnffad94d2015-06-30 14:46:22 -07001541 if (loc == NULL) {
1542 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1543 return;
1544 }
1545 strcpy(loc, location);
1546#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06001547 }
Jon Ashburnffad94d2015-06-30 14:46:22 -07001548 else {
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -06001549 loc = loader_stack_alloc(strlen(override) + 1);
Jon Ashburnffad94d2015-06-30 14:46:22 -07001550 if (loc == NULL) {
1551 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1552 return;
1553 }
1554 strcpy(loc, override);
1555 }
Jon Ashburn2077e382015-06-29 11:25:34 -06001556
1557 file = loc;
1558 while (*file) {
1559 next_file = loader_get_next_path(file);
Jon Ashburnffad94d2015-06-30 14:46:22 -07001560 if (list_is_dirs) {
Jon Ashburn2077e382015-06-29 11:25:34 -06001561 sysdir = opendir(file);
1562 name = NULL;
1563 if (sysdir) {
1564 dent = readdir(sysdir);
1565 if (dent == NULL)
1566 break;
1567 name = &(dent->d_name[0]);
1568 loader_get_fullpath(name, file, sizeof(full_path), full_path);
1569 name = full_path;
1570 }
1571 }
1572 else {
Jon Ashburnffad94d2015-06-30 14:46:22 -07001573#if defined(__linux__)
1574 // only Linux has relative paths
Jon Ashburn2077e382015-06-29 11:25:34 -06001575 char *dir;
1576 // make a copy of location so it isn't modified
1577 dir = alloca(strlen(location) + 1);
1578 if (dir == NULL) {
1579 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1580 return;
1581 }
1582 strcpy(dir, location);
1583
1584 loader_get_fullpath(file, dir, sizeof(full_path), full_path);
1585
1586 name = full_path;
Jon Ashburnffad94d2015-06-30 14:46:22 -07001587#else // WIN32
1588 name = file;
1589#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06001590 }
1591 while (name) {
1592 /* Look for files ending with ".json" suffix */
1593 uint32_t nlen = (uint32_t) strlen(name);
1594 const char *suf = name + nlen - 5;
1595 if ((nlen > 5) && !strncmp(suf, ".json", 5)) {
1596 if (out_files->count == 0) {
1597 out_files->filename_list = malloc(alloced_count * sizeof(char *));
1598 }
1599 else if (out_files->count == alloced_count) {
1600 out_files->filename_list = realloc(out_files->filename_list,
1601 alloced_count * sizeof(char *) * 2);
1602 alloced_count *= 2;
1603 }
1604 if (out_files->filename_list == NULL) {
1605 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't alloc manifest file list");
1606 return;
1607 }
1608 out_files->filename_list[out_files->count] = malloc(strlen(name) + 1);
1609 if (out_files->filename_list[out_files->count] == NULL) {
1610 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1611 return;
1612 }
1613 strcpy(out_files->filename_list[out_files->count], name);
1614 out_files->count++;
Jon Ashburnf70f3612015-07-02 10:08:47 -06001615 } else if (!list_is_dirs) {
1616 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 -06001617 }
Jon Ashburnffad94d2015-06-30 14:46:22 -07001618 if (list_is_dirs) {
Jon Ashburn2077e382015-06-29 11:25:34 -06001619 dent = readdir(sysdir);
1620 if (dent == NULL)
1621 break;
1622 name = &(dent->d_name[0]);
1623 loader_get_fullpath(name, file, sizeof(full_path), full_path);
1624 name = full_path;
1625 }
1626 else {
1627 break;
1628 }
1629 }
1630 if (sysdir)
1631 closedir(sysdir);
1632 file = next_file;
1633 }
1634 return;
1635}
1636
1637/**
1638 * Try to find the Vulkan ICD driver(s).
1639 *
1640 * This function scans the default system loader path(s) or path
1641 * specified by the \c VK_ICD_FILENAMES environment variable in
1642 * order to find loadable VK ICDs manifest files. From these
1643 * manifest files it finds the ICD libraries.
1644 *
1645 * \returns
Jon Ashburn3a37aee2015-06-30 16:44:28 -06001646 * void
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001647 */
Jon Ashburn27cd5842015-05-12 17:26:48 -06001648void loader_icd_scan(void)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001649{
Jon Ashburn2077e382015-06-29 11:25:34 -06001650 char *file_str;
1651 struct loader_manifest_files manifest_files;
1652
Jon Ashburn6301a0f2015-05-29 13:15:39 -06001653
1654 // convenient place to initialize a mutex
1655 loader_platform_thread_create_mutex(&loader_lock);
1656
Jon Ashburn2077e382015-06-29 11:25:34 -06001657 // convenient place to initialize logging
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001658 loader_debug_init();
1659
Jon Ashburn2077e382015-06-29 11:25:34 -06001660 // Get a list of manifest files for ICDs
1661 loader_get_manifest_files("VK_ICD_FILENAMES", false, DEFAULT_VK_DRIVERS_INFO,
1662 &manifest_files);
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001663 if (manifest_files.count == 0)
1664 return;
Jon Ashburn2077e382015-06-29 11:25:34 -06001665 for (uint32_t i = 0; i < manifest_files.count; i++) {
1666 file_str = manifest_files.filename_list[i];
1667 if (file_str == NULL)
1668 continue;
1669
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001670 cJSON *json;
Jon Ashburn2077e382015-06-29 11:25:34 -06001671 json = loader_get_json(file_str);
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001672 cJSON *item;
1673 item = cJSON_GetObjectItem(json, "file_format_version");
1674 if (item == NULL)
1675 return;
1676 char *file_vers = cJSON_Print(item);
1677 loader_log(VK_DBG_REPORT_INFO_BIT, 0, "Found manifest file %s, version %s",
1678 file_str, file_vers);
1679 if (strcmp(file_vers, "\"1.0.0\"") != 0)
1680 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unexpected manifest file version (expected 1.0.0), may cause errors");
1681 free(file_vers);
1682 item = cJSON_GetObjectItem(json, "ICD");
1683 if (item != NULL) {
1684 item = cJSON_GetObjectItem(item, "library_path");
1685 if (item != NULL) {
1686 char *icd_filename = cJSON_PrintUnformatted(item);
Jon Ashburn2077e382015-06-29 11:25:34 -06001687 char *icd_file = icd_filename;
1688 if (icd_filename != NULL) {
Jon Ashburn2077e382015-06-29 11:25:34 -06001689 char def_dir[] = DEFAULT_VK_DRIVERS_PATH;
1690 char *dir = def_dir;
1691 // strip off extra quotes
1692 if (icd_filename[strlen(icd_filename) - 1] == '"')
1693 icd_filename[strlen(icd_filename) - 1] = '\0';
1694 if (icd_filename[0] == '"')
1695 icd_filename++;
Jon Ashburnffad94d2015-06-30 14:46:22 -07001696#if defined(__linux__)
1697 char full_path[2048];
Jon Ashburn2077e382015-06-29 11:25:34 -06001698 loader_get_fullpath(icd_filename, dir, sizeof(full_path), full_path);
1699 loader_scanned_icd_add(full_path);
Jon Ashburnffad94d2015-06-30 14:46:22 -07001700#else // WIN32
1701 loader_scanned_icd_add(icd_filename);
1702#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06001703 free(icd_file);
1704 }
1705 }
1706 else
1707 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"library_path\" in ICD JSON file %s, skipping", file_str);
1708 }
1709 else
1710 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"ICD\" object in ICD JSON file %s, skipping", file_str);
1711
1712 free(file_str);
1713 cJSON_Delete(json);
1714 }
1715 free(manifest_files.filename_list);
1716
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001717}
1718
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001719
Jon Ashburn5ef20602015-07-02 09:40:15 -06001720void loader_layer_scan(void)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001721{
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001722 char *file_str;
1723 struct loader_manifest_files manifest_files;
1724 cJSON *json;
1725 uint32_t i;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001726
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001727 // Get a list of manifest files for layers
1728 loader_get_manifest_files(LAYERS_PATH_ENV, true, DEFAULT_VK_LAYERS_INFO,
1729 &manifest_files);
1730 if (manifest_files.count == 0)
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -07001731 return;
Jon Ashburn90c6a0e2015-06-04 15:30:58 -06001732
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001733#if 0
1734 /**
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06001735 * We need a list of the layer libraries, not just a list of
1736 * the layer properties (a layer library could expose more than
1737 * one layer property). This list of scanned layers would be
1738 * used to check for global and physicaldevice layer properties.
1739 */
1740 if (!loader_init_layer_library_list(&loader.scanned_layer_libraries)) {
1741 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1742 "Malloc for layer list failed: %s line: %d", __FILE__, __LINE__);
1743 return;
Jon Ashburn5ef20602015-07-02 09:40:15 -06001744 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001745#endif
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001746
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001747 // TODO use global_layer add and delete functions instead
1748 if (loader.scanned_layers.capacity == 0) {
1749 loader.scanned_layers.list = malloc(sizeof(struct loader_layer_properties) * 64);
1750 if (loader.scanned_layers.list == NULL) {
1751 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can'add any layer properties to list");
1752 return;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001753 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001754 memset(loader.scanned_layers.list, 0, sizeof(struct loader_layer_properties) * 64);
1755 loader.scanned_layers.capacity = sizeof(struct loader_layer_properties) * 64;
1756 }
1757 else {
1758 /* cleanup any previously scanned libraries */
1759 //TODO make sure everything is cleaned up properly
1760 for (i = 0; i < loader.scanned_layers.count; i++) {
1761 if (loader.scanned_layers.list[i].lib_info.lib_name != NULL)
1762 free(loader.scanned_layers.list[i].lib_info.lib_name);
1763 loader_destroy_ext_list(&loader.scanned_layers.list[i].instance_extension_list);
1764 loader_destroy_ext_list(&loader.scanned_layers.list[i].device_extension_list);
1765 loader.scanned_layers.list[i].lib_info.lib_name = NULL;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001766 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001767 loader.scanned_layers.count = 0;
1768 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001769
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001770 for (i = 0; i < manifest_files.count; i++) {
1771 file_str = manifest_files.filename_list[i];
1772 if (file_str == NULL)
1773 continue;
Courtney Goeltzenleuchtera9e4af42015-06-01 14:49:17 -06001774
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001775 // parse file into JSON struct
1776 json = loader_get_json(file_str);
1777 if (!json) {
1778 continue;
1779 }
1780 // ensure enough room to add an entry
1781 if ((loader.scanned_layers.count + 1) * sizeof (struct loader_layer_properties)
1782 > loader.scanned_layers.capacity) {
1783 loader.scanned_layers.list = realloc(loader.scanned_layers.list,
1784 loader.scanned_layers.capacity * 2);
1785 if (loader.scanned_layers.list == NULL) {
1786 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1787 "realloc failed for scanned layers");
1788 break;
1789 }
1790 loader.scanned_layers.capacity *= 2;
1791 }
1792 //TODO pass in implicit versus explicit bool
1793 loader_add_layer_properties(&loader.scanned_layers, json, false, file_str);
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06001794
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001795 free(file_str);
1796 cJSON_Delete(json);
1797 }
1798 free(manifest_files.filename_list);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001799
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001800}
1801
Courtney Goeltzenleuchter2d3ba632015-07-12 14:35:22 -06001802static PFN_vkVoidFunction VKAPI loader_gpa_instance_internal(VkInstance inst, const char * pName)
Jon Ashburn27cd5842015-05-12 17:26:48 -06001803{
1804 // inst is not wrapped
1805 if (inst == VK_NULL_HANDLE) {
1806 return NULL;
1807 }
1808 VkLayerInstanceDispatchTable* disp_table = * (VkLayerInstanceDispatchTable **) inst;
1809 void *addr;
1810
Jon Ashburn8fd08252015-05-28 16:25:02 -06001811 if (!strcmp(pName, "vkGetInstanceProcAddr"))
1812 return (void *) loader_gpa_instance_internal;
1813
Jon Ashburn27cd5842015-05-12 17:26:48 -06001814 if (disp_table == NULL)
1815 return NULL;
1816
1817 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001818 if (addr) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06001819 return addr;
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001820 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001821
1822 if (disp_table->GetInstanceProcAddr == NULL) {
1823 return NULL;
1824 }
1825 return disp_table->GetInstanceProcAddr(inst, pName);
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001826}
1827
Jon Ashburn128f9422015-05-28 19:16:58 -06001828struct loader_icd * loader_get_icd(const VkPhysicalDevice gpu, uint32_t *gpu_index)
Jon Ashburn876b1ac2014-10-17 15:09:07 -06001829{
Jon Ashburn128f9422015-05-28 19:16:58 -06001830
Tony Barbourb5d2c942015-07-14 13:34:05 -06001831 *gpu_index = 0;
Jon Ashburn98bd4542015-01-29 16:44:24 -07001832 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
1833 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
1834 for (uint32_t i = 0; i < icd->gpu_count; i++)
Jon Ashburn128f9422015-05-28 19:16:58 -06001835 if (icd->gpus[i] == gpu) {
Jon Ashburn98bd4542015-01-29 16:44:24 -07001836 *gpu_index = i;
1837 return icd;
1838 }
1839 }
Jon Ashburn876b1ac2014-10-17 15:09:07 -06001840 }
1841 return NULL;
1842}
1843
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001844static loader_platform_dl_handle loader_add_layer_lib(
Jon Ashburn4f67d742015-05-27 13:19:22 -06001845 const char *chain_type,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001846 struct loader_layer_properties *layer_prop)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001847{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001848 struct loader_lib_info *new_layer_lib_list, *my_lib;
1849
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06001850 /*
1851 * TODO: We can now track this information in the
1852 * scanned_layer_libraries list.
1853 */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001854 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001855 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, layer_prop->lib_info.lib_name) == 0) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001856 /* Have already loaded this library, just increment ref count */
1857 loader.loaded_layer_lib_list[i].ref_count++;
Courtney Goeltzenleuchterca8c81a2015-06-14 11:59:07 -06001858 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001859 "%s Chain: Increment layer reference count for layer library %s",
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001860 chain_type, layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001861 return loader.loaded_layer_lib_list[i].lib_handle;
1862 }
1863 }
1864
1865 /* Haven't seen this library so load it */
1866 new_layer_lib_list = realloc(loader.loaded_layer_lib_list,
1867 (loader.loaded_layer_lib_count + 1) * sizeof(struct loader_lib_info));
1868 if (!new_layer_lib_list) {
1869 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1870 return NULL;
1871 }
1872
1873 my_lib = &new_layer_lib_list[loader.loaded_layer_lib_count];
1874
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001875 /* NOTE: We require that the layer property be immutable */
1876 my_lib->lib_name = (char *) layer_prop->lib_info.lib_name;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001877 my_lib->ref_count = 0;
1878 my_lib->lib_handle = NULL;
1879
1880 if ((my_lib->lib_handle = loader_platform_open_library(my_lib->lib_name)) == NULL) {
1881 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1882 loader_platform_open_library_error(my_lib->lib_name));
1883 return NULL;
1884 } else {
Courtney Goeltzenleuchterca8c81a2015-06-14 11:59:07 -06001885 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001886 "Chain: %s: Loading layer library %s",
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001887 chain_type, layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001888 }
1889 loader.loaded_layer_lib_count++;
1890 loader.loaded_layer_lib_list = new_layer_lib_list;
1891 my_lib->ref_count++;
1892
1893 return my_lib->lib_handle;
1894}
1895
1896static void loader_remove_layer_lib(
1897 struct loader_instance *inst,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001898 struct loader_layer_properties *layer_prop)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001899{
1900 uint32_t idx;
Tony Barbourb5d2c942015-07-14 13:34:05 -06001901 struct loader_lib_info *new_layer_lib_list, *my_lib = NULL;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001902
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001903 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001904 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, layer_prop->lib_info.lib_name) == 0) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001905 /* found matching library */
1906 idx = i;
1907 my_lib = &loader.loaded_layer_lib_list[i];
1908 break;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001909 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001910 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001911
Tony Barbourb5d2c942015-07-14 13:34:05 -06001912 if (my_lib) {
1913 my_lib->ref_count--;
1914 if (my_lib->ref_count > 0) {
1915 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
1916 "Decrement reference count for layer library %s", layer_prop->lib_info.lib_name);
1917 return;
1918 }
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001919 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001920 loader_platform_close_library(my_lib->lib_handle);
Courtney Goeltzenleuchterca8c81a2015-06-14 11:59:07 -06001921 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001922 "Unloading layer library %s", layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001923
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001924 /* Need to remove unused library from list */
1925 new_layer_lib_list = malloc((loader.loaded_layer_lib_count - 1) * sizeof(struct loader_lib_info));
1926 if (!new_layer_lib_list) {
1927 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1928 return;
1929 }
1930
1931 if (idx > 0) {
1932 /* Copy records before idx */
1933 memcpy(new_layer_lib_list, &loader.loaded_layer_lib_list[0],
1934 sizeof(struct loader_lib_info) * idx);
1935 }
1936 if (idx < (loader.loaded_layer_lib_count - 1)) {
1937 /* Copy records after idx */
1938 memcpy(&new_layer_lib_list[idx], &loader.loaded_layer_lib_list[idx+1],
1939 sizeof(struct loader_lib_info) * (loader.loaded_layer_lib_count - idx - 1));
1940 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001941
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001942 free(loader.loaded_layer_lib_list);
1943 loader.loaded_layer_lib_count--;
1944 loader.loaded_layer_lib_list = new_layer_lib_list;
Jon Ashburnb8358052014-11-18 09:06:04 -07001945}
1946
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001947
1948/**
1949 * Go through the search_list and find any layers which match type. If layer
1950 * type match is found in then add it to ext_list.
1951 */
1952//TODO need to handle implict layer enable env var and disable env var
Jon Ashburn0c26e712015-07-02 16:10:32 -06001953static void loader_add_layer_implicit(
1954 const enum layer_type type,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001955 struct loader_layer_list *list,
1956 struct loader_layer_list *search_list)
Jon Ashburn0c26e712015-07-02 16:10:32 -06001957{
1958 uint32_t i;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001959 for (i = 0; i < search_list->count; i++) {
1960 const struct loader_layer_properties *prop = &search_list->list[i];
Jon Ashburn0c26e712015-07-02 16:10:32 -06001961 if (prop->type & type) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001962 /* Found an layer with the same type, add to layer_list */
1963 loader_add_to_layer_list(list, 1, prop);
Jon Ashburn0c26e712015-07-02 16:10:32 -06001964 }
1965 }
1966
1967}
1968
1969/**
1970 * Get the layer name(s) from the env_name environment variable. If layer
Jon Ashburnbd332cc2015-07-07 10:27:45 -06001971 * is found in search_list then add it to layer_list. But only add it to
1972 * layer_list if type matches.
Jon Ashburn0c26e712015-07-02 16:10:32 -06001973 */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001974static void loader_add_layer_env(
Jon Ashburnbd332cc2015-07-07 10:27:45 -06001975 const enum layer_type type,
Jon Ashburneb6d5682015-07-02 14:10:53 -06001976 const char *env_name,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001977 struct loader_layer_list *layer_list,
1978 const struct loader_layer_list *search_list)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001979{
Ian Elliott4470a302015-02-17 10:33:47 -07001980 char *layerEnv;
Jon Ashburneb6d5682015-07-02 14:10:53 -06001981 char *next, *name;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001982
Jon Ashburneb6d5682015-07-02 14:10:53 -06001983 layerEnv = getenv(env_name);
Ian Elliott4470a302015-02-17 10:33:47 -07001984 if (layerEnv == NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001985 return;
Ian Elliott4470a302015-02-17 10:33:47 -07001986 }
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -06001987 name = loader_stack_alloc(strlen(layerEnv) + 1);
Jon Ashburneb6d5682015-07-02 14:10:53 -06001988 if (name == NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001989 return;
Ian Elliott4470a302015-02-17 10:33:47 -07001990 }
Jon Ashburneb6d5682015-07-02 14:10:53 -06001991 strcpy(name, layerEnv);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001992
Jon Ashburneb6d5682015-07-02 14:10:53 -06001993 while (name && *name ) {
1994 next = loader_get_next_path(name);
Jon Ashburnbd332cc2015-07-07 10:27:45 -06001995 loader_find_layer_name_add_list(name, type, search_list, layer_list);
Jon Ashburneb6d5682015-07-02 14:10:53 -06001996 name = next;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001997 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001998
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001999 return;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002000}
2001
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -06002002void loader_deactivate_instance_layers(struct loader_instance *instance)
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002003{
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002004 if (!instance->activated_layer_list.count) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002005 return;
2006 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002007
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002008 /* Create instance chain of enabled layers */
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -06002009 for (uint32_t i = 0; i < instance->activated_layer_list.count; i++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002010 struct loader_layer_properties *layer_prop = &instance->activated_layer_list.list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002011
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002012 loader_remove_layer_lib(instance, layer_prop);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002013 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002014 loader_destroy_layer_list(&instance->activated_layer_list);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002015}
2016
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002017VkResult loader_enable_instance_layers(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002018 struct loader_instance *inst,
2019 const VkInstanceCreateInfo *pCreateInfo)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002020{
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002021 VkResult err;
2022
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002023 if (inst == NULL)
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002024 return VK_ERROR_UNKNOWN;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002025
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002026 if (!loader_init_layer_list(&inst->activated_layer_list)) {
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002027 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance activated layer list");
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002028 return VK_ERROR_OUT_OF_HOST_MEMORY;
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002029 }
2030
Jon Ashburn0c26e712015-07-02 16:10:32 -06002031 /* Add any implicit layers first */
2032 loader_add_layer_implicit(
2033 VK_LAYER_TYPE_INSTANCE_IMPLICIT,
2034 &inst->activated_layer_list,
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002035 &loader.scanned_layers);
Jon Ashburn0c26e712015-07-02 16:10:32 -06002036
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002037 /* Add any layers specified via environment variable next */
Jon Ashburneb6d5682015-07-02 14:10:53 -06002038 loader_add_layer_env(
Jon Ashburnbd332cc2015-07-07 10:27:45 -06002039 VK_LAYER_TYPE_INSTANCE_EXPLICIT,
Jon Ashburneb6d5682015-07-02 14:10:53 -06002040 "VK_INSTANCE_LAYERS",
2041 &inst->activated_layer_list,
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002042 &loader.scanned_layers);
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002043
2044 /* Add layers specified by the application */
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002045 err = loader_add_layer_names_to_list(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002046 &inst->activated_layer_list,
2047 pCreateInfo->layerCount,
2048 pCreateInfo->ppEnabledLayerNames,
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002049 &loader.scanned_layers);
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002050
2051 return err;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002052}
2053
Jon Ashburn27cd5842015-05-12 17:26:48 -06002054uint32_t loader_activate_instance_layers(struct loader_instance *inst)
2055{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002056 uint32_t layer_idx;
Jon Ashburn128f9422015-05-28 19:16:58 -06002057 VkBaseLayerObject *wrappedInstance;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002058
David Pinedoa0a8a242015-06-24 15:29:18 -06002059 if (inst == NULL) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06002060 return 0;
David Pinedoa0a8a242015-06-24 15:29:18 -06002061 }
Jon Ashburn27cd5842015-05-12 17:26:48 -06002062
2063 // NOTE inst is unwrapped at this point in time
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06002064 void* baseObj = (void*) inst;
2065 void* nextObj = (void*) inst;
Jon Ashburn27cd5842015-05-12 17:26:48 -06002066 VkBaseLayerObject *nextInstObj;
2067 PFN_vkGetInstanceProcAddr nextGPA = loader_gpa_instance_internal;
2068
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002069 if (!inst->activated_layer_list.count) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06002070 return 0;
2071 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002072
Courtney Goeltzenleuchter6f460c52015-07-06 09:04:55 -06002073 wrappedInstance = loader_stack_alloc(sizeof(VkBaseLayerObject)
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002074 * inst->activated_layer_list.count);
Jon Ashburn128f9422015-05-28 19:16:58 -06002075 if (!wrappedInstance) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002076 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance objects for layer");
2077 return 0;
2078 }
2079
2080 /* Create instance chain of enabled layers */
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002081 layer_idx = inst->activated_layer_list.count - 1;
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06002082 for (int32_t i = inst->activated_layer_list.count - 1; i >= 0; i--) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002083 struct loader_layer_properties *layer_prop = &inst->activated_layer_list.list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002084 loader_platform_dl_handle lib_handle;
2085
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002086 /*
Courtney Goeltzenleuchteree3b16a2015-06-01 14:12:42 -06002087 * Note: An extension's Get*ProcAddr should not return a function pointer for
2088 * any extension entry points until the extension has been enabled.
2089 * To do this requires a different behavior from Get*ProcAddr functions implemented
2090 * in layers.
2091 * The very first call to a layer will be it's Get*ProcAddr function requesting
2092 * the layer's vkGet*ProcAddr. The layer should intialize it's internal dispatch table
2093 * with the wrapped object given (either Instance or Device) and return the layer's
2094 * Get*ProcAddr function. The layer should also use this opportunity to record the
2095 * baseObject so that it can find the correct local dispatch table on future calls.
2096 * Subsequent calls to Get*ProcAddr, CreateInstance, CreateDevice
2097 * will not use a wrapped object and must look up their local dispatch table from
2098 * the given baseObject.
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002099 */
Jon Ashburn128f9422015-05-28 19:16:58 -06002100 nextInstObj = (wrappedInstance + layer_idx);
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06002101 nextInstObj->pGPA = (PFN_vkGPA) nextGPA;
Jon Ashburn27cd5842015-05-12 17:26:48 -06002102 nextInstObj->baseObject = baseObj;
2103 nextInstObj->nextObject = nextObj;
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06002104 nextObj = (void*) nextInstObj;
Jon Ashburn27cd5842015-05-12 17:26:48 -06002105
2106 char funcStr[256];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002107 snprintf(funcStr, 256, "%sGetInstanceProcAddr", layer_prop->info.layerName);
2108 lib_handle = loader_add_layer_lib("instance", layer_prop);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002109 if ((nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
2110 nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
Jon Ashburn27cd5842015-05-12 17:26:48 -06002111 if (!nextGPA) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002112 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 -06002113
2114 /* TODO: Should we return nextObj, nextGPA to previous? */
Jon Ashburn27cd5842015-05-12 17:26:48 -06002115 continue;
2116 }
2117
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002118 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002119 "Insert instance layer %s (%s)",
2120 layer_prop->info.layerName,
2121 layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002122
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002123 layer_idx--;
Jon Ashburn27cd5842015-05-12 17:26:48 -06002124 }
2125
Jon Ashburn8fd08252015-05-28 16:25:02 -06002126 loader_init_instance_core_dispatch_table(inst->disp, nextGPA, (VkInstance) nextObj, (VkInstance) baseObj);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002127
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002128 return inst->activated_layer_list.count;
Jon Ashburn27cd5842015-05-12 17:26:48 -06002129}
2130
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002131void loader_activate_instance_layer_extensions(struct loader_instance *inst)
2132{
2133
2134 loader_init_instance_extension_dispatch_table(inst->disp,
2135 inst->disp->GetInstanceProcAddr,
Jon Ashburn128f9422015-05-28 19:16:58 -06002136 (VkInstance) inst);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002137}
2138
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002139static VkResult loader_enable_device_layers(
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06002140 struct loader_icd *icd,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002141 struct loader_device *dev,
2142 const VkDeviceCreateInfo *pCreateInfo)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002143{
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002144 VkResult err;
2145
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002146 if (dev == NULL)
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002147 return VK_ERROR_UNKNOWN;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002148
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002149 if (dev->activated_layer_list.list == NULL || dev->activated_layer_list.capacity == 0) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002150 loader_init_layer_list(&dev->activated_layer_list);
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002151 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002152
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002153 if (dev->activated_layer_list.list == NULL) {
2154 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc device activated layer list");
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002155 return VK_ERROR_OUT_OF_HOST_MEMORY;
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002156 }
2157
Jon Ashburn0c26e712015-07-02 16:10:32 -06002158 /* Add any implicit layers first */
2159 loader_add_layer_implicit(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002160 VK_LAYER_TYPE_DEVICE_IMPLICIT,
2161 &dev->activated_layer_list,
Jon Ashburnbd332cc2015-07-07 10:27:45 -06002162 &loader.scanned_layers);
Jon Ashburn0c26e712015-07-02 16:10:32 -06002163
2164 /* Add any layers specified via environment variable next */
Jon Ashburneb6d5682015-07-02 14:10:53 -06002165 loader_add_layer_env(
Jon Ashburnbd332cc2015-07-07 10:27:45 -06002166 VK_LAYER_TYPE_DEVICE_EXPLICIT,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002167 "VK_DEVICE_LAYERS",
2168 &dev->activated_layer_list,
Jon Ashburnbd332cc2015-07-07 10:27:45 -06002169 &loader.scanned_layers);
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002170
2171 /* Add layers specified by the application */
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002172 err = loader_add_layer_names_to_list(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002173 &dev->activated_layer_list,
2174 pCreateInfo->layerCount,
2175 pCreateInfo->ppEnabledLayerNames,
Jon Ashburnbd332cc2015-07-07 10:27:45 -06002176 &loader.scanned_layers);
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002177
2178 return err;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002179}
2180
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002181/*
2182 * This function terminates the device chain fro CreateDevice.
2183 * CreateDevice is a special case and so the loader call's
2184 * the ICD's CreateDevice before creating the chain. Since
2185 * we can't call CreateDevice twice we must terminate the
2186 * device chain with something else.
2187 */
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002188static VkResult scratch_vkCreateDevice(
2189 VkPhysicalDevice gpu,
2190 const VkDeviceCreateInfo *pCreateInfo,
2191 VkDevice *pDevice)
2192{
2193 return VK_SUCCESS;
2194}
2195
Courtney Goeltzenleuchter2d3ba632015-07-12 14:35:22 -06002196static PFN_vkVoidFunction VKAPI loader_GetDeviceChainProcAddr(VkDevice device, const char * name)
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002197{
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002198 if (!strcmp(name, "vkGetDeviceProcAddr"))
Courtney Goeltzenleuchter2d3ba632015-07-12 14:35:22 -06002199 return (PFN_vkVoidFunction) loader_GetDeviceChainProcAddr;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002200 if (!strcmp(name, "vkCreateDevice"))
Courtney Goeltzenleuchter2d3ba632015-07-12 14:35:22 -06002201 return (PFN_vkVoidFunction) scratch_vkCreateDevice;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002202
Courtney Goeltzenleuchter3e029d12015-06-29 16:09:23 -06002203 struct loader_device *found_dev;
2204 struct loader_icd *icd = loader_get_icd_and_device(device, &found_dev);
2205 return icd->GetDeviceProcAddr(device, name);
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002206}
2207
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002208static uint32_t loader_activate_device_layers(
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06002209 struct loader_icd *icd,
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002210 struct loader_device *dev,
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06002211 VkDevice device)
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002212{
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002213 if (!icd)
2214 return 0;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002215
David Pinedoa0a8a242015-06-24 15:29:18 -06002216 if (!dev) {
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002217 return 0;
David Pinedoa0a8a242015-06-24 15:29:18 -06002218 }
Jon Ashburn94e70492015-06-10 10:13:10 -06002219
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002220 /* activate any layer libraries */
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06002221 void* nextObj = (void*) device;
2222 void* baseObj = nextObj;
Jon Ashburn94e70492015-06-10 10:13:10 -06002223 VkBaseLayerObject *nextGpuObj;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002224 PFN_vkGetDeviceProcAddr nextGPA = loader_GetDeviceChainProcAddr;
Jon Ashburn94e70492015-06-10 10:13:10 -06002225 VkBaseLayerObject *wrappedGpus;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002226
Jon Ashburn94e70492015-06-10 10:13:10 -06002227 if (!dev->activated_layer_list.count)
2228 return 0;
2229
2230 wrappedGpus = malloc(sizeof (VkBaseLayerObject) * dev->activated_layer_list.count);
2231 if (!wrappedGpus) {
2232 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Gpu objects for layer");
2233 return 0;
2234 }
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002235
Jon Ashburn94e70492015-06-10 10:13:10 -06002236 for (int32_t i = dev->activated_layer_list.count - 1; i >= 0; i--) {
2237
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002238 struct loader_layer_properties *layer_prop = &dev->activated_layer_list.list[i];
Jon Ashburn94e70492015-06-10 10:13:10 -06002239 loader_platform_dl_handle lib_handle;
2240
Jon Ashburn94e70492015-06-10 10:13:10 -06002241 nextGpuObj = (wrappedGpus + i);
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06002242 nextGpuObj->pGPA = (PFN_vkGPA)nextGPA;
Jon Ashburn94e70492015-06-10 10:13:10 -06002243 nextGpuObj->baseObject = baseObj;
2244 nextGpuObj->nextObject = nextObj;
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06002245 nextObj = (void*) nextGpuObj;
Jon Ashburn94e70492015-06-10 10:13:10 -06002246
2247 char funcStr[256];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002248 snprintf(funcStr, 256, "%sGetDeviceProcAddr", layer_prop->info.layerName);
2249 lib_handle = loader_add_layer_lib("device", layer_prop);
Jon Ashburn94e70492015-06-10 10:13:10 -06002250 if ((nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
2251 nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr");
2252 if (!nextGPA) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002253 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 -06002254 continue;
2255 }
2256
2257 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002258 "Insert device layer library %s (%s)",
2259 layer_prop->info.layerName,
2260 layer_prop->lib_info.lib_name);
Jon Ashburn94e70492015-06-10 10:13:10 -06002261
2262 }
2263
2264 loader_init_device_dispatch_table(&dev->loader_dispatch, nextGPA,
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06002265 (VkDevice) nextObj, (VkDevice) baseObj);
Jon Ashburn94e70492015-06-10 10:13:10 -06002266 free(wrappedGpus);
2267
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002268 return dev->activated_layer_list.count;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002269}
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002270
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002271VkResult loader_validate_layers(
2272 const uint32_t layer_count,
2273 const char * const *ppEnabledLayerNames,
2274 struct loader_layer_list *list)
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06002275{
2276 struct loader_layer_properties *prop;
2277
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002278 for (uint32_t i = 0; i < layer_count; i++) {
2279 prop = get_layer_property(ppEnabledLayerNames[i],
2280 list);
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06002281 if (!prop) {
2282 return VK_ERROR_INVALID_LAYER;
2283 }
2284 }
2285
2286 return VK_SUCCESS;
2287}
2288
2289VkResult loader_validate_instance_extensions(
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002290 const VkInstanceCreateInfo *pCreateInfo)
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06002291{
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002292 struct loader_extension_property *extension_prop;
2293 struct loader_layer_properties *layer_prop;
2294
2295 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2296 extension_prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
2297 &loader.global_extensions);
2298
2299 if (extension_prop) {
2300 continue;
2301 }
2302
2303 extension_prop = NULL;
2304
2305 /* Not in global list, search layer extension lists */
2306 for (uint32_t j = 0; j < pCreateInfo->layerCount; j++) {
2307 layer_prop = get_layer_property(pCreateInfo->ppEnabledLayerNames[i],
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002308 &loader.scanned_layers);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002309
2310 if (!layer_prop) {
Courtney Goeltzenleuchter6f5b00c2015-07-06 20:46:50 -06002311 /* Should NOT get here, loader_validate_layers
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002312 * should have already filtered this case out.
2313 */
2314 continue;
2315 }
2316
2317 extension_prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
2318 &layer_prop->instance_extension_list);
2319 if (extension_prop) {
2320 /* Found the extension in one of the layers enabled by the app. */
2321 break;
2322 }
2323 }
2324
2325 if (!extension_prop) {
2326 /* Didn't find extension name in any of the global layers, error out */
2327 return VK_ERROR_INVALID_EXTENSION;
2328 }
2329 }
2330 return VK_SUCCESS;
2331}
2332
2333VkResult loader_validate_device_extensions(
2334 struct loader_icd *icd,
Cody Northrope62183e2015-07-09 18:08:05 -06002335 uint32_t gpu_index,
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002336 const VkDeviceCreateInfo *pCreateInfo)
2337{
2338 struct loader_extension_property *extension_prop;
2339 struct loader_layer_properties *layer_prop;
2340
2341 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2342 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
2343 extension_prop = get_extension_property(extension_name,
Courtney Goeltzenleuchterfedb2a52015-07-08 21:13:16 -06002344 &icd->device_extension_cache[gpu_index]);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002345
2346 if (extension_prop) {
2347 continue;
2348 }
2349
2350 /* Not in global list, search layer extension lists */
2351 for (uint32_t j = 0; j < pCreateInfo->layerCount; j++) {
2352 const char *layer_name = pCreateInfo->ppEnabledLayerNames[j];
2353 layer_prop = get_layer_property(layer_name,
2354 &icd->layer_properties_cache);
2355
2356 if (!layer_prop) {
2357 /* Should NOT get here, loader_validate_instance_layers
2358 * should have already filtered this case out.
2359 */
2360 continue;
2361 }
2362
2363 extension_prop = get_extension_property(extension_name,
2364 &layer_prop->device_extension_list);
2365 if (extension_prop) {
2366 /* Found the extension in one of the layers enabled by the app. */
2367 break;
2368 }
2369 }
2370
2371 if (!extension_prop) {
2372 /* Didn't find extension name in any of the device layers, error out */
2373 return VK_ERROR_INVALID_EXTENSION;
2374 }
2375 }
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06002376 return VK_SUCCESS;
2377}
2378
Jon Ashburn27cd5842015-05-12 17:26:48 -06002379VkResult loader_CreateInstance(
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002380 const VkInstanceCreateInfo* pCreateInfo,
2381 VkInstance* pInstance)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002382{
Jon Ashburneed0c002015-05-21 17:42:17 -06002383 struct loader_instance *ptr_instance = *(struct loader_instance **) pInstance;
Jon Ashburn46888392015-01-29 15:45:51 -07002384 struct loader_scanned_icds *scanned_icds;
2385 struct loader_icd *icd;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06002386 struct loader_extension_property *prop;
2387 char **filtered_extension_names = NULL;
2388 VkInstanceCreateInfo icd_create_info;
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002389 VkResult res = VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002390
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06002391 icd_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
2392 icd_create_info.layerCount = 0;
2393 icd_create_info.ppEnabledLayerNames = NULL;
2394 icd_create_info.pAllocCb = pCreateInfo->pAllocCb;
2395 icd_create_info.pAppInfo = pCreateInfo->pAppInfo;
2396 icd_create_info.pNext = pCreateInfo->pNext;
2397
2398 /*
2399 * NOTE: Need to filter the extensions to only those
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002400 * supported by the ICD.
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06002401 * No ICD will advertise support for layers. An ICD
2402 * library could support a layer, but it would be
2403 * independent of the actual ICD, just in the same library.
2404 */
2405 filtered_extension_names = loader_stack_alloc(pCreateInfo->extensionCount * sizeof(char *));
2406 if (!filtered_extension_names) {
2407 return VK_ERROR_OUT_OF_HOST_MEMORY;
2408 }
2409 icd_create_info.ppEnabledExtensionNames = (const char * const *) filtered_extension_names;
2410
Jon Ashburn46888392015-01-29 15:45:51 -07002411 scanned_icds = loader.scanned_icd_list;
2412 while (scanned_icds) {
2413 icd = loader_icd_add(ptr_instance, scanned_icds);
2414 if (icd) {
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06002415
2416 icd_create_info.extensionCount = 0;
2417 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2418 prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
2419 &scanned_icds->global_extension_list);
2420 if (prop) {
2421 filtered_extension_names[icd_create_info.extensionCount] = (char *) pCreateInfo->ppEnabledExtensionNames[i];
2422 icd_create_info.extensionCount++;
2423 }
2424 }
2425
2426 res = scanned_icds->CreateInstance(&icd_create_info,
Jon Ashburn3da71f22015-05-14 12:43:38 -06002427 &(icd->instance));
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06002428 if (res != VK_SUCCESS)
Jon Ashburn46888392015-01-29 15:45:51 -07002429 {
2430 ptr_instance->icds = ptr_instance->icds->next;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002431 loader_icd_destroy(ptr_instance, icd);
Jon Ashburn3da71f22015-05-14 12:43:38 -06002432 icd->instance = VK_NULL_HANDLE;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002433 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Jon Ashburn46888392015-01-29 15:45:51 -07002434 "ICD ignored: failed to CreateInstance on device");
Jon Ashburn3da71f22015-05-14 12:43:38 -06002435 } else
2436 {
2437 loader_icd_init_entrys(icd, scanned_icds);
Jon Ashburn46888392015-01-29 15:45:51 -07002438 }
2439 }
2440 scanned_icds = scanned_icds->next;
2441 }
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002442
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002443 /*
2444 * If no ICDs were added to instance list and res is unchanged
2445 * from it's initial value, the loader was unable to find
2446 * a suitable ICD.
2447 */
Ian Elliotteb450762015-02-05 15:19:15 -07002448 if (ptr_instance->icds == NULL) {
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002449 if (res == VK_SUCCESS) {
2450 return VK_ERROR_INCOMPATIBLE_DRIVER;
2451 } else {
2452 return res;
2453 }
Ian Elliotteb450762015-02-05 15:19:15 -07002454 }
Jon Ashburn46888392015-01-29 15:45:51 -07002455
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002456 return VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002457}
2458
Jon Ashburn27cd5842015-05-12 17:26:48 -06002459VkResult loader_DestroyInstance(
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06002460 VkInstance instance)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002461{
Courtney Goeltzenleuchterdeceded2015-06-08 15:04:02 -06002462 struct loader_instance *ptr_instance = loader_instance(instance);
Jon Ashburn3da71f22015-05-14 12:43:38 -06002463 struct loader_icd *icds = ptr_instance->icds;
Jon Ashburna6fd2612015-06-16 14:43:19 -06002464 struct loader_icd *next_icd;
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06002465 VkResult res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002466
2467 // Remove this instance from the list of instances:
2468 struct loader_instance *prev = NULL;
2469 struct loader_instance *next = loader.instances;
2470 while (next != NULL) {
2471 if (next == ptr_instance) {
2472 // Remove this instance from the list:
2473 if (prev)
2474 prev->next = next->next;
Jon Ashburnc5c49602015-02-03 09:26:59 -07002475 else
2476 loader.instances = next->next;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002477 break;
2478 }
2479 prev = next;
2480 next = next->next;
2481 }
2482 if (next == NULL) {
2483 // This must be an invalid instance handle or empty list
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06002484 return VK_ERROR_INVALID_HANDLE;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002485 }
2486
Jon Ashburn3da71f22015-05-14 12:43:38 -06002487 while (icds) {
2488 if (icds->instance) {
2489 res = icds->DestroyInstance(icds->instance);
Tony Barbourf20f87b2015-04-22 09:02:32 -06002490 if (res != VK_SUCCESS)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002491 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Tony Barbourf20f87b2015-04-22 09:02:32 -06002492 "ICD ignored: failed to DestroyInstance on device");
2493 }
Jon Ashburna6fd2612015-06-16 14:43:19 -06002494 next_icd = icds->next;
Jon Ashburn3da71f22015-05-14 12:43:38 -06002495 icds->instance = VK_NULL_HANDLE;
Jon Ashburna6fd2612015-06-16 14:43:19 -06002496 loader_icd_destroy(ptr_instance, icds);
2497
2498 icds = next_icd;
Jon Ashburn46888392015-01-29 15:45:51 -07002499 }
2500
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002501
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06002502 return VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002503}
2504
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002505VkResult loader_init_physical_device_info(
2506 struct loader_instance *ptr_instance)
2507{
2508 struct loader_icd *icd;
2509 uint32_t n, count = 0;
2510 VkResult res = VK_ERROR_UNKNOWN;
2511
2512 icd = ptr_instance->icds;
2513 while (icd) {
2514 res = icd->EnumeratePhysicalDevices(icd->instance, &n, NULL);
2515 if (res != VK_SUCCESS)
2516 return res;
2517 icd->gpu_count = n;
2518 count += n;
2519 icd = icd->next;
2520 }
2521
2522 ptr_instance->total_gpu_count = count;
2523
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002524 icd = ptr_instance->icds;
2525 while (icd) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002526
2527 n = icd->gpu_count;
Jon Ashburn128f9422015-05-28 19:16:58 -06002528 icd->gpus = (VkPhysicalDevice *) malloc(n * sizeof(VkPhysicalDevice));
2529 if (!icd->gpus) {
2530 /* TODO: Add cleanup code here */
2531 return VK_ERROR_OUT_OF_HOST_MEMORY;
2532 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002533 res = icd->EnumeratePhysicalDevices(
2534 icd->instance,
2535 &n,
Jon Ashburn128f9422015-05-28 19:16:58 -06002536 icd->gpus);
2537 if ((res == VK_SUCCESS) && (n == icd->gpu_count)) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002538
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002539 for (unsigned int i = 0; i < n; i++) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002540
Jon Ashburn128f9422015-05-28 19:16:58 -06002541 loader_init_dispatch(icd->gpus[i], ptr_instance->disp);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002542
2543 if (!loader_init_ext_list(&icd->device_extension_cache[i])) {
2544 /* TODO: Add cleanup code here */
2545 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2546 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002547 if (res == VK_SUCCESS) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002548
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002549 loader_add_physical_device_extensions(
2550 icd->GetPhysicalDeviceExtensionProperties,
2551 icd->gpus[0],
2552 VK_EXTENSION_ORIGIN_ICD,
2553 icd->scanned_icds->lib_name,
2554 &icd->device_extension_cache[i]);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002555
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002556 for (uint32_t l = 0; l < loader.scanned_layers.count; l++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002557 loader_platform_dl_handle lib_handle;
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002558 char *lib_name = loader.scanned_layers.list[l].lib_info.lib_name;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002559
2560 lib_handle = loader_platform_open_library(lib_name);
2561 if (lib_handle == NULL) {
2562 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "open library failed: %s", lib_name);
2563 continue;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002564 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002565 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
2566 "library: %s", lib_name);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002567
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002568 loader_add_physical_device_layer_properties(
2569 icd, lib_name, lib_handle);
2570
2571 loader_platform_close_library(lib_handle);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002572 }
2573 }
2574
2575 if (res != VK_SUCCESS) {
2576 /* clean up any extension lists previously created before this request failed */
2577 for (uint32_t j = 0; j < i; j++) {
2578 loader_destroy_ext_list(&icd->device_extension_cache[i]);
2579 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002580
2581 loader_destroy_layer_list(&icd->layer_properties_cache);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002582 return res;
2583 }
2584 }
2585
2586 count += n;
2587 }
2588
2589 icd = icd->next;
2590 }
2591
2592 return VK_SUCCESS;
2593}
2594
Jon Ashburn27cd5842015-05-12 17:26:48 -06002595VkResult loader_EnumeratePhysicalDevices(
Courtney Goeltzenleuchter5e41f1d2015-04-20 12:48:54 -06002596 VkInstance instance,
2597 uint32_t* pPhysicalDeviceCount,
2598 VkPhysicalDevice* pPhysicalDevices)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002599{
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002600 uint32_t index = 0;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07002601 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002602 struct loader_icd *icd = ptr_instance->icds;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07002603
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002604 if (ptr_instance->total_gpu_count == 0) {
2605 loader_init_physical_device_info(ptr_instance);
Jon Ashburn4c392fb2015-01-28 19:57:09 -07002606 }
2607
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002608 *pPhysicalDeviceCount = ptr_instance->total_gpu_count;
2609 if (!pPhysicalDevices) {
2610 return VK_SUCCESS;
2611 }
Jon Ashburn4c392fb2015-01-28 19:57:09 -07002612
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002613 while (icd) {
2614 assert((index + icd->gpu_count) <= *pPhysicalDeviceCount);
Jon Ashburn128f9422015-05-28 19:16:58 -06002615 memcpy(&pPhysicalDevices[index], icd->gpus, icd->gpu_count * sizeof(VkPhysicalDevice));
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002616 index += icd->gpu_count;
2617 icd = icd->next;
2618 }
2619
2620 return VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002621}
2622
Tony Barbour59a47322015-06-24 16:06:58 -06002623VkResult loader_GetPhysicalDeviceProperties(
Jon Ashburn3da71f22015-05-14 12:43:38 -06002624 VkPhysicalDevice gpu,
Tony Barbour59a47322015-06-24 16:06:58 -06002625 VkPhysicalDeviceProperties* pProperties)
Jon Ashburn3da71f22015-05-14 12:43:38 -06002626{
2627 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06002628 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburn3da71f22015-05-14 12:43:38 -06002629 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2630
Tony Barbour59a47322015-06-24 16:06:58 -06002631 if (icd->GetPhysicalDeviceProperties)
2632 res = icd->GetPhysicalDeviceProperties(gpu, pProperties);
2633
2634 return res;
2635}
2636
Tony Barbour59a47322015-06-24 16:06:58 -06002637VkResult loader_GetPhysicalDeviceQueueCount(
2638 VkPhysicalDevice gpu,
2639 uint32_t* pCount)
2640{
2641 uint32_t gpu_index;
2642 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2643 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2644
2645 if (icd->GetPhysicalDeviceQueueCount)
2646 res = icd->GetPhysicalDeviceQueueCount(gpu, pCount);
2647
2648 return res;
2649}
2650
2651VkResult loader_GetPhysicalDeviceQueueProperties (
2652 VkPhysicalDevice gpu,
2653 uint32_t count,
2654 VkPhysicalDeviceQueueProperties * pProperties)
2655{
2656 uint32_t gpu_index;
2657 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2658 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2659
2660 if (icd->GetPhysicalDeviceQueueProperties)
2661 res = icd->GetPhysicalDeviceQueueProperties(gpu, count, pProperties);
2662
2663 return res;
2664}
2665
2666VkResult loader_GetPhysicalDeviceMemoryProperties (
2667 VkPhysicalDevice gpu,
2668 VkPhysicalDeviceMemoryProperties* pProperties)
2669{
2670 uint32_t gpu_index;
2671 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2672 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2673
2674 if (icd->GetPhysicalDeviceMemoryProperties)
2675 res = icd->GetPhysicalDeviceMemoryProperties(gpu, pProperties);
Jon Ashburn3da71f22015-05-14 12:43:38 -06002676
2677 return res;
2678}
2679
Chris Forbesbc0bb772015-06-21 22:55:02 +12002680VkResult loader_GetPhysicalDeviceFeatures(
2681 VkPhysicalDevice physicalDevice,
2682 VkPhysicalDeviceFeatures* pFeatures)
2683{
2684 uint32_t gpu_index;
2685 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2686 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2687
2688 if (icd->GetPhysicalDeviceFeatures)
2689 res = icd->GetPhysicalDeviceFeatures(physicalDevice, pFeatures);
2690
2691 return res;
2692}
2693
Courtney Goeltzenleuchter2caec862015-07-12 12:52:09 -06002694VkResult loader_GetPhysicalDeviceFormatProperties(
Chris Forbesbc0bb772015-06-21 22:55:02 +12002695 VkPhysicalDevice physicalDevice,
2696 VkFormat format,
2697 VkFormatProperties* pFormatInfo)
2698{
2699 uint32_t gpu_index;
2700 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2701 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2702
Courtney Goeltzenleuchter2caec862015-07-12 12:52:09 -06002703 if (icd->GetPhysicalDeviceFormatProperties)
2704 res = icd->GetPhysicalDeviceFormatProperties(physicalDevice, format, pFormatInfo);
Chris Forbesbc0bb772015-06-21 22:55:02 +12002705
2706 return res;
2707}
2708
2709VkResult loader_GetPhysicalDeviceLimits(
2710 VkPhysicalDevice physicalDevice,
2711 VkPhysicalDeviceLimits* pLimits)
2712{
2713 uint32_t gpu_index;
2714 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2715 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2716
2717 if (icd->GetPhysicalDeviceLimits)
2718 res = icd->GetPhysicalDeviceLimits(physicalDevice, pLimits);
2719
2720 return res;
2721}
2722
Mark Lobodzinski16e8bef2015-07-03 15:58:09 -06002723VkResult loader_GetPhysicalDeviceSparseImageFormatProperties(
2724 VkPhysicalDevice physicalDevice,
2725 VkFormat format,
2726 VkImageType type,
2727 uint32_t samples,
2728 VkImageUsageFlags usage,
2729 VkImageTiling tiling,
2730 uint32_t* pNumProperties,
2731 VkSparseImageFormatProperties* pProperties)
2732{
2733 uint32_t gpu_index;
2734 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2735 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2736
2737 if (icd->GetPhysicalDeviceSparseImageFormatProperties)
2738 res = icd->GetPhysicalDeviceSparseImageFormatProperties(physicalDevice, format, type, samples, usage, tiling, pNumProperties, pProperties);
2739
2740 return res;
2741}
2742
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002743VkResult loader_CreateDevice(
2744 VkPhysicalDevice gpu,
2745 const VkDeviceCreateInfo* pCreateInfo,
2746 VkDevice* pDevice)
2747{
2748 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06002749 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002750 struct loader_device *dev;
Courtney Goeltzenleuchter6f5b00c2015-07-06 20:46:50 -06002751 VkDeviceCreateInfo device_create_info;
2752 char **filtered_extension_names = NULL;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002753 VkResult res;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002754
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002755 if (!icd->CreateDevice) {
2756 return VK_ERROR_INITIALIZATION_FAILED;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002757 }
2758
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002759 res = loader_validate_layers(pCreateInfo->layerCount,
2760 pCreateInfo->ppEnabledLayerNames,
2761 &icd->layer_properties_cache);
2762 if (res != VK_SUCCESS) {
2763 return res;
2764 }
2765
Courtney Goeltzenleuchterfedb2a52015-07-08 21:13:16 -06002766 res = loader_validate_device_extensions(icd, gpu_index, pCreateInfo);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002767 if (res != VK_SUCCESS) {
2768 return res;
2769 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002770
Courtney Goeltzenleuchter6f5b00c2015-07-06 20:46:50 -06002771 /*
2772 * NOTE: Need to filter the extensions to only those
2773 * supported by the ICD.
2774 * No ICD will advertise support for layers. An ICD
2775 * library could support a layer, but it would be
2776 * independent of the actual ICD, just in the same library.
2777 */
2778 filtered_extension_names = loader_stack_alloc(pCreateInfo->extensionCount * sizeof(char *));
2779 if (!filtered_extension_names) {
2780 return VK_ERROR_OUT_OF_HOST_MEMORY;
2781 }
2782
2783 /* Copy user's data */
2784 memcpy(&device_create_info, pCreateInfo, sizeof(VkDeviceCreateInfo));
2785
2786 /* ICD's do not use layers */
2787 device_create_info.layerCount = 0;
2788 device_create_info.ppEnabledLayerNames = NULL;
2789
2790 device_create_info.extensionCount = 0;
2791 device_create_info.ppEnabledExtensionNames = (const char * const *) filtered_extension_names;
2792
2793 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2794 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
2795 struct loader_extension_property *prop = get_extension_property(extension_name,
2796 &icd->device_extension_cache[gpu_index]);
2797 if (prop) {
2798 filtered_extension_names[device_create_info.extensionCount] = (char *) extension_name;
2799 device_create_info.extensionCount++;
2800 }
2801 }
2802
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002803 res = icd->CreateDevice(gpu, pCreateInfo, pDevice);
2804 if (res != VK_SUCCESS) {
2805 return res;
2806 }
2807
2808 dev = loader_add_logical_device(*pDevice, &icd->logical_device_list);
2809 if (dev == NULL) {
2810 return VK_ERROR_OUT_OF_HOST_MEMORY;
2811 }
2812 PFN_vkGetDeviceProcAddr get_proc_addr = icd->GetDeviceProcAddr;
2813 loader_init_device_dispatch_table(&dev->loader_dispatch, get_proc_addr,
Courtney Goeltzenleuchtere315d3c2015-07-16 10:36:57 -06002814 *pDevice, *pDevice);
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002815
2816 dev->loader_dispatch.CreateDevice = scratch_vkCreateDevice;
2817 loader_init_dispatch(*pDevice, &dev->loader_dispatch);
2818
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002819 /*
2820 * Put together the complete list of extensions to enable
2821 * This includes extensions requested via environment variables.
2822 */
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06002823 loader_enable_device_layers(icd, dev, pCreateInfo);
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002824
2825 /*
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002826 * Load the libraries and build the device chain
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002827 * terminating with the selected device.
2828 */
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06002829 loader_activate_device_layers(icd, dev, *pDevice);
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002830
2831 res = dev->loader_dispatch.CreateDevice(gpu, pCreateInfo, pDevice);
2832
2833 dev->loader_dispatch.CreateDevice = icd->CreateDevice;
2834
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002835 return res;
2836}
2837
Courtney Goeltzenleuchter2d3ba632015-07-12 14:35:22 -06002838static PFN_vkVoidFunction VKAPI loader_GetInstanceProcAddr(VkInstance instance, const char * pName)
Jon Ashburnb0fbe912015-05-06 10:15:07 -06002839{
Jon Ashburn07daee72015-05-21 18:13:33 -06002840 if (instance == VK_NULL_HANDLE)
2841 return NULL;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002842
Jon Ashburn07daee72015-05-21 18:13:33 -06002843 void *addr;
2844 /* get entrypoint addresses that are global (in the loader)*/
2845 addr = globalGetProcAddr(pName);
2846 if (addr)
2847 return addr;
Jon Ashburnb0fbe912015-05-06 10:15:07 -06002848
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002849 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
2850
Jon Ashburn922c8f62015-06-18 09:05:37 -06002851 /* return any extension global entrypoints */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002852 addr = debug_report_instance_gpa(ptr_instance, pName);
2853 if (addr) {
2854 return addr;
2855 }
2856
Ian Elliottd3ef02f2015-07-06 14:36:13 -06002857 addr = wsi_swapchain_GetInstanceProcAddr(ptr_instance, pName);
David Pinedoa0a8a242015-06-24 15:29:18 -06002858 if (addr) {
Jon Ashburn922c8f62015-06-18 09:05:37 -06002859 return addr;
David Pinedoa0a8a242015-06-24 15:29:18 -06002860 }
Jon Ashburn07daee72015-05-21 18:13:33 -06002861
2862 /* return the instance dispatch table entrypoint for extensions */
2863 const VkLayerInstanceDispatchTable *disp_table = * (VkLayerInstanceDispatchTable **) instance;
2864 if (disp_table == NULL)
2865 return NULL;
2866
2867 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
2868 if (addr)
2869 return addr;
Jon Ashburnb0fbe912015-05-06 10:15:07 -06002870
2871 return NULL;
2872}
2873
Courtney Goeltzenleuchter2d3ba632015-07-12 14:35:22 -06002874LOADER_EXPORT PFN_vkVoidFunction VKAPI vkGetInstanceProcAddr(VkInstance instance, const char * pName)
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -06002875{
2876 return loader_GetInstanceProcAddr(instance, pName);
2877}
2878
Courtney Goeltzenleuchter2d3ba632015-07-12 14:35:22 -06002879static PFN_vkVoidFunction VKAPI loader_GetDeviceProcAddr(VkDevice device, const char * pName)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002880{
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06002881 if (device == VK_NULL_HANDLE) {
2882 return NULL;
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07002883 }
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002884
Chia-I Wuf46b81a2015-01-04 11:12:47 +08002885 void *addr;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002886
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002887 /* for entrypoints that loader must handle (ie non-dispatchable or create object)
2888 make sure the loader entrypoint is returned */
2889 addr = loader_non_passthrough_gpa(pName);
Ian Elliotte19c9152015-04-15 12:53:19 -06002890 if (addr) {
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002891 return addr;
Ian Elliotte19c9152015-04-15 12:53:19 -06002892 }
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002893
2894 /* return the dispatch table entrypoint for the fastest case */
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06002895 const VkLayerDispatchTable *disp_table = * (VkLayerDispatchTable **) device;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002896 if (disp_table == NULL)
2897 return NULL;
2898
Jon Ashburn27cd5842015-05-12 17:26:48 -06002899 addr = loader_lookup_device_dispatch_table(disp_table, pName);
Chia-I Wuf46b81a2015-01-04 11:12:47 +08002900 if (addr)
2901 return addr;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002902 else {
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06002903 if (disp_table->GetDeviceProcAddr == NULL)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002904 return NULL;
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06002905 return disp_table->GetDeviceProcAddr(device, pName);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002906 }
2907}
2908
Courtney Goeltzenleuchter2d3ba632015-07-12 14:35:22 -06002909LOADER_EXPORT PFN_vkVoidFunction VKAPI vkGetDeviceProcAddr(VkDevice device, const char * pName)
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -06002910{
2911 return loader_GetDeviceProcAddr(device, pName);
2912}
2913
Tony Barbour59a47322015-06-24 16:06:58 -06002914LOADER_EXPORT VkResult VKAPI vkGetGlobalExtensionProperties(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002915 const char* pLayerName,
2916 uint32_t* pCount,
2917 VkExtensionProperties* pProperties)
2918{
2919 struct loader_extension_list *global_extension_list;
2920
2921 /* Scan/discover all ICD libraries in a single-threaded manner */
2922 loader_platform_thread_once(&once_icd, loader_icd_scan);
2923
2924 /* get layer libraries in a single-threaded manner */
2925 loader_platform_thread_once(&once_layer, loader_layer_scan);
2926
2927 /* merge any duplicate extensions */
2928 loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
2929
2930 uint32_t copy_size;
2931
2932 if (pCount == NULL) {
2933 return VK_ERROR_INVALID_POINTER;
2934 }
2935
2936 loader_platform_thread_lock_mutex(&loader_lock);
2937
2938 global_extension_list = loader_global_extensions(pLayerName);
2939 if (global_extension_list == NULL) {
2940 loader_platform_thread_unlock_mutex(&loader_lock);
2941 return VK_ERROR_INVALID_LAYER;
2942 }
2943
2944 if (pProperties == NULL) {
2945 *pCount = global_extension_list->count;
2946 loader_platform_thread_unlock_mutex(&loader_lock);
2947 return VK_SUCCESS;
2948 }
2949
2950 copy_size = *pCount < global_extension_list->count ? *pCount : global_extension_list->count;
2951 for (uint32_t i = 0; i < copy_size; i++) {
2952 memcpy(&pProperties[i],
2953 &global_extension_list->list[i].info,
2954 sizeof(VkExtensionProperties));
2955 }
2956 *pCount = copy_size;
2957
2958 loader_platform_thread_unlock_mutex(&loader_lock);
2959
2960 if (copy_size < global_extension_list->count) {
2961 return VK_INCOMPLETE;
2962 }
2963
2964 return VK_SUCCESS;
2965}
2966
2967LOADER_EXPORT VkResult VKAPI vkGetGlobalLayerProperties(
2968 uint32_t* pCount,
2969 VkLayerProperties* pProperties)
Tony Barbour59a47322015-06-24 16:06:58 -06002970{
Jon Ashburn6301a0f2015-05-29 13:15:39 -06002971
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06002972 /* Scan/discover all ICD libraries in a single-threaded manner */
2973 loader_platform_thread_once(&once_icd, loader_icd_scan);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07002974
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06002975 /* get layer libraries in a single-threaded manner */
Jon Ashburn5ef20602015-07-02 09:40:15 -06002976 loader_platform_thread_once(&once_layer, loader_layer_scan);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07002977
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06002978 /* merge any duplicate extensions */
2979 loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
2980
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002981 uint32_t copy_size;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06002982
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002983 if (pCount == NULL) {
2984 return VK_ERROR_INVALID_POINTER;
2985 }
2986
2987 /* TODO: do we still need to lock */
Jon Ashburn6301a0f2015-05-29 13:15:39 -06002988 loader_platform_thread_lock_mutex(&loader_lock);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002989
2990 struct loader_layer_list *layer_list;
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002991 layer_list = loader_scanned_layers();
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002992
2993 if (pProperties == NULL) {
2994 *pCount = layer_list->count;
2995 loader_platform_thread_unlock_mutex(&loader_lock);
2996 return VK_SUCCESS;
2997 }
2998
2999 copy_size = *pCount < layer_list->count ? *pCount : layer_list->count;
3000 for (uint32_t i = 0; i < copy_size; i++) {
3001 memcpy(&pProperties[i], &layer_list->list[i].info, sizeof(VkLayerProperties));
3002 }
3003 *pCount = copy_size;
Tony Barbour59a47322015-06-24 16:06:58 -06003004
Jon Ashburn6301a0f2015-05-29 13:15:39 -06003005 loader_platform_thread_unlock_mutex(&loader_lock);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06003006
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06003007 if (copy_size < layer_list->count) {
3008 return VK_INCOMPLETE;
3009 }
Tony Barbour59a47322015-06-24 16:06:58 -06003010
3011 return VK_SUCCESS;
3012}
3013
3014VkResult loader_GetPhysicalDeviceExtensionProperties(
3015 VkPhysicalDevice gpu,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06003016 const char* pLayerName,
3017 uint32_t* pCount,
Tony Barbour59a47322015-06-24 16:06:58 -06003018 VkExtensionProperties* pProperties)
3019{
3020 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06003021 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06003022 uint32_t copy_size;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07003023
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06003024 if (pCount == NULL) {
3025 return VK_ERROR_INVALID_POINTER;
3026 }
Jon Ashburn95a77ba2015-05-15 15:09:35 -06003027
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06003028 uint32_t count;
3029 struct loader_extension_list *list;
3030 loader_physical_device_extensions(icd, gpu_index, pLayerName, &count, &list);
3031
3032 if (pProperties == NULL) {
3033 *pCount = count;
3034 return VK_SUCCESS;
3035 }
3036
3037 copy_size = *pCount < count ? *pCount : count;
3038 for (uint32_t i = 0; i < copy_size; i++) {
3039 memcpy(&pProperties[i],
3040 &list->list[i].info,
3041 sizeof(VkExtensionProperties));
3042 }
3043 *pCount = copy_size;
3044
3045 if (copy_size < count) {
3046 return VK_INCOMPLETE;
3047 }
3048
3049 return VK_SUCCESS;
3050}
3051
3052VkResult loader_GetPhysicalDeviceLayerProperties(
3053 VkPhysicalDevice gpu,
3054 uint32_t* pCount,
3055 VkLayerProperties* pProperties)
3056{
3057 uint32_t gpu_index;
3058 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
3059 uint32_t copy_size;
3060
3061 if (pCount == NULL) {
3062 return VK_ERROR_INVALID_POINTER;
3063 }
3064
3065 uint32_t count;
3066 struct loader_layer_list *layer_list;
3067 loader_physical_device_layers(icd, &count, &layer_list);
3068
3069 if (pProperties == NULL) {
3070 *pCount = count;
3071 return VK_SUCCESS;
3072 }
3073
3074 copy_size = *pCount < count ? *pCount : count;
3075 for (uint32_t i = 0; i < copy_size; i++) {
3076 memcpy(&pProperties[i],
3077 &layer_list->list[i].info,
3078 sizeof(VkLayerProperties));
3079 }
3080 *pCount = copy_size;
3081
3082 if (copy_size < count) {
3083 return VK_INCOMPLETE;
3084 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06003085
3086 return VK_SUCCESS;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06003087}