blob: 75701cf218c3f27155805b5d5e63044570b02019 [file] [log] [blame]
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001/*
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06002 * Vulkan
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08003 *
4 * Copyright (C) 2014 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
Chia-I Wu701f3f62014-09-02 08:32:09 +080023 *
24 * Authors:
25 * Chia-I Wu <olv@lunarg.com>
Jon Ashburn01e2d662014-11-14 09:52:42 -070026 * Jon Ashburn <jon@lunarg.com>
Chia-I Wu701f3f62014-09-02 08:32:09 +080027 * Courtney Goeltzenleuchter <courtney@lunarg.com>
Ian Elliott5aa4ea22015-03-31 15:32:41 -060028 * Ian Elliott <ian@lunarg.com>
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080029 */
Jon Ashburn6b4d70c2014-10-22 18:13:16 -060030#define _GNU_SOURCE
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080031#include <stdio.h>
32#include <stdlib.h>
33#include <stdarg.h>
34#include <stdbool.h>
35#include <string.h>
36
Chia-I Wu13a61a52014-08-04 11:18:20 +080037#include <sys/types.h>
Ian Elliott2d4ab1e2015-01-13 17:52:38 -070038#if defined(WIN32)
39#include "dirent_on_windows.h"
40#else // WIN32
Chia-I Wu13a61a52014-08-04 11:18:20 +080041#include <dirent.h>
Ian Elliott2d4ab1e2015-01-13 17:52:38 -070042#endif // WIN32
Tobin Ehlisb835d1b2015-07-03 10:34:49 -060043#include "vk_loader_platform.h"
Chia-I Wu19300602014-08-04 08:03:57 +080044#include "loader.h"
Jon Ashburn07daee72015-05-21 18:13:33 -060045#include "wsi_lunarg.h"
Jon Ashburn27cd5842015-05-12 17:26:48 -060046#include "gpa_helper.h"
47#include "table_ops.h"
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060048#include "debug_report.h"
Tobin Ehlis0c6f9ee2015-07-03 09:42:57 -060049#include "vk_icd.h"
Jon Ashburn2077e382015-06-29 11:25:34 -060050#include "cJSON.h"
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080051
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060052void loader_add_to_ext_list(
53 struct loader_extension_list *ext_list,
54 uint32_t prop_list_count,
55 const struct loader_extension_property *prop_list);
56
Courtney Goeltzenleuchtered488302015-06-01 14:09:34 -060057static loader_platform_dl_handle loader_add_layer_lib(
58 const char *chain_type,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -060059 struct loader_layer_properties *layer_prop);
Courtney Goeltzenleuchtered488302015-06-01 14:09:34 -060060
61static void loader_remove_layer_lib(
62 struct loader_instance *inst,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -060063 struct loader_layer_properties *layer_prop);
Courtney Goeltzenleuchtered488302015-06-01 14:09:34 -060064
Jon Ashburn27cd5842015-05-12 17:26:48 -060065struct loader_struct loader = {0};
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080066
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -060067static void * VKAPI loader_GetInstanceProcAddr(VkInstance instance, const char * pName);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -060068static bool loader_init_ext_list(struct loader_extension_list *ext_info);
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -060069
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -060070enum loader_debug {
71 LOADER_INFO_BIT = VK_BIT(0),
72 LOADER_WARN_BIT = VK_BIT(1),
73 LOADER_PERF_BIT = VK_BIT(2),
74 LOADER_ERROR_BIT = VK_BIT(3),
75 LOADER_DEBUG_BIT = VK_BIT(4),
76};
77
78uint32_t g_loader_debug = 0;
79uint32_t g_loader_log_msgs = 0;
80
Jon Ashburn6301a0f2015-05-29 13:15:39 -060081//thread safety lock for accessing global data structures such as "loader"
82// all entrypoints on the instance chain need to be locked except GPA
Jon Ashburn2077e382015-06-29 11:25:34 -060083// additionally CreateDevice and DestroyDevice needs to be locked
Jon Ashburn6301a0f2015-05-29 13:15:39 -060084loader_platform_thread_mutex loader_lock;
85
86const VkLayerInstanceDispatchTable instance_disp = {
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -060087 .GetInstanceProcAddr = loader_GetInstanceProcAddr,
Jon Ashburn27cd5842015-05-12 17:26:48 -060088 .CreateInstance = loader_CreateInstance,
89 .DestroyInstance = loader_DestroyInstance,
90 .EnumeratePhysicalDevices = loader_EnumeratePhysicalDevices,
Chris Forbesbc0bb772015-06-21 22:55:02 +120091 .GetPhysicalDeviceFeatures = loader_GetPhysicalDeviceFeatures,
92 .GetPhysicalDeviceFormatInfo = loader_GetPhysicalDeviceFormatInfo,
93 .GetPhysicalDeviceLimits = loader_GetPhysicalDeviceLimits,
Tony Barbour59a47322015-06-24 16:06:58 -060094 .GetPhysicalDeviceProperties = loader_GetPhysicalDeviceProperties,
95 .GetPhysicalDevicePerformance = loader_GetPhysicalDevicePerformance,
96 .GetPhysicalDeviceQueueCount = loader_GetPhysicalDeviceQueueCount,
97 .GetPhysicalDeviceQueueProperties = loader_GetPhysicalDeviceQueueProperties,
98 .GetPhysicalDeviceMemoryProperties = loader_GetPhysicalDeviceMemoryProperties,
Tony Barbour59a47322015-06-24 16:06:58 -060099 .GetPhysicalDeviceExtensionProperties = loader_GetPhysicalDeviceExtensionProperties,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600100 .GetPhysicalDeviceLayerProperties = loader_GetPhysicalDeviceLayerProperties,
Mark Lobodzinski16e8bef2015-07-03 15:58:09 -0600101 .GetPhysicalDeviceSparseImageFormatProperties = loader_GetPhysicalDeviceSparseImageFormatProperties,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600102 .DbgCreateMsgCallback = loader_DbgCreateMsgCallback,
103 .DbgDestroyMsgCallback = loader_DbgDestroyMsgCallback,
Jon Ashburn27cd5842015-05-12 17:26:48 -0600104};
105
106LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_icd);
107LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_layer);
108LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_exts);
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700109
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600110void* loader_heap_alloc(
111 struct loader_instance *instance,
112 size_t size,
113 VkSystemAllocType alloc_type)
114{
115 if (instance && instance->alloc_callbacks.pfnAlloc) {
116 /* TODO: What should default alignment be? 1, 4, 8, other? */
117 return instance->alloc_callbacks.pfnAlloc(instance->alloc_callbacks.pUserData, size, 4, alloc_type);
118 }
119 return malloc(size);
120}
121
122void* loader_aligned_heap_alloc(
123 struct loader_instance *instance,
124 size_t size,
125 size_t alignment,
126 VkSystemAllocType alloc_type)
127{
128 if (!instance && instance->alloc_callbacks.pfnAlloc) {
129 return instance->alloc_callbacks.pfnAlloc(instance->alloc_callbacks.pUserData, size, alignment, alloc_type);
130 }
Cody Northrop33fa0412015-07-08 16:48:37 -0600131#if defined(_WIN32)
132 return _aligned_malloc(alignment, size);
133#else
134 return aligned_alloc(alignment, size);
135#endif
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600136}
137
138void loader_heap_free(
139 struct loader_instance *instance,
140 void *pMem)
141{
142 if (!instance && instance->alloc_callbacks.pfnFree) {
Courtney Goeltzenleuchter922e1452015-07-10 17:39:59 -0600143 instance->alloc_callbacks.pfnFree(instance->alloc_callbacks.pUserData, pMem);
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600144 }
Courtney Goeltzenleuchter922e1452015-07-10 17:39:59 -0600145 free(pMem);
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600146}
147
Jon Ashburnffad94d2015-06-30 14:46:22 -0700148static void loader_log(VkFlags msg_type, int32_t msg_code,
149 const char *format, ...)
150{
151 char msg[256];
152 va_list ap;
153 int ret;
154
155 if (!(msg_type & g_loader_log_msgs)) {
156 return;
157 }
158
159 va_start(ap, format);
160 ret = vsnprintf(msg, sizeof(msg), format, ap);
161 if ((ret >= (int) sizeof(msg)) || ret < 0) {
162 msg[sizeof(msg)-1] = '\0';
163 }
164 va_end(ap);
165
Ian Elliott4470a302015-02-17 10:33:47 -0700166#if defined(WIN32)
Jon Ashburnffad94d2015-06-30 14:46:22 -0700167 OutputDebugString(msg);
168#endif
169 fputs(msg, stderr);
170 fputc('\n', stderr);
171}
172
173#if defined(WIN32)
174/**
175* Find the list of registry files (names within a key) in key "location".
176*
177* This function looks in the registry (hive = DEFAULT_VK_REGISTRY_HIVE) key as given in "location"
178* for a list or name/values which are added to a returned list (function return value).
179* The DWORD values within the key must be 0 or they are skipped.
180* Function return is a string with a ';' seperated list of filenames.
181* Function return is NULL if no valid name/value pairs are found in the key,
182* or the key is not found.
183*
184* \returns
185* A string list of filenames as pointer.
186* When done using the returned string list, pointer should be freed.
187*/
188static char *loader_get_registry_files(const char *location)
189{
190 LONG rtn_value;
191 HKEY hive, key;
192 DWORD access_flags = KEY_QUERY_VALUE;
193 char name[2048];
194 char *out = NULL;
195
196 hive = DEFAULT_VK_REGISTRY_HIVE;
197 rtn_value = RegOpenKeyEx(hive, location, 0, access_flags, &key);
198 if (rtn_value != ERROR_SUCCESS) {
199 // We didn't find the key. Try the 32-bit hive (where we've seen the
200 // key end up on some people's systems):
201 access_flags |= KEY_WOW64_32KEY;
202 rtn_value = RegOpenKeyEx(hive, location, 0, access_flags, &key);
203 if (rtn_value != ERROR_SUCCESS) {
204 // We still couldn't find the key, so give up:
205 return NULL;
206 }
207 }
208
209 DWORD idx = 0;
210 DWORD name_size = sizeof(name);
211 DWORD value;
212 DWORD total_size = 4096;
213 DWORD value_size = sizeof(value);
214 while((rtn_value = RegEnumValue(key, idx++, name, &name_size, NULL, NULL, (LPBYTE) &value, &value_size)) == ERROR_SUCCESS) {
215 if (value_size == sizeof(value) && value == 0) {
216 if (out == NULL) {
217 out = malloc(total_size);
218 out[0] = '\0';
219 }
220 else if (strlen(out) + name_size + 1 > total_size) {
221 out = realloc(out, total_size * 2);
222 total_size *= 2;
223 }
224 if (out == NULL) {
225 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory, failed loader_get_registry_files");
226 return NULL;
227 }
228 if (strlen(out) == 0)
229 snprintf(out, name_size + 1, "%s", name);
230 else
231 snprintf(out + strlen(out), name_size + 1, "%c%s", PATH_SEPERATOR, name);
232 }
233 }
234 return out;
235}
236
Ian Elliott4470a302015-02-17 10:33:47 -0700237#endif // WIN32
238
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600239bool compare_vk_extension_properties(const VkExtensionProperties *op1, const VkExtensionProperties *op2)
240{
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600241 return strcmp(op1->extName, op2->extName) == 0 ? true : false;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600242}
243
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -0600244/**
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600245 * Search the given ext_array for an extension
246 * matching the given vk_ext_prop
247 */
248bool has_vk_extension_property_array(
249 const VkExtensionProperties *vk_ext_prop,
250 const uint32_t count,
251 const VkExtensionProperties *ext_array)
252{
253 for (uint32_t i = 0; i < count; i++) {
254 if (compare_vk_extension_properties(vk_ext_prop, &ext_array[i]))
255 return true;
256 }
257 return false;
258}
259
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -0600260/**
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600261 * Search the given ext_list for an extension
262 * matching the given vk_ext_prop
263 */
264bool has_vk_extension_property(
265 const VkExtensionProperties *vk_ext_prop,
266 const struct loader_extension_list *ext_list)
267{
268 for (uint32_t i = 0; i < ext_list->count; i++) {
269 if (compare_vk_extension_properties(&ext_list->list[i].info, vk_ext_prop))
270 return true;
271 }
272 return false;
273}
274
275/*
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -0600276 * Search the given layer list for a layer matching the given layer name
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600277 */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600278static struct loader_layer_properties *get_layer_property(
279 const char *name,
280 const struct loader_layer_list *layer_list)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600281{
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600282 for (uint32_t i = 0; i < layer_list->count; i++) {
283 const VkLayerProperties *item = &layer_list->list[i].info;
284 if (strcmp(name, item->layerName) == 0)
285 return &layer_list->list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600286 }
287 return NULL;
288}
289
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600290static void loader_add_global_extensions(
Tony Barbour59a47322015-06-24 16:06:58 -0600291 const PFN_vkGetGlobalExtensionProperties fp_get_props,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600292 const char *lib_name,
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600293 const loader_platform_dl_handle lib_handle,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600294 const enum extension_origin origin,
295 struct loader_extension_list *ext_list)
296{
297 uint32_t i, count;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600298 struct loader_extension_property ext_props;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600299 VkExtensionProperties *extension_properties;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600300 VkResult res;
301
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -0600302 if (!fp_get_props) {
303 /* No GetGlobalExtensionProperties defined */
304 return;
305 }
306
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600307 res = fp_get_props(NULL, &count, NULL);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600308 if (res != VK_SUCCESS) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600309 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extension count from %s", lib_name);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600310 return;
311 }
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600312
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -0600313 if (count == 0) {
314 /* No ExtensionProperties to report */
315 return;
316 }
317
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600318 extension_properties = loader_stack_alloc(count * sizeof(VkExtensionProperties));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600319
320 res = fp_get_props(NULL, &count, extension_properties);
321 if (res != VK_SUCCESS) {
322 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extensions from %s", lib_name);
323 return;
324 }
Tony Barbour59a47322015-06-24 16:06:58 -0600325
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600326 for (i = 0; i < count; i++) {
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600327 memset(&ext_props, 0, sizeof(ext_props));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600328 memcpy(&ext_props.info, &extension_properties[i], sizeof(VkExtensionProperties));
329 //TODO eventually get this from the layer config file
330 ext_props.origin = origin;
331 ext_props.lib_name = lib_name;
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600332
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600333 char spec_version[64], version[64];
334
335 snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
336 VK_MAJOR(ext_props.info.specVersion),
337 VK_MINOR(ext_props.info.specVersion),
338 VK_PATCH(ext_props.info.specVersion));
339 snprintf(version, sizeof(version), "%d.%d.%d",
340 VK_MAJOR(ext_props.info.version),
341 VK_MINOR(ext_props.info.version),
342 VK_PATCH(ext_props.info.version));
343
344 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
345 "Global Extension: %s (%s) version %s, Vulkan version %s",
346 ext_props.info.extName, lib_name, version, spec_version);
347 loader_add_to_ext_list(ext_list, 1, &ext_props);
348 }
349
350 return;
351}
352
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600353static void loader_add_physical_device_extensions(
354 PFN_vkGetPhysicalDeviceExtensionProperties get_phys_dev_ext_props,
355 VkPhysicalDevice physical_device,
356 const enum extension_origin origin,
357 const char *lib_name,
358 struct loader_extension_list *ext_list)
359{
360 uint32_t i, count;
361 VkResult res;
362 struct loader_extension_property ext_props;
363 VkExtensionProperties *extension_properties;
364
365 memset(&ext_props, 0, sizeof(ext_props));
366 ext_props.origin = origin;
367 ext_props.lib_name = lib_name;
368
369 if (get_phys_dev_ext_props) {
370 res = get_phys_dev_ext_props(physical_device, NULL, &count, NULL);
371 if (res == VK_SUCCESS && count > 0) {
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600372
373 extension_properties = loader_stack_alloc(count * sizeof(VkExtensionProperties));
374
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600375 res = get_phys_dev_ext_props(physical_device, NULL, &count, extension_properties);
376 for (i = 0; i < count; i++) {
377 char spec_version[64], version[64];
378
379 memcpy(&ext_props.info, &extension_properties[i], sizeof(VkExtensionProperties));
380
381 snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
382 VK_MAJOR(ext_props.info.specVersion),
383 VK_MINOR(ext_props.info.specVersion),
384 VK_PATCH(ext_props.info.specVersion));
385 snprintf(version, sizeof(version), "%d.%d.%d",
386 VK_MAJOR(ext_props.info.version),
387 VK_MINOR(ext_props.info.version),
388 VK_PATCH(ext_props.info.version));
389
390 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
391 "PhysicalDevice Extension: %s (%s) version %s, Vulkan version %s",
392 ext_props.info.extName, lib_name, version, spec_version);
393 loader_add_to_ext_list(ext_list, 1, &ext_props);
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600394 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600395 } else {
396 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 -0600397 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600398 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600399
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600400 return;
401}
402
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600403static void loader_add_physical_device_layer_properties(
404 struct loader_icd *icd,
405 char *lib_name,
406 const loader_platform_dl_handle lib_handle)
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600407{
408 uint32_t i, count;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600409 VkLayerProperties *layer_properties;
410 PFN_vkGetPhysicalDeviceExtensionProperties fp_get_ext_props;
411 PFN_vkGetPhysicalDeviceLayerProperties fp_get_layer_props;
412 VkPhysicalDevice gpu = icd->gpus[0];
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600413 VkResult res;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600414
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600415 fp_get_ext_props = loader_platform_get_proc_address(lib_handle, "vkGetPhysicalDeviceExtensionProperties");
416 if (!fp_get_ext_props) {
417 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
418 "Couldn't dlsym vkGetPhysicalDeviceExtensionProperties from library %s",
419 lib_name);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600420 }
421
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600422 fp_get_layer_props = loader_platform_get_proc_address(lib_handle, "vkGetPhysicalDeviceLayerProperties");
423 if (!fp_get_layer_props) {
424 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
425 "Couldn't dlsym vkGetPhysicalDeviceLayerProperties from library %s",
426 lib_name);
427 return;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600428 }
429
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600430 /*
431 * NOTE: We assume that all GPUs of an ICD support the same PhysicalDevice
432 * layers and extensions. Thus only ask for info about the first gpu.
433 */
434 res = fp_get_layer_props(gpu, &count, NULL);
435 if (res != VK_SUCCESS) {
436 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Error getting PhysicalDevice layer count from %s", lib_name);
437 return;
438 }
439
440 if (count == 0) {
441 return;
442 }
443
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600444 layer_properties = loader_stack_alloc(count * sizeof(VkLayerProperties));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600445
446 res = fp_get_layer_props(gpu, &count, layer_properties);
447 if (res != VK_SUCCESS) {
448 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Error getting %d PhysicalDevice layer properties from %s",
449 count, lib_name);
450 return;
451 }
452
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -0600453 //TODO get layer properties from manifest file
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600454 for (i = 0; i < count; i++) {
455 struct loader_layer_properties layer;
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600456
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600457 memset(&layer, 0, sizeof(struct loader_layer_properties));
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600458
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600459 layer.lib_info.lib_name = lib_name;
460 memcpy(&layer.info, &layer_properties[i], sizeof(VkLayerProperties));
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600461
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600462 loader_init_ext_list(&layer.instance_extension_list);
463 loader_init_ext_list(&layer.device_extension_list);
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600464
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600465 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Collecting PhysicalDevice extensions for layer %s (%s)",
466 layer.info.layerName, layer.info.description);
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600467
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600468 loader_add_physical_device_extensions(
469 fp_get_ext_props,
470 icd->gpus[i],
471 VK_EXTENSION_ORIGIN_LAYER,
472 lib_name,
473 &layer.device_extension_list);
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600474
475 loader_add_to_layer_list(&icd->layer_properties_cache, 1, &layer);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600476 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600477 return;
478}
479
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600480static bool loader_init_ext_list(struct loader_extension_list *ext_info)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600481{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600482 ext_info->capacity = 32 * sizeof(struct loader_extension_property);
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600483 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600484 ext_info->list = malloc(ext_info->capacity);
485 if (ext_info->list == NULL) {
486 return false;
487 }
488 memset(ext_info->list, 0, ext_info->capacity);
489 ext_info->count = 0;
490 return true;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600491}
492
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -0600493void loader_destroy_ext_list(struct loader_extension_list *ext_info)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600494{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600495 free(ext_info->list);
496 ext_info->count = 0;
497 ext_info->capacity = 0;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600498}
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600499
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600500/**
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600501 * Search the given search_list for any layers in the props list.
502 * Add these to the output layer_list. Don't add duplicates to the output layer_list.
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600503 */
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -0600504static VkResult loader_add_layer_names_to_list(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600505 struct loader_layer_list *output_list,
506 uint32_t name_count,
507 const char * const *names,
508 const struct loader_layer_list *search_list)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600509{
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600510 struct loader_layer_properties *layer_prop;
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -0600511 VkResult err = VK_SUCCESS;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600512
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600513 for (uint32_t i = 0; i < name_count; i++) {
514 const char *search_target = names[i];
515 layer_prop = get_layer_property(search_target, search_list);
516 if (!layer_prop) {
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -0600517 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Unable to find layer %s", search_target);
518 err = VK_ERROR_INVALID_LAYER;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600519 continue;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600520 }
521
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600522 loader_add_to_layer_list(output_list, 1, layer_prop);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600523 }
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -0600524
525 return err;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600526}
527
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600528/*
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -0600529 * Append non-duplicate extension properties defined in props
530 * to the given ext_list.
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600531 */
532void loader_add_to_ext_list(
533 struct loader_extension_list *ext_list,
534 uint32_t prop_list_count,
535 const struct loader_extension_property *props)
536{
537 uint32_t i;
538 struct loader_extension_property *cur_ext;
539
540 if (ext_list->list == NULL || ext_list->capacity == 0) {
541 loader_init_ext_list(ext_list);
542 }
543
544 if (ext_list->list == NULL)
545 return;
546
547 for (i = 0; i < prop_list_count; i++) {
548 cur_ext = (struct loader_extension_property *) &props[i];
549
550 // look for duplicates
551 if (has_vk_extension_property(&cur_ext->info, ext_list)) {
552 continue;
553 }
554
555 // add to list at end
556 // check for enough capacity
557 if (ext_list->count * sizeof(struct loader_extension_property)
558 >= ext_list->capacity) {
559 // double capacity
560 ext_list->capacity *= 2;
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600561 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600562 ext_list->list = realloc(ext_list->list, ext_list->capacity);
563 }
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600564
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600565 memcpy(&ext_list->list[ext_list->count], cur_ext, sizeof(struct loader_extension_property));
566 ext_list->count++;
567 }
568}
569
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600570/*
571 * Manage lists of VkLayerProperties
572 */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600573static bool loader_init_layer_list(struct loader_layer_list *list)
574{
575 list->capacity = 32 * sizeof(struct loader_layer_properties);
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600576 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600577 list->list = malloc(list->capacity);
578 if (list->list == NULL) {
579 return false;
580 }
581 memset(list->list, 0, list->capacity);
582 list->count = 0;
583 return true;
584}
585
586void loader_destroy_layer_list(struct loader_layer_list *layer_list)
587{
588 free(layer_list->list);
589 layer_list->count = 0;
590 layer_list->capacity = 0;
591}
592
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600593/*
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600594 * Manage list of layer libraries (loader_lib_info)
595 */
596static bool loader_init_layer_library_list(struct loader_layer_library_list *list)
597{
598 list->capacity = 32 * sizeof(struct loader_lib_info);
599 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
600 list->list = malloc(list->capacity);
601 if (list->list == NULL) {
602 return false;
603 }
604 memset(list->list, 0, list->capacity);
605 list->count = 0;
606 return true;
607}
608
609void loader_destroy_layer_library_list(struct loader_layer_library_list *list)
610{
611 for (uint32_t i = 0; i < list->count; i++) {
612 free(list->list[i].lib_name);
613 }
614 free(list->list);
615 list->count = 0;
616 list->capacity = 0;
617}
618
619void loader_add_to_layer_library_list(
620 struct loader_layer_library_list *list,
621 uint32_t item_count,
622 const struct loader_lib_info *new_items)
623{
624 uint32_t i;
625 struct loader_lib_info *item;
626
627 if (list->list == NULL || list->capacity == 0) {
628 loader_init_layer_library_list(list);
629 }
630
631 if (list->list == NULL)
632 return;
633
634 for (i = 0; i < item_count; i++) {
635 item = (struct loader_lib_info *) &new_items[i];
636
637 // look for duplicates
638 for (uint32_t j = 0; j < list->count; j++) {
639 if (strcmp(list->list[i].lib_name, new_items->lib_name) == 0) {
640 continue;
641 }
642 }
643
644 // add to list at end
645 // check for enough capacity
646 if (list->count * sizeof(struct loader_lib_info)
647 >= list->capacity) {
648 // double capacity
649 list->capacity *= 2;
650 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
651 list->list = realloc(list->list, list->capacity);
652 }
653
654 memcpy(&list->list[list->count], item, sizeof(struct loader_lib_info));
655 list->count++;
656 }
657}
658
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -0600659#if 0
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600660/*
661 * Add's library indicated by lib_name to list if it
662 * implements vkGetGlobalLayerProperties or
663 * vkGetPhysicalDeviceLayerProperties.
664 */
665static void loader_add_layer_library(
666 struct loader_instance *instance,
667 const char *lib_name,
668 const loader_platform_dl_handle lib_handle,
669 struct loader_layer_library_list *list)
670{
671 struct loader_lib_info *library_info;
672 PFN_vkGetPhysicalDeviceLayerProperties fp_get_phydev_props;
673 PFN_vkGetGlobalLayerProperties fp_get_layer_props;
674
675 fp_get_layer_props = loader_platform_get_proc_address(lib_handle, "vkGetGlobalLayerProperties");
676 fp_get_phydev_props = loader_platform_get_proc_address(lib_handle, "vkGetPhysicalDeviceLayerProperties");
677
678 if (!fp_get_layer_props && !fp_get_phydev_props)
679 return;
680
681 /*
682 * Allocate enough space for the library name to
683 * immediately follow the loader_lib_info structure
684 */
685 library_info = loader_heap_alloc(instance, sizeof(struct loader_lib_info) + strlen(lib_name) + 1, VK_SYSTEM_ALLOC_TYPE_INTERNAL);
686 if (!library_info) {
687 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
688 "Malloc for layer library list failed: %s line: %d", __FILE__, __LINE__);
689 return;
690 }
691 memset(library_info, 0, sizeof(struct loader_lib_info));
692 library_info->lib_name = (char *) &library_info[1];
693 strcpy(library_info->lib_name, lib_name);
694
695 loader_add_to_layer_library_list(list, 1, library_info);
696}
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -0600697#endif
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600698/*
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600699 * Search the given layer list for a list
700 * matching the given VkLayerProperties
701 */
702bool has_vk_layer_property(
703 const VkLayerProperties *vk_layer_prop,
704 const struct loader_layer_list *list)
705{
706 for (uint32_t i = 0; i < list->count; i++) {
707 if (strcmp(vk_layer_prop->layerName, list->list[i].info.layerName) == 0)
708 return true;
709 }
710 return false;
711}
712
713/*
714 * Search the given layer list for a layer
715 * matching the given name
716 */
717bool has_layer_name(
718 const char *name,
719 const struct loader_layer_list *list)
720{
721 for (uint32_t i = 0; i < list->count; i++) {
722 if (strcmp(name, list->list[i].info.layerName) == 0)
723 return true;
724 }
725 return false;
726}
727
728/*
729 * Append non-duplicate layer properties defined in prop_list
730 * to the given layer_info list
731 */
732void loader_add_to_layer_list(
733 struct loader_layer_list *list,
734 uint32_t prop_list_count,
735 const struct loader_layer_properties *props)
736{
737 uint32_t i;
738 struct loader_layer_properties *layer;
739
740 if (list->list == NULL || list->capacity == 0) {
741 loader_init_layer_list(list);
742 }
743
744 if (list->list == NULL)
745 return;
746
747 for (i = 0; i < prop_list_count; i++) {
748 layer = (struct loader_layer_properties *) &props[i];
749
750 // look for duplicates
751 if (has_vk_layer_property(&layer->info, list)) {
752 continue;
753 }
754
755 // add to list at end
756 // check for enough capacity
757 if (list->count * sizeof(struct loader_layer_properties)
758 >= list->capacity) {
759 // double capacity
760 list->capacity *= 2;
761 list->list = realloc(list->list, list->capacity);
762 }
763
764 memcpy(&list->list[list->count], layer, sizeof(struct loader_layer_properties));
765 list->count++;
766 }
767}
768
Jon Ashburnbd332cc2015-07-07 10:27:45 -0600769/**
770 * Search the search_list for any layer with a name
771 * that matches the given name and a type that matches the given type
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600772 * Add all matching layers to the found_list
Jon Ashburnbd332cc2015-07-07 10:27:45 -0600773 * Do not add if found loader_layer_properties is already
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600774 * on the found_list.
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600775 */
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600776static void loader_find_layer_name_add_list(
777 const char *name,
Jon Ashburnbd332cc2015-07-07 10:27:45 -0600778 const enum layer_type type,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600779 const struct loader_layer_list *search_list,
780 struct loader_layer_list *found_list)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600781{
782 for (uint32_t i = 0; i < search_list->count; i++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600783 struct loader_layer_properties *layer_prop = &search_list->list[i];
Jon Ashburnbd332cc2015-07-07 10:27:45 -0600784 if (0 == strcmp(layer_prop->info.layerName, name) &&
785 (layer_prop->type & type)) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600786 /* Found a layer with the same name, add to found_list */
787 loader_add_to_layer_list(found_list, 1, layer_prop);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600788 }
789 }
790}
791
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -0600792static struct loader_extension_property *get_extension_property(
793 const char *name,
794 const struct loader_extension_list *list)
Jon Ashburnfc2e38c2015-04-14 09:15:32 -0600795{
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -0600796 for (uint32_t i = 0; i < list->count; i++) {
797 const VkExtensionProperties *item = &list->list[i].info;
798 if (strcmp(name, item->extName) == 0)
799 return &list->list[i];
Jon Ashburnfc2e38c2015-04-14 09:15:32 -0600800 }
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -0600801 return NULL;
Jon Ashburnfc2e38c2015-04-14 09:15:32 -0600802}
803
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600804/*
805 * For global exenstions implemented within the loader (i.e. DEBUG_REPORT
806 * the extension must provide two entry points for the loader to use:
807 * - "trampoline" entry point - this is the address returned by GetProcAddr
808 * and will always do what's necessary to support a global call.
809 * - "terminator" function - this function will be put at the end of the
810 * instance chain and will contain the necessary logica to call / process
811 * the extension for the appropriate ICDs that are available.
812 * There is no generic mechanism for including these functions, the references
813 * must be placed into the appropriate loader entry points.
814 * GetInstanceProcAddr: call extension GetInstanceProcAddr to check for GetProcAddr requests
815 * loader_coalesce_extensions(void) - add extension records to the list of global
816 * extension available to the app.
817 * instance_disp - add function pointer for terminator function to this array.
818 * The extension itself should be in a separate file that will be
819 * linked directly with the loader.
820 */
Jon Ashburn27cd5842015-05-12 17:26:48 -0600821void loader_coalesce_extensions(void)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600822{
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600823 struct loader_scanned_icds *icd_list = loader.scanned_icd_list;
824
825 // traverse scanned icd list adding non-duplicate extensions to the list
826 while (icd_list != NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600827 loader_add_to_ext_list(&loader.global_extensions,
828 icd_list->global_extension_list.count,
829 icd_list->global_extension_list.list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600830 icd_list = icd_list->next;
831 };
832
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600833 // Traverse loader's extensions, adding non-duplicate extensions to the list
834 debug_report_add_instance_extensions(&loader.global_extensions);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600835}
836
Jon Ashburndc6fcad2015-06-10 10:06:06 -0600837static struct loader_icd *loader_get_icd_and_device(const VkDevice device,
838 struct loader_device **found_dev)
839{
840 *found_dev = NULL;
841 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
842 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
843 for (struct loader_device *dev = icd->logical_device_list; dev; dev = dev->next)
844 if (dev->device == device) {
845 *found_dev = dev;
846 return icd;
847 }
848 }
849 }
850 return NULL;
851}
852
853static void loader_destroy_logical_device(struct loader_device *dev)
854{
855 free(dev->app_extension_props);
Jon Ashburndc6fcad2015-06-10 10:06:06 -0600856 if (dev->activated_layer_list.count)
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600857 loader_destroy_layer_list(&dev->activated_layer_list);
Jon Ashburndc6fcad2015-06-10 10:06:06 -0600858 free(dev);
859}
860
861static struct loader_device *loader_add_logical_device(const VkDevice dev, struct loader_device **device_list)
862{
863 struct loader_device *new_dev;
864
865 new_dev = malloc(sizeof(struct loader_device));
866 if (!new_dev) {
867 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc struct laoder-device");
868 return NULL;
869 }
870
871 memset(new_dev, 0, sizeof(struct loader_device));
872
873 new_dev->next = *device_list;
874 new_dev->device = dev;
875 *device_list = new_dev;
876 return new_dev;
877}
878
879void loader_remove_logical_device(VkDevice device)
880{
881 struct loader_device *found_dev, *dev, *prev_dev;
882 struct loader_icd *icd;
883 icd = loader_get_icd_and_device(device, &found_dev);
884
885 if (!icd || !found_dev)
886 return;
887
888 prev_dev = NULL;
889 dev = icd->logical_device_list;
890 while (dev && dev != found_dev) {
891 prev_dev = dev;
892 dev = dev->next;
893 }
894
895 if (prev_dev)
896 prev_dev->next = found_dev->next;
897 else
898 icd->logical_device_list = found_dev->next;
899 loader_destroy_logical_device(found_dev);
900}
901
902
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600903static void loader_icd_destroy(
904 struct loader_instance *ptr_inst,
905 struct loader_icd *icd)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800906{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600907 ptr_inst->total_icd_count--;
Jon Ashburn128f9422015-05-28 19:16:58 -0600908 free(icd->gpus);
Courtney Goeltzenleuchter1f157ac2015-06-14 19:57:15 -0600909 for (struct loader_device *dev = icd->logical_device_list; dev; ) {
910 struct loader_device *next_dev = dev->next;
Jon Ashburndc6fcad2015-06-10 10:06:06 -0600911 loader_destroy_logical_device(dev);
Courtney Goeltzenleuchter1f157ac2015-06-14 19:57:15 -0600912 dev = next_dev;
913 }
Jon Ashburndc6fcad2015-06-10 10:06:06 -0600914
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800915 free(icd);
916}
917
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600918static struct loader_icd * loader_icd_create(const struct loader_scanned_icds *scanned)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800919{
920 struct loader_icd *icd;
921
922 icd = malloc(sizeof(*icd));
923 if (!icd)
924 return NULL;
925
Courtney Goeltzenleuchter55001bb2014-10-28 10:29:27 -0600926 memset(icd, 0, sizeof(*icd));
927
Jon Ashburn46d1f582015-01-28 11:01:35 -0700928 icd->scanned_icds = scanned;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800929
930 return icd;
931}
932
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600933static struct loader_icd *loader_icd_add(
934 struct loader_instance *ptr_inst,
935 const struct loader_scanned_icds *scanned)
Chia-I Wu13a61a52014-08-04 11:18:20 +0800936{
937 struct loader_icd *icd;
938
Jon Ashburn46d1f582015-01-28 11:01:35 -0700939 icd = loader_icd_create(scanned);
Chia-I Wu13a61a52014-08-04 11:18:20 +0800940 if (!icd)
941 return NULL;
942
Chia-I Wu13a61a52014-08-04 11:18:20 +0800943 /* prepend to the list */
Jon Ashburn46888392015-01-29 15:45:51 -0700944 icd->next = ptr_inst->icds;
945 ptr_inst->icds = icd;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600946 ptr_inst->total_icd_count++;
Chia-I Wu13a61a52014-08-04 11:18:20 +0800947
948 return icd;
949}
950
Jon Ashburn46d1f582015-01-28 11:01:35 -0700951static void loader_scanned_icd_add(const char *filename)
952{
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700953 loader_platform_dl_handle handle;
Tony Barbour1d2cd3f2015-07-03 10:33:54 -0600954 PFN_vkCreateInstance fp_create_inst;
955 PFN_vkGetGlobalExtensionProperties fp_get_global_ext_props;
956 PFN_vkGetPhysicalDeviceExtensionProperties fp_get_device_ext_props;
957 PFN_vkGetDeviceProcAddr fp_get_proc_addr;
Jon Ashburn46d1f582015-01-28 11:01:35 -0700958 struct loader_scanned_icds *new_node;
959
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700960 // Used to call: dlopen(filename, RTLD_LAZY);
961 handle = loader_platform_open_library(filename);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700962 if (!handle) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600963 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_open_library_error(filename));
Jon Ashburn46d1f582015-01-28 11:01:35 -0700964 return;
965 }
966
967#define LOOKUP(func_ptr, func) do { \
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600968 func_ptr = (PFN_vk ##func) loader_platform_get_proc_address(handle, "vk" #func); \
Jon Ashburn46d1f582015-01-28 11:01:35 -0700969 if (!func_ptr) { \
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600970 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
Jon Ashburn46d1f582015-01-28 11:01:35 -0700971 return; \
972 } \
973} while (0)
974
Jon Ashburn46888392015-01-29 15:45:51 -0700975 LOOKUP(fp_create_inst, CreateInstance);
Tony Barbour59a47322015-06-24 16:06:58 -0600976 LOOKUP(fp_get_global_ext_props, GetGlobalExtensionProperties);
Tony Barbour59a47322015-06-24 16:06:58 -0600977 LOOKUP(fp_get_device_ext_props, GetPhysicalDeviceExtensionProperties);
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600978 LOOKUP(fp_get_proc_addr, GetDeviceProcAddr);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700979#undef LOOKUP
980
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600981 new_node = (struct loader_scanned_icds *) malloc(sizeof(struct loader_scanned_icds)
982 + strlen(filename) + 1);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700983 if (!new_node) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600984 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
Jon Ashburn46d1f582015-01-28 11:01:35 -0700985 return;
986 }
987
988 new_node->handle = handle;
Jon Ashburn46888392015-01-29 15:45:51 -0700989 new_node->CreateInstance = fp_create_inst;
Tony Barbour59a47322015-06-24 16:06:58 -0600990 new_node->GetGlobalExtensionProperties = fp_get_global_ext_props;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600991 loader_init_ext_list(&new_node->global_extension_list);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600992 loader_init_ext_list(&new_node->device_extension_list);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700993 new_node->next = loader.scanned_icd_list;
Jon Ashburn46d1f582015-01-28 11:01:35 -0700994
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600995 new_node->lib_name = (char *) (new_node + 1);
996 if (!new_node->lib_name) {
997 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
998 return;
999 }
1000 strcpy(new_node->lib_name, filename);
1001
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001002 loader.scanned_icd_list = new_node;
1003
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001004 loader_add_global_extensions(
Tony Barbour59a47322015-06-24 16:06:58 -06001005 (PFN_vkGetGlobalExtensionProperties) fp_get_global_ext_props,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001006 new_node->lib_name,
Jon Ashburn953bb3c2015-06-10 16:11:42 -06001007 handle,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001008 VK_EXTENSION_ORIGIN_ICD,
1009 &new_node->global_extension_list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001010}
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001011
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001012static struct loader_extension_list *loader_global_extensions(const char *pLayerName)
1013{
1014 if (pLayerName == NULL || (strlen(pLayerName) == 0)) {
1015 return &loader.global_extensions;
1016 }
1017
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06001018 /* Find and return global extension list for given layer */
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001019 for (uint32_t i = 0; i < loader.scanned_layers.count; i++) {
1020 struct loader_layer_properties *work_layer = &loader.scanned_layers.list[i];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001021 if (strcmp(work_layer->info.layerName, pLayerName) == 0) {
1022 return &work_layer->instance_extension_list;
1023 }
1024 }
1025
1026 return NULL;
1027}
1028
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001029static struct loader_layer_list *loader_scanned_layers()
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001030{
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001031 return &loader.scanned_layers;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001032}
1033
1034static void loader_physical_device_layers(
1035 struct loader_icd *icd,
1036 uint32_t *count,
1037 struct loader_layer_list **list)
1038{
1039 *count = icd->layer_properties_cache.count;
1040 *list = &icd->layer_properties_cache;
1041}
1042
1043static void loader_physical_device_extensions(
1044 struct loader_icd *icd,
1045 uint32_t gpu_idx,
1046 const char *layer_name,
1047 uint32_t *count,
1048 struct loader_extension_list **list)
1049{
1050 if (layer_name == NULL || (strlen(layer_name) == 0)) {
1051 *count = icd->device_extension_cache[gpu_idx].count;
1052 *list = &icd->device_extension_cache[gpu_idx];
1053 return;
1054 }
1055 for (uint32_t i = 0; i < icd->layer_properties_cache.count; i++) {
1056 if (strcmp(layer_name, icd->layer_properties_cache.list[i].info.layerName) == 0) {
1057 *count = icd->layer_properties_cache.list[i].device_extension_list.count;
1058 *list = &icd->layer_properties_cache.list[i].device_extension_list;
Courtney Goeltzenleuchtercc44f2a2015-07-10 10:11:50 -06001059 break;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001060 }
1061 }
1062}
1063
Jon Ashburn3da71f22015-05-14 12:43:38 -06001064static void loader_icd_init_entrys(struct loader_icd *icd,
1065 struct loader_scanned_icds *scanned_icds)
1066{
1067 /* initialize entrypoint function pointers */
1068
1069 #define LOOKUP(func) do { \
1070 icd->func = (PFN_vk ##func) loader_platform_get_proc_address(scanned_icds->handle, "vk" #func); \
1071 if (!icd->func) { \
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001072 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
Jon Ashburn3da71f22015-05-14 12:43:38 -06001073 return; \
1074 } \
1075 } while (0)
1076
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001077 /* could change this to use GetInstanceProcAddr in driver instead of dlsym */
1078 LOOKUP(GetDeviceProcAddr);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001079 LOOKUP(DestroyInstance);
1080 LOOKUP(EnumeratePhysicalDevices);
Chris Forbesbc0bb772015-06-21 22:55:02 +12001081 LOOKUP(GetPhysicalDeviceFeatures);
1082 LOOKUP(GetPhysicalDeviceFormatInfo);
1083 LOOKUP(GetPhysicalDeviceLimits);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001084 LOOKUP(CreateDevice);
Tony Barbour59a47322015-06-24 16:06:58 -06001085 LOOKUP(GetPhysicalDeviceProperties);
1086 LOOKUP(GetPhysicalDeviceMemoryProperties);
1087 LOOKUP(GetPhysicalDevicePerformance);
1088 LOOKUP(GetPhysicalDeviceQueueCount);
1089 LOOKUP(GetPhysicalDeviceQueueProperties);
1090 LOOKUP(GetPhysicalDeviceExtensionProperties);
Mark Lobodzinski16e8bef2015-07-03 15:58:09 -06001091 LOOKUP(GetPhysicalDeviceSparseImageFormatProperties);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001092 LOOKUP(DbgCreateMsgCallback);
1093 LOOKUP(DbgDestroyMsgCallback);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001094#undef LOOKUP
1095
1096 return;
1097}
1098
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001099static void loader_debug_init(void)
1100{
1101 const char *env;
1102
1103 if (g_loader_debug > 0)
1104 return;
1105
1106 g_loader_debug = 0;
1107
1108 /* parse comma-separated debug options */
1109 env = getenv("LOADER_DEBUG");
1110 while (env) {
1111 const char *p = strchr(env, ',');
1112 size_t len;
1113
1114 if (p)
1115 len = p - env;
1116 else
1117 len = strlen(env);
1118
1119 if (len > 0) {
1120 if (strncmp(env, "warn", len) == 0) {
1121 g_loader_debug |= LOADER_WARN_BIT;
1122 g_loader_log_msgs |= VK_DBG_REPORT_WARN_BIT;
1123 } else if (strncmp(env, "info", len) == 0) {
1124 g_loader_debug |= LOADER_INFO_BIT;
1125 g_loader_log_msgs |= VK_DBG_REPORT_INFO_BIT;
1126 } else if (strncmp(env, "perf", len) == 0) {
1127 g_loader_debug |= LOADER_PERF_BIT;
1128 g_loader_log_msgs |= VK_DBG_REPORT_PERF_WARN_BIT;
1129 } else if (strncmp(env, "error", len) == 0) {
1130 g_loader_debug |= LOADER_ERROR_BIT;
1131 g_loader_log_msgs |= VK_DBG_REPORT_ERROR_BIT;
1132 } else if (strncmp(env, "debug", len) == 0) {
1133 g_loader_debug |= LOADER_DEBUG_BIT;
1134 g_loader_log_msgs |= VK_DBG_REPORT_DEBUG_BIT;
1135 }
1136 }
1137
1138 if (!p)
1139 break;
1140
1141 env = p + 1;
1142 }
1143}
1144
Jon Ashburn2077e382015-06-29 11:25:34 -06001145struct loader_manifest_files {
1146 uint32_t count;
1147 char **filename_list;
1148};
1149
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001150/**
Jon Ashburn2077e382015-06-29 11:25:34 -06001151 * Get next file or dirname given a string list or registry key path
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001152 *
1153 * \returns
Jon Ashburn2077e382015-06-29 11:25:34 -06001154 * A pointer to first char in the next path.
1155 * The next path (or NULL) in the list is returned in next_path.
1156 * Note: input string is modified in some cases. PASS IN A COPY!
1157 */
Jon Ashburn2077e382015-06-29 11:25:34 -06001158static char *loader_get_next_path(char *path)
1159{
1160 uint32_t len;
1161 char *next;
1162
1163 if (path == NULL)
1164 return NULL;
1165 next = strchr(path, PATH_SEPERATOR);
1166 if (next == NULL) {
1167 len = (uint32_t) strlen(path);
1168 next = path + len;
1169 }
1170 else {
1171 *next = '\0';
1172 next++;
1173 }
1174
1175 return next;
1176}
1177
1178/**
Jon Ashburn15315172015-07-07 15:06:25 -06001179 * Given a path which is absolute or relative. Expand the path if relative otherwise
1180 * leave the path unmodified if absolute. The path which is relative from is
1181 * given in rel_base and should include trailing directory seperator '/'
1182 *
1183 * \returns
1184 * A string in out_fullpath of the full absolute path
1185 * Side effect is that dir string maybe modified.
1186 */
1187static void loader_expand_path(const char *path,
1188 const char *rel_base,
1189 size_t out_size,
1190 char *out_fullpath)
1191{
1192 if (loader_platform_is_path_absolute(path)) {
1193 strncpy(out_fullpath, path, out_size);
1194 out_fullpath[out_size - 1] = '\0';
1195 }
1196 else {
1197 // convert relative to absolute path based on rel_base
1198 size_t len = strlen(path);
1199 strncpy(out_fullpath, rel_base, out_size);
1200 out_fullpath[out_size - 1] = '\0';
1201 assert(out_size >= strlen(out_fullpath) + len + 1);
1202 strncat(out_fullpath, path, len);
1203 }
1204}
1205
1206/**
Jon Ashburn2077e382015-06-29 11:25:34 -06001207 * Given a filename (file) and a list of paths (dir), try to find an existing
1208 * file in the paths. If filename already is a path then no
1209 * searching in the given paths.
1210 *
1211 * \returns
1212 * A string in out_fullpath of either the full path or file.
1213 * Side effect is that dir string maybe modified.
1214 */
1215static void loader_get_fullpath(const char *file,
1216 char *dir,
1217 size_t out_size,
1218 char *out_fullpath)
1219{
1220 char *next_dir;
1221 if (strchr(file,DIRECTORY_SYMBOL) == NULL) {
1222 //find file exists with prepending given path
1223 while (*dir) {
1224 next_dir = loader_get_next_path(dir);
1225 snprintf(out_fullpath, out_size, "%s%c%s",
1226 dir, DIRECTORY_SYMBOL, file);
1227 if (loader_platform_file_exists(out_fullpath)) {
1228 return;
1229 }
1230 dir = next_dir;
1231 }
1232 }
1233 snprintf(out_fullpath, out_size, "%s", file);
1234}
1235
1236/**
1237 * Read a JSON file into a buffer.
1238 *
1239 * \returns
1240 * A pointer to a cJSON object representing the JSON parse tree.
1241 * This returned buffer should be freed by caller.
1242 */
1243static cJSON *loader_get_json(const char *filename)
1244{
1245 FILE *file;
1246 char *json_buf;
1247 cJSON *json;
1248 uint64_t len;
1249 file = fopen(filename,"rb");
1250 fseek(file, 0, SEEK_END);
1251 len = ftell(file);
1252 fseek(file, 0, SEEK_SET);
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -06001253 json_buf = (char*) loader_stack_alloc(len+1);
Jon Ashburn2077e382015-06-29 11:25:34 -06001254 if (json_buf == NULL) {
1255 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get JSON file");
1256 fclose(file);
1257 return NULL;
1258 }
1259 if (fread(json_buf, sizeof(char), len, file) != len) {
1260 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "fread failed can't get JSON file");
1261 fclose(file);
1262 return NULL;
1263 }
1264 fclose(file);
1265 json_buf[len] = '\0';
1266
1267 //parse text from file
1268 json = cJSON_Parse(json_buf);
1269 if (json == NULL)
1270 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Can't parse JSON file %s", filename);
1271 return json;
1272}
1273
1274/**
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001275 * Given a cJSON struct (json) of the top level JSON object from layer manifest
1276 * file, add entry to the layer_list.
1277 * Fill out the layer_properties in this list entry from the input cHJSON object.
1278 *
1279 * \returns
1280 * void
1281 * layer_list has a new entry and initialized accordingly.
1282 * If the json input object does not have all the required fields no entry
1283 * is added to the list.
1284 */
1285static void loader_add_layer_properties(struct loader_layer_list *layer_list,
1286 cJSON *json,
1287 bool is_implicit,
1288 char *filename)
1289{
1290 /* Fields in layer manifest file that are required:
1291 * (required) “file_format_version”
1292 * following are required in the "layer" object:
1293 * (required) "name"
1294 * (required) "type"
1295 * (required) “library_path”
1296 * (required) “abi_versions”
1297 * (required) “implementation_version”
1298 * (required) “description”
1299 * (required for implicit layers) “disable_environment”
1300 *
1301 * First get all required items and if any missing abort
1302 */
1303
1304 cJSON *item, *layer_node, *ext_item;
1305 char *temp;
1306 char *name, *type, *library_path, *abi_versions;
1307 char *implementation_version, *description;
1308 cJSON *disable_environment;
1309 int i;
1310 struct loader_extension_property ext_prop;
1311 item = cJSON_GetObjectItem(json, "file_format_version");
1312 if (item == NULL) {
1313 return;
1314 }
1315 char *file_vers = cJSON_PrintUnformatted(item);
1316 loader_log(VK_DBG_REPORT_INFO_BIT, 0, "Found manifest file %s, version %s",
1317 filename, file_vers);
1318 if (strcmp(file_vers, "\"0.9.0\"") != 0)
1319 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unexpected manifest file version (expected 1.0.0), may cause errors");
1320 free(file_vers);
1321
1322 //TODO handle multiple layer nodes in the file
1323 //TODO handle scanned libraries not one per layer property
1324 layer_node = cJSON_GetObjectItem(json, "layer");
1325 if (layer_node == NULL) {
1326 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"layer\" object in manifest JSON file, skipping");
1327 return;
1328 }
1329#define GET_JSON_OBJECT(node, var) { \
1330 var = cJSON_GetObjectItem(node, #var); \
1331 if (var == NULL) \
1332 return; \
1333 }
1334#define GET_JSON_ITEM(node, var) { \
1335 item = cJSON_GetObjectItem(node, #var); \
1336 if (item == NULL) \
1337 return; \
1338 temp = cJSON_Print(item); \
1339 temp[strlen(temp) - 1] = '\0'; \
1340 var = malloc(strlen(temp) + 1); \
1341 strcpy(var, &temp[1]); \
1342 free(temp); \
1343 }
1344 GET_JSON_ITEM(layer_node, name)
1345 GET_JSON_ITEM(layer_node, type)
1346 GET_JSON_ITEM(layer_node, library_path)
1347 GET_JSON_ITEM(layer_node, abi_versions)
1348 GET_JSON_ITEM(layer_node, implementation_version)
1349 GET_JSON_ITEM(layer_node, description)
1350 if (is_implicit) {
1351 GET_JSON_OBJECT(layer_node, disable_environment)
1352 }
1353#undef GET_JSON_ITEM
1354#undef GET_JSON_OBJECT
1355
1356 // add list entry
1357 assert((layer_list->count + 1) * sizeof(struct loader_layer_properties) <= layer_list->capacity);
1358 struct loader_layer_properties *props = &(layer_list->list[layer_list->count]);
Jon Ashburn15315172015-07-07 15:06:25 -06001359 strncpy(props->info.layerName, name, sizeof(props->info.layerName));
1360 props->info.layerName[sizeof(props->info.layerName) - 1] = '\0';
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001361 free(name);
Jon Ashburn15315172015-07-07 15:06:25 -06001362
Jon Ashburnbd332cc2015-07-07 10:27:45 -06001363 if (!strcmp(type, "DEVICE"))
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001364 props->type = (is_implicit) ? VK_LAYER_TYPE_DEVICE_IMPLICIT : VK_LAYER_TYPE_DEVICE_EXPLICIT;
Jon Ashburnbd332cc2015-07-07 10:27:45 -06001365 if (!strcmp(type, "INSTANCE"))
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001366 props->type = (is_implicit) ? VK_LAYER_TYPE_INSTANCE_IMPLICIT : VK_LAYER_TYPE_INSTANCE_EXPLICIT;
Jon Ashburnbd332cc2015-07-07 10:27:45 -06001367 if (!strcmp(type, "GLOBAL"))
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001368 props->type = (is_implicit) ? VK_LAYER_TYPE_GLOBAL_IMPLICIT : VK_LAYER_TYPE_GLOBAL_EXPLICIT;
1369 free(type);
Jon Ashburn15315172015-07-07 15:06:25 -06001370
1371 char *fullpath = malloc(2048);
1372 char *rel_base;
1373 if (strchr(library_path, DIRECTORY_SYMBOL) == NULL) {
1374 // a filename which is assumed in the system directory
Jon Ashburn5e1f63d2015-07-09 14:06:55 -06001375 char *def_path = loader_stack_alloc(strlen(DEFAULT_VK_LAYERS_PATH) + 1);
1376 strcpy(def_path, DEFAULT_VK_LAYERS_PATH);
1377 loader_get_fullpath(library_path, def_path, 2048, fullpath);
Jon Ashburn15315172015-07-07 15:06:25 -06001378 }
1379 else {
1380 // a relative or absolute path
1381 char *name_copy = loader_stack_alloc(strlen(filename) + 2);
1382 size_t len;
1383 strcpy(name_copy, filename);
1384 rel_base = loader_platform_dirname(name_copy);
1385 len = strlen(rel_base);
1386 rel_base[len] = DIRECTORY_SYMBOL;
1387 rel_base[len + 1] = '\0';
1388 loader_expand_path(library_path, rel_base, 2048, fullpath);
1389 }
1390 props->lib_info.lib_name = fullpath;
1391 free(library_path);
1392 //TODO merge the info with the versions and convert string to int
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001393 props->abi_version = abi_versions;
1394 props->impl_version = implementation_version;
Jon Ashburn15315172015-07-07 15:06:25 -06001395 strncpy(props->info.description, description, sizeof(props->info.description));
1396 props->info.description[sizeof(props->info.description) - 1] = '\0';
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001397 free(description);
1398 if (is_implicit) {
1399 props->disable_env_var.name = disable_environment->child->string;
1400 props->disable_env_var.value = disable_environment->child->valuestring;
1401 }
1402 layer_list->count++;
1403
1404 /**
1405 * Now get all optional items and objects and put in list:
1406 * functions
1407 * instance_extensions
1408 * device_extensions
1409 * enable_environment (implicit layers only)
1410 */
1411#define GET_JSON_OBJECT(node, var) { \
1412 var = cJSON_GetObjectItem(node, #var); \
1413 }
1414#define GET_JSON_ITEM(node, var) { \
1415 item = cJSON_GetObjectItem(node, #var); \
1416 if (item != NULL) \
1417 temp = cJSON_Print(item); \
1418 temp[strlen(temp) - 1] = '\0'; \
1419 var = malloc(strlen(temp) + 1); \
1420 strcpy(var, &temp[1]); \
1421 free(temp); \
1422 }
1423
1424 cJSON *instance_extensions, *device_extensions, *functions, *enable_environment;
1425 char *vkGetInstanceProcAddr, *vkGetDeviceProcAddr, *version;
1426 GET_JSON_OBJECT(layer_node, functions)
1427 if (functions != NULL) {
1428 GET_JSON_ITEM(functions, vkGetInstanceProcAddr)
1429 GET_JSON_ITEM(functions, vkGetDeviceProcAddr)
1430 props->functions.str_gipa = vkGetInstanceProcAddr;
1431 props->functions.str_gdpa = vkGetDeviceProcAddr;
1432 }
1433 GET_JSON_OBJECT(layer_node, instance_extensions)
1434 if (instance_extensions != NULL) {
1435 int count = cJSON_GetArraySize(instance_extensions);
1436 for (i = 0; i < count; i++) {
1437 ext_item = cJSON_GetArrayItem(instance_extensions, i);
1438 GET_JSON_ITEM(ext_item, name)
1439 GET_JSON_ITEM(ext_item, version)
1440 ext_prop.origin = VK_EXTENSION_ORIGIN_LAYER;
1441 ext_prop.lib_name = library_path;
1442 strcpy(ext_prop.info.extName, name);
1443 //TODO convert from string to int ext_prop.info.version = version;
1444 loader_add_to_ext_list(&props->instance_extension_list, 1, &ext_prop);
1445 }
1446 }
1447 GET_JSON_OBJECT(layer_node, device_extensions)
1448 if (device_extensions != NULL) {
1449 int count = cJSON_GetArraySize(device_extensions);
1450 for (i = 0; i < count; i++) {
1451 ext_item = cJSON_GetArrayItem(device_extensions, i);
1452 GET_JSON_ITEM(ext_item, name);
1453 GET_JSON_ITEM(ext_item, version);
1454 ext_prop.origin = VK_EXTENSION_ORIGIN_LAYER;
1455 ext_prop.lib_name = library_path;
1456 strcpy(ext_prop.info.extName, name);
1457 //TODO convert from string to int ext_prop.info.version = version;
1458 loader_add_to_ext_list(&props->device_extension_list, 1, &ext_prop);
1459 }
1460 }
1461 if (is_implicit) {
1462 GET_JSON_OBJECT(layer_node, enable_environment)
1463 props->enable_env_var.name = enable_environment->child->string;
1464 props->enable_env_var.value = enable_environment->child->valuestring;
1465 }
1466#undef GET_JSON_ITEM
1467#undef GET_JSON_OBJECT
1468
1469}
1470
1471/**
Jon Ashburn2077e382015-06-29 11:25:34 -06001472 * Find the Vulkan library manifest files.
1473 *
1474 * This function scans the location or env_override directories/files
1475 * for a list of JSON manifest files. If env_override is non-NULL
1476 * and has a valid value. Then the location is ignored. Otherwise
1477 * location is used to look for manifest files. The location
1478 * is interpreted as Registry path on Windows and a directory path(s)
1479 * on Linux.
1480 *
1481 * \returns
1482 * A string list of manifest files to be opened in out_files param.
1483 * List has a pointer to string for each manifest filename.
1484 * When done using the list in out_files, pointers should be freed.
Jon Ashburnffad94d2015-06-30 14:46:22 -07001485 * Location or override string lists can be either files or directories as follows:
1486 * | location | override
1487 * --------------------------------
1488 * Win ICD | files | files
1489 * Win Layer | files | dirs
1490 * Linux ICD | dirs | files
1491 * Linux Layer| dirs | dirs
Jon Ashburn2077e382015-06-29 11:25:34 -06001492 */
1493static void loader_get_manifest_files(const char *env_override,
Jon Ashburnffad94d2015-06-30 14:46:22 -07001494 bool is_layer,
1495 const char *location,
1496 struct loader_manifest_files *out_files)
Jon Ashburn2077e382015-06-29 11:25:34 -06001497{
1498 char *override = NULL;
1499 char *loc;
1500 char *file, *next_file, *name;
1501 size_t alloced_count = 64;
1502 char full_path[2048];
1503 DIR *sysdir = NULL;
Jon Ashburnffad94d2015-06-30 14:46:22 -07001504 bool list_is_dirs = false;
Jon Ashburn2077e382015-06-29 11:25:34 -06001505 struct dirent *dent;
1506
1507 out_files->count = 0;
1508 out_files->filename_list = NULL;
1509
Jon Ashburn2077e382015-06-29 11:25:34 -06001510 if (env_override != NULL && (override = getenv(env_override))) {
1511#if defined(__linux__)
1512 if (geteuid() != getuid()) {
Jon Ashburnffad94d2015-06-30 14:46:22 -07001513 /* Don't allow setuid apps to use the env var: */
Jon Ashburn2077e382015-06-29 11:25:34 -06001514 override = NULL;
1515 }
1516#endif
1517 }
1518
1519 if (location == NULL) {
1520 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
Jon Ashburnffad94d2015-06-30 14:46:22 -07001521 "Can't get manifest files with NULL location, env_override=%s",
1522 env_override);
Jon Ashburn2077e382015-06-29 11:25:34 -06001523 return;
1524 }
1525
Jon Ashburnffad94d2015-06-30 14:46:22 -07001526#if defined(__linux__)
1527 list_is_dirs = (override == NULL || is_layer) ? true : false;
1528#else //WIN32
1529 list_is_dirs = (is_layer && override != NULL) ? true : false;
1530#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06001531 // Make a copy of the input we are using so it is not modified
Jon Ashburnffad94d2015-06-30 14:46:22 -07001532 // Also handle getting the location(s) from registry on Windows
1533 if (override == NULL) {
1534#if defined (_WIN32)
1535 loc = loader_get_registry_files(location);
1536 if (loc == NULL) {
1537 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Registry lookup failed can't get manifest files");
1538 return;
1539 }
1540#else
Jon Ashburn2077e382015-06-29 11:25:34 -06001541 loc = alloca(strlen(location) + 1);
Jon Ashburnffad94d2015-06-30 14:46:22 -07001542 if (loc == NULL) {
1543 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1544 return;
1545 }
1546 strcpy(loc, location);
1547#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06001548 }
Jon Ashburnffad94d2015-06-30 14:46:22 -07001549 else {
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -06001550 loc = loader_stack_alloc(strlen(override) + 1);
Jon Ashburnffad94d2015-06-30 14:46:22 -07001551 if (loc == NULL) {
1552 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1553 return;
1554 }
1555 strcpy(loc, override);
1556 }
Jon Ashburn2077e382015-06-29 11:25:34 -06001557
1558 file = loc;
1559 while (*file) {
1560 next_file = loader_get_next_path(file);
Jon Ashburnffad94d2015-06-30 14:46:22 -07001561 if (list_is_dirs) {
Jon Ashburn2077e382015-06-29 11:25:34 -06001562 sysdir = opendir(file);
1563 name = NULL;
1564 if (sysdir) {
1565 dent = readdir(sysdir);
1566 if (dent == NULL)
1567 break;
1568 name = &(dent->d_name[0]);
1569 loader_get_fullpath(name, file, sizeof(full_path), full_path);
1570 name = full_path;
1571 }
1572 }
1573 else {
Jon Ashburnffad94d2015-06-30 14:46:22 -07001574#if defined(__linux__)
1575 // only Linux has relative paths
Jon Ashburn2077e382015-06-29 11:25:34 -06001576 char *dir;
1577 // make a copy of location so it isn't modified
1578 dir = alloca(strlen(location) + 1);
1579 if (dir == NULL) {
1580 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1581 return;
1582 }
1583 strcpy(dir, location);
1584
1585 loader_get_fullpath(file, dir, sizeof(full_path), full_path);
1586
1587 name = full_path;
Jon Ashburnffad94d2015-06-30 14:46:22 -07001588#else // WIN32
1589 name = file;
1590#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06001591 }
1592 while (name) {
1593 /* Look for files ending with ".json" suffix */
1594 uint32_t nlen = (uint32_t) strlen(name);
1595 const char *suf = name + nlen - 5;
1596 if ((nlen > 5) && !strncmp(suf, ".json", 5)) {
1597 if (out_files->count == 0) {
1598 out_files->filename_list = malloc(alloced_count * sizeof(char *));
1599 }
1600 else if (out_files->count == alloced_count) {
1601 out_files->filename_list = realloc(out_files->filename_list,
1602 alloced_count * sizeof(char *) * 2);
1603 alloced_count *= 2;
1604 }
1605 if (out_files->filename_list == NULL) {
1606 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't alloc manifest file list");
1607 return;
1608 }
1609 out_files->filename_list[out_files->count] = malloc(strlen(name) + 1);
1610 if (out_files->filename_list[out_files->count] == NULL) {
1611 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1612 return;
1613 }
1614 strcpy(out_files->filename_list[out_files->count], name);
1615 out_files->count++;
Jon Ashburnf70f3612015-07-02 10:08:47 -06001616 } else if (!list_is_dirs) {
1617 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 -06001618 }
Jon Ashburnffad94d2015-06-30 14:46:22 -07001619 if (list_is_dirs) {
Jon Ashburn2077e382015-06-29 11:25:34 -06001620 dent = readdir(sysdir);
1621 if (dent == NULL)
1622 break;
1623 name = &(dent->d_name[0]);
1624 loader_get_fullpath(name, file, sizeof(full_path), full_path);
1625 name = full_path;
1626 }
1627 else {
1628 break;
1629 }
1630 }
1631 if (sysdir)
1632 closedir(sysdir);
1633 file = next_file;
1634 }
1635 return;
1636}
1637
1638/**
1639 * Try to find the Vulkan ICD driver(s).
1640 *
1641 * This function scans the default system loader path(s) or path
1642 * specified by the \c VK_ICD_FILENAMES environment variable in
1643 * order to find loadable VK ICDs manifest files. From these
1644 * manifest files it finds the ICD libraries.
1645 *
1646 * \returns
Jon Ashburn3a37aee2015-06-30 16:44:28 -06001647 * void
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001648 */
Jon Ashburn27cd5842015-05-12 17:26:48 -06001649void loader_icd_scan(void)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001650{
Jon Ashburn2077e382015-06-29 11:25:34 -06001651 char *file_str;
1652 struct loader_manifest_files manifest_files;
1653
Jon Ashburn6301a0f2015-05-29 13:15:39 -06001654
1655 // convenient place to initialize a mutex
1656 loader_platform_thread_create_mutex(&loader_lock);
1657
Jon Ashburn2077e382015-06-29 11:25:34 -06001658 // convenient place to initialize logging
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001659 loader_debug_init();
1660
Jon Ashburn2077e382015-06-29 11:25:34 -06001661 // Get a list of manifest files for ICDs
1662 loader_get_manifest_files("VK_ICD_FILENAMES", false, DEFAULT_VK_DRIVERS_INFO,
1663 &manifest_files);
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001664 if (manifest_files.count == 0)
1665 return;
Jon Ashburn2077e382015-06-29 11:25:34 -06001666 for (uint32_t i = 0; i < manifest_files.count; i++) {
1667 file_str = manifest_files.filename_list[i];
1668 if (file_str == NULL)
1669 continue;
1670
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001671 cJSON *json;
Jon Ashburn2077e382015-06-29 11:25:34 -06001672 json = loader_get_json(file_str);
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001673 cJSON *item;
1674 item = cJSON_GetObjectItem(json, "file_format_version");
1675 if (item == NULL)
1676 return;
1677 char *file_vers = cJSON_Print(item);
1678 loader_log(VK_DBG_REPORT_INFO_BIT, 0, "Found manifest file %s, version %s",
1679 file_str, file_vers);
1680 if (strcmp(file_vers, "\"1.0.0\"") != 0)
1681 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unexpected manifest file version (expected 1.0.0), may cause errors");
1682 free(file_vers);
1683 item = cJSON_GetObjectItem(json, "ICD");
1684 if (item != NULL) {
1685 item = cJSON_GetObjectItem(item, "library_path");
1686 if (item != NULL) {
1687 char *icd_filename = cJSON_PrintUnformatted(item);
Jon Ashburn2077e382015-06-29 11:25:34 -06001688 char *icd_file = icd_filename;
1689 if (icd_filename != NULL) {
Jon Ashburn2077e382015-06-29 11:25:34 -06001690 char def_dir[] = DEFAULT_VK_DRIVERS_PATH;
1691 char *dir = def_dir;
1692 // strip off extra quotes
1693 if (icd_filename[strlen(icd_filename) - 1] == '"')
1694 icd_filename[strlen(icd_filename) - 1] = '\0';
1695 if (icd_filename[0] == '"')
1696 icd_filename++;
Jon Ashburnffad94d2015-06-30 14:46:22 -07001697#if defined(__linux__)
1698 char full_path[2048];
Jon Ashburn2077e382015-06-29 11:25:34 -06001699 loader_get_fullpath(icd_filename, dir, sizeof(full_path), full_path);
1700 loader_scanned_icd_add(full_path);
Jon Ashburnffad94d2015-06-30 14:46:22 -07001701#else // WIN32
1702 loader_scanned_icd_add(icd_filename);
1703#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06001704 free(icd_file);
1705 }
1706 }
1707 else
1708 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"library_path\" in ICD JSON file %s, skipping", file_str);
1709 }
1710 else
1711 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"ICD\" object in ICD JSON file %s, skipping", file_str);
1712
1713 free(file_str);
1714 cJSON_Delete(json);
1715 }
1716 free(manifest_files.filename_list);
1717
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001718}
1719
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001720
Jon Ashburn5ef20602015-07-02 09:40:15 -06001721void loader_layer_scan(void)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001722{
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001723 char *file_str;
1724 struct loader_manifest_files manifest_files;
1725 cJSON *json;
1726 uint32_t i;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001727
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001728 // Get a list of manifest files for layers
1729 loader_get_manifest_files(LAYERS_PATH_ENV, true, DEFAULT_VK_LAYERS_INFO,
1730 &manifest_files);
1731 if (manifest_files.count == 0)
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -07001732 return;
Jon Ashburn90c6a0e2015-06-04 15:30:58 -06001733
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001734#if 0
1735 /**
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06001736 * We need a list of the layer libraries, not just a list of
1737 * the layer properties (a layer library could expose more than
1738 * one layer property). This list of scanned layers would be
1739 * used to check for global and physicaldevice layer properties.
1740 */
1741 if (!loader_init_layer_library_list(&loader.scanned_layer_libraries)) {
1742 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1743 "Malloc for layer list failed: %s line: %d", __FILE__, __LINE__);
1744 return;
Jon Ashburn5ef20602015-07-02 09:40:15 -06001745 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001746#endif
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001747
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001748 // TODO use global_layer add and delete functions instead
1749 if (loader.scanned_layers.capacity == 0) {
1750 loader.scanned_layers.list = malloc(sizeof(struct loader_layer_properties) * 64);
1751 if (loader.scanned_layers.list == NULL) {
1752 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can'add any layer properties to list");
1753 return;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001754 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001755 memset(loader.scanned_layers.list, 0, sizeof(struct loader_layer_properties) * 64);
1756 loader.scanned_layers.capacity = sizeof(struct loader_layer_properties) * 64;
1757 }
1758 else {
1759 /* cleanup any previously scanned libraries */
1760 //TODO make sure everything is cleaned up properly
1761 for (i = 0; i < loader.scanned_layers.count; i++) {
1762 if (loader.scanned_layers.list[i].lib_info.lib_name != NULL)
1763 free(loader.scanned_layers.list[i].lib_info.lib_name);
1764 loader_destroy_ext_list(&loader.scanned_layers.list[i].instance_extension_list);
1765 loader_destroy_ext_list(&loader.scanned_layers.list[i].device_extension_list);
1766 loader.scanned_layers.list[i].lib_info.lib_name = NULL;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001767 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001768 loader.scanned_layers.count = 0;
1769 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001770
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001771 for (i = 0; i < manifest_files.count; i++) {
1772 file_str = manifest_files.filename_list[i];
1773 if (file_str == NULL)
1774 continue;
Courtney Goeltzenleuchtera9e4af42015-06-01 14:49:17 -06001775
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001776 // parse file into JSON struct
1777 json = loader_get_json(file_str);
1778 if (!json) {
1779 continue;
1780 }
1781 // ensure enough room to add an entry
1782 if ((loader.scanned_layers.count + 1) * sizeof (struct loader_layer_properties)
1783 > loader.scanned_layers.capacity) {
1784 loader.scanned_layers.list = realloc(loader.scanned_layers.list,
1785 loader.scanned_layers.capacity * 2);
1786 if (loader.scanned_layers.list == NULL) {
1787 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1788 "realloc failed for scanned layers");
1789 break;
1790 }
1791 loader.scanned_layers.capacity *= 2;
1792 }
1793 //TODO pass in implicit versus explicit bool
1794 loader_add_layer_properties(&loader.scanned_layers, json, false, file_str);
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06001795
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001796 free(file_str);
1797 cJSON_Delete(json);
1798 }
1799 free(manifest_files.filename_list);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001800
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001801}
1802
Jon Ashburn27cd5842015-05-12 17:26:48 -06001803static void* VKAPI loader_gpa_instance_internal(VkInstance inst, const char * pName)
1804{
1805 // inst is not wrapped
1806 if (inst == VK_NULL_HANDLE) {
1807 return NULL;
1808 }
1809 VkLayerInstanceDispatchTable* disp_table = * (VkLayerInstanceDispatchTable **) inst;
1810 void *addr;
1811
Jon Ashburn8fd08252015-05-28 16:25:02 -06001812 if (!strcmp(pName, "vkGetInstanceProcAddr"))
1813 return (void *) loader_gpa_instance_internal;
1814
Jon Ashburn27cd5842015-05-12 17:26:48 -06001815 if (disp_table == NULL)
1816 return NULL;
1817
1818 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001819 if (addr) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06001820 return addr;
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001821 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001822
1823 if (disp_table->GetInstanceProcAddr == NULL) {
1824 return NULL;
1825 }
1826 return disp_table->GetInstanceProcAddr(inst, pName);
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001827}
1828
Jon Ashburn128f9422015-05-28 19:16:58 -06001829struct loader_icd * loader_get_icd(const VkPhysicalDevice gpu, uint32_t *gpu_index)
Jon Ashburn876b1ac2014-10-17 15:09:07 -06001830{
Jon Ashburn128f9422015-05-28 19:16:58 -06001831
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;
1901 struct loader_lib_info *new_layer_lib_list, *my_lib;
1902
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
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001912 my_lib->ref_count--;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001913 if (my_lib->ref_count > 0) {
Courtney Goeltzenleuchterca8c81a2015-06-14 11:59:07 -06001914 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001915 "Decrement reference count for layer library %s", layer_prop->lib_info.lib_name);
Jon Ashburn27cd5842015-05-12 17:26:48 -06001916 return;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001917 }
Jon Ashburn19c25022015-04-14 14:14:48 -06001918
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001919 loader_platform_close_library(my_lib->lib_handle);
Courtney Goeltzenleuchterca8c81a2015-06-14 11:59:07 -06001920 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001921 "Unloading layer library %s", layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001922
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001923 /* Need to remove unused library from list */
1924 new_layer_lib_list = malloc((loader.loaded_layer_lib_count - 1) * sizeof(struct loader_lib_info));
1925 if (!new_layer_lib_list) {
1926 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1927 return;
1928 }
1929
1930 if (idx > 0) {
1931 /* Copy records before idx */
1932 memcpy(new_layer_lib_list, &loader.loaded_layer_lib_list[0],
1933 sizeof(struct loader_lib_info) * idx);
1934 }
1935 if (idx < (loader.loaded_layer_lib_count - 1)) {
1936 /* Copy records after idx */
1937 memcpy(&new_layer_lib_list[idx], &loader.loaded_layer_lib_list[idx+1],
1938 sizeof(struct loader_lib_info) * (loader.loaded_layer_lib_count - idx - 1));
1939 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001940
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001941 free(loader.loaded_layer_lib_list);
1942 loader.loaded_layer_lib_count--;
1943 loader.loaded_layer_lib_list = new_layer_lib_list;
Jon Ashburnb8358052014-11-18 09:06:04 -07001944}
1945
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001946
1947/**
1948 * Go through the search_list and find any layers which match type. If layer
1949 * type match is found in then add it to ext_list.
1950 */
1951//TODO need to handle implict layer enable env var and disable env var
Jon Ashburn0c26e712015-07-02 16:10:32 -06001952static void loader_add_layer_implicit(
1953 const enum layer_type type,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001954 struct loader_layer_list *list,
1955 struct loader_layer_list *search_list)
Jon Ashburn0c26e712015-07-02 16:10:32 -06001956{
1957 uint32_t i;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001958 for (i = 0; i < search_list->count; i++) {
1959 const struct loader_layer_properties *prop = &search_list->list[i];
Jon Ashburn0c26e712015-07-02 16:10:32 -06001960 if (prop->type & type) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001961 /* Found an layer with the same type, add to layer_list */
1962 loader_add_to_layer_list(list, 1, prop);
Jon Ashburn0c26e712015-07-02 16:10:32 -06001963 }
1964 }
1965
1966}
1967
1968/**
1969 * Get the layer name(s) from the env_name environment variable. If layer
Jon Ashburnbd332cc2015-07-07 10:27:45 -06001970 * is found in search_list then add it to layer_list. But only add it to
1971 * layer_list if type matches.
Jon Ashburn0c26e712015-07-02 16:10:32 -06001972 */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001973static void loader_add_layer_env(
Jon Ashburnbd332cc2015-07-07 10:27:45 -06001974 const enum layer_type type,
Jon Ashburneb6d5682015-07-02 14:10:53 -06001975 const char *env_name,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001976 struct loader_layer_list *layer_list,
1977 const struct loader_layer_list *search_list)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001978{
Ian Elliott4470a302015-02-17 10:33:47 -07001979 char *layerEnv;
Jon Ashburneb6d5682015-07-02 14:10:53 -06001980 char *next, *name;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001981
Jon Ashburneb6d5682015-07-02 14:10:53 -06001982 layerEnv = getenv(env_name);
Ian Elliott4470a302015-02-17 10:33:47 -07001983 if (layerEnv == NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001984 return;
Ian Elliott4470a302015-02-17 10:33:47 -07001985 }
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -06001986 name = loader_stack_alloc(strlen(layerEnv) + 1);
Jon Ashburneb6d5682015-07-02 14:10:53 -06001987 if (name == NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001988 return;
Ian Elliott4470a302015-02-17 10:33:47 -07001989 }
Jon Ashburneb6d5682015-07-02 14:10:53 -06001990 strcpy(name, layerEnv);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001991
Jon Ashburneb6d5682015-07-02 14:10:53 -06001992 while (name && *name ) {
1993 next = loader_get_next_path(name);
Jon Ashburnbd332cc2015-07-07 10:27:45 -06001994 loader_find_layer_name_add_list(name, type, search_list, layer_list);
Jon Ashburneb6d5682015-07-02 14:10:53 -06001995 name = next;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001996 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001997
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001998 return;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001999}
2000
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -06002001void loader_deactivate_instance_layers(struct loader_instance *instance)
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002002{
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002003 if (!instance->activated_layer_list.count) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002004 return;
2005 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002006
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002007 /* Create instance chain of enabled layers */
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -06002008 for (uint32_t i = 0; i < instance->activated_layer_list.count; i++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002009 struct loader_layer_properties *layer_prop = &instance->activated_layer_list.list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002010
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002011 loader_remove_layer_lib(instance, layer_prop);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002012 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002013 loader_destroy_layer_list(&instance->activated_layer_list);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002014}
2015
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002016VkResult loader_enable_instance_layers(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002017 struct loader_instance *inst,
2018 const VkInstanceCreateInfo *pCreateInfo)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002019{
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002020 VkResult err;
2021
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002022 if (inst == NULL)
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002023 return VK_ERROR_UNKNOWN;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002024
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002025 if (!loader_init_layer_list(&inst->activated_layer_list)) {
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002026 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance activated layer list");
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002027 return VK_ERROR_OUT_OF_HOST_MEMORY;
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002028 }
2029
Jon Ashburn0c26e712015-07-02 16:10:32 -06002030 /* Add any implicit layers first */
2031 loader_add_layer_implicit(
2032 VK_LAYER_TYPE_INSTANCE_IMPLICIT,
2033 &inst->activated_layer_list,
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002034 &loader.scanned_layers);
Jon Ashburn0c26e712015-07-02 16:10:32 -06002035
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002036 /* Add any layers specified via environment variable next */
Jon Ashburneb6d5682015-07-02 14:10:53 -06002037 loader_add_layer_env(
Jon Ashburnbd332cc2015-07-07 10:27:45 -06002038 VK_LAYER_TYPE_INSTANCE_EXPLICIT,
Jon Ashburneb6d5682015-07-02 14:10:53 -06002039 "VK_INSTANCE_LAYERS",
2040 &inst->activated_layer_list,
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002041 &loader.scanned_layers);
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002042
2043 /* Add layers specified by the application */
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002044 err = loader_add_layer_names_to_list(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002045 &inst->activated_layer_list,
2046 pCreateInfo->layerCount,
2047 pCreateInfo->ppEnabledLayerNames,
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002048 &loader.scanned_layers);
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002049
2050 return err;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002051}
2052
Jon Ashburn27cd5842015-05-12 17:26:48 -06002053uint32_t loader_activate_instance_layers(struct loader_instance *inst)
2054{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002055 uint32_t layer_idx;
Jon Ashburn128f9422015-05-28 19:16:58 -06002056 VkBaseLayerObject *wrappedInstance;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002057
David Pinedoa0a8a242015-06-24 15:29:18 -06002058 if (inst == NULL) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06002059 return 0;
David Pinedoa0a8a242015-06-24 15:29:18 -06002060 }
Jon Ashburn27cd5842015-05-12 17:26:48 -06002061
2062 // NOTE inst is unwrapped at this point in time
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06002063 void* baseObj = (void*) inst;
2064 void* nextObj = (void*) inst;
Jon Ashburn27cd5842015-05-12 17:26:48 -06002065 VkBaseLayerObject *nextInstObj;
2066 PFN_vkGetInstanceProcAddr nextGPA = loader_gpa_instance_internal;
2067
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002068 if (!inst->activated_layer_list.count) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06002069 return 0;
2070 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002071
Courtney Goeltzenleuchter6f460c52015-07-06 09:04:55 -06002072 wrappedInstance = loader_stack_alloc(sizeof(VkBaseLayerObject)
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002073 * inst->activated_layer_list.count);
Jon Ashburn128f9422015-05-28 19:16:58 -06002074 if (!wrappedInstance) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002075 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance objects for layer");
2076 return 0;
2077 }
2078
2079 /* Create instance chain of enabled layers */
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002080 layer_idx = inst->activated_layer_list.count - 1;
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06002081 for (int32_t i = inst->activated_layer_list.count - 1; i >= 0; i--) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002082 struct loader_layer_properties *layer_prop = &inst->activated_layer_list.list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002083 loader_platform_dl_handle lib_handle;
2084
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002085 /*
Courtney Goeltzenleuchteree3b16a2015-06-01 14:12:42 -06002086 * Note: An extension's Get*ProcAddr should not return a function pointer for
2087 * any extension entry points until the extension has been enabled.
2088 * To do this requires a different behavior from Get*ProcAddr functions implemented
2089 * in layers.
2090 * The very first call to a layer will be it's Get*ProcAddr function requesting
2091 * the layer's vkGet*ProcAddr. The layer should intialize it's internal dispatch table
2092 * with the wrapped object given (either Instance or Device) and return the layer's
2093 * Get*ProcAddr function. The layer should also use this opportunity to record the
2094 * baseObject so that it can find the correct local dispatch table on future calls.
2095 * Subsequent calls to Get*ProcAddr, CreateInstance, CreateDevice
2096 * will not use a wrapped object and must look up their local dispatch table from
2097 * the given baseObject.
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002098 */
Jon Ashburn128f9422015-05-28 19:16:58 -06002099 nextInstObj = (wrappedInstance + layer_idx);
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06002100 nextInstObj->pGPA = (PFN_vkGPA) nextGPA;
Jon Ashburn27cd5842015-05-12 17:26:48 -06002101 nextInstObj->baseObject = baseObj;
2102 nextInstObj->nextObject = nextObj;
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06002103 nextObj = (void*) nextInstObj;
Jon Ashburn27cd5842015-05-12 17:26:48 -06002104
2105 char funcStr[256];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002106 snprintf(funcStr, 256, "%sGetInstanceProcAddr", layer_prop->info.layerName);
2107 lib_handle = loader_add_layer_lib("instance", layer_prop);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002108 if ((nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
2109 nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
Jon Ashburn27cd5842015-05-12 17:26:48 -06002110 if (!nextGPA) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002111 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 -06002112
2113 /* TODO: Should we return nextObj, nextGPA to previous? */
Jon Ashburn27cd5842015-05-12 17:26:48 -06002114 continue;
2115 }
2116
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002117 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002118 "Insert instance layer %s (%s)",
2119 layer_prop->info.layerName,
2120 layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002121
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002122 layer_idx--;
Jon Ashburn27cd5842015-05-12 17:26:48 -06002123 }
2124
Jon Ashburn8fd08252015-05-28 16:25:02 -06002125 loader_init_instance_core_dispatch_table(inst->disp, nextGPA, (VkInstance) nextObj, (VkInstance) baseObj);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002126
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002127 return inst->activated_layer_list.count;
Jon Ashburn27cd5842015-05-12 17:26:48 -06002128}
2129
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002130void loader_activate_instance_layer_extensions(struct loader_instance *inst)
2131{
2132
2133 loader_init_instance_extension_dispatch_table(inst->disp,
2134 inst->disp->GetInstanceProcAddr,
Jon Ashburn128f9422015-05-28 19:16:58 -06002135 (VkInstance) inst);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002136}
2137
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002138static VkResult loader_enable_device_layers(
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06002139 struct loader_icd *icd,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002140 struct loader_device *dev,
2141 const VkDeviceCreateInfo *pCreateInfo)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002142{
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002143 VkResult err;
2144
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002145 if (dev == NULL)
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002146 return VK_ERROR_UNKNOWN;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002147
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002148 if (dev->activated_layer_list.list == NULL || dev->activated_layer_list.capacity == 0) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002149 loader_init_layer_list(&dev->activated_layer_list);
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002150 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002151
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002152 if (dev->activated_layer_list.list == NULL) {
2153 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc device activated layer list");
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002154 return VK_ERROR_OUT_OF_HOST_MEMORY;
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002155 }
2156
Jon Ashburn0c26e712015-07-02 16:10:32 -06002157 /* Add any implicit layers first */
2158 loader_add_layer_implicit(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002159 VK_LAYER_TYPE_DEVICE_IMPLICIT,
2160 &dev->activated_layer_list,
Jon Ashburnbd332cc2015-07-07 10:27:45 -06002161 &loader.scanned_layers);
Jon Ashburn0c26e712015-07-02 16:10:32 -06002162
2163 /* Add any layers specified via environment variable next */
Jon Ashburneb6d5682015-07-02 14:10:53 -06002164 loader_add_layer_env(
Jon Ashburnbd332cc2015-07-07 10:27:45 -06002165 VK_LAYER_TYPE_DEVICE_EXPLICIT,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002166 "VK_DEVICE_LAYERS",
2167 &dev->activated_layer_list,
Jon Ashburnbd332cc2015-07-07 10:27:45 -06002168 &loader.scanned_layers);
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002169
2170 /* Add layers specified by the application */
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002171 err = loader_add_layer_names_to_list(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002172 &dev->activated_layer_list,
2173 pCreateInfo->layerCount,
2174 pCreateInfo->ppEnabledLayerNames,
Jon Ashburnbd332cc2015-07-07 10:27:45 -06002175 &loader.scanned_layers);
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002176
2177 return err;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002178}
2179
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002180/*
2181 * This function terminates the device chain fro CreateDevice.
2182 * CreateDevice is a special case and so the loader call's
2183 * the ICD's CreateDevice before creating the chain. Since
2184 * we can't call CreateDevice twice we must terminate the
2185 * device chain with something else.
2186 */
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002187static VkResult scratch_vkCreateDevice(
2188 VkPhysicalDevice gpu,
2189 const VkDeviceCreateInfo *pCreateInfo,
2190 VkDevice *pDevice)
2191{
2192 return VK_SUCCESS;
2193}
2194
2195static void * VKAPI loader_GetDeviceChainProcAddr(VkDevice device, const char * name)
2196{
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002197 if (!strcmp(name, "vkGetDeviceProcAddr"))
2198 return (void *) loader_GetDeviceChainProcAddr;
2199 if (!strcmp(name, "vkCreateDevice"))
2200 return (void *) scratch_vkCreateDevice;
2201
Courtney Goeltzenleuchter3e029d12015-06-29 16:09:23 -06002202 struct loader_device *found_dev;
2203 struct loader_icd *icd = loader_get_icd_and_device(device, &found_dev);
2204 return icd->GetDeviceProcAddr(device, name);
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002205}
2206
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002207static uint32_t loader_activate_device_layers(
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06002208 struct loader_icd *icd,
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002209 struct loader_device *dev,
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06002210 VkDevice device)
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002211{
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002212 if (!icd)
2213 return 0;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002214
David Pinedoa0a8a242015-06-24 15:29:18 -06002215 if (!dev) {
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002216 return 0;
David Pinedoa0a8a242015-06-24 15:29:18 -06002217 }
Jon Ashburn94e70492015-06-10 10:13:10 -06002218
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002219 /* activate any layer libraries */
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06002220 void* nextObj = (void*) device;
2221 void* baseObj = nextObj;
Jon Ashburn94e70492015-06-10 10:13:10 -06002222 VkBaseLayerObject *nextGpuObj;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002223 PFN_vkGetDeviceProcAddr nextGPA = loader_GetDeviceChainProcAddr;
Jon Ashburn94e70492015-06-10 10:13:10 -06002224 VkBaseLayerObject *wrappedGpus;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002225
Jon Ashburn94e70492015-06-10 10:13:10 -06002226 if (!dev->activated_layer_list.count)
2227 return 0;
2228
2229 wrappedGpus = malloc(sizeof (VkBaseLayerObject) * dev->activated_layer_list.count);
2230 if (!wrappedGpus) {
2231 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Gpu objects for layer");
2232 return 0;
2233 }
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002234
Jon Ashburn94e70492015-06-10 10:13:10 -06002235 for (int32_t i = dev->activated_layer_list.count - 1; i >= 0; i--) {
2236
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002237 struct loader_layer_properties *layer_prop = &dev->activated_layer_list.list[i];
Jon Ashburn94e70492015-06-10 10:13:10 -06002238 loader_platform_dl_handle lib_handle;
2239
Jon Ashburn94e70492015-06-10 10:13:10 -06002240 nextGpuObj = (wrappedGpus + i);
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06002241 nextGpuObj->pGPA = (PFN_vkGPA)nextGPA;
Jon Ashburn94e70492015-06-10 10:13:10 -06002242 nextGpuObj->baseObject = baseObj;
2243 nextGpuObj->nextObject = nextObj;
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06002244 nextObj = (void*) nextGpuObj;
Jon Ashburn94e70492015-06-10 10:13:10 -06002245
2246 char funcStr[256];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002247 snprintf(funcStr, 256, "%sGetDeviceProcAddr", layer_prop->info.layerName);
2248 lib_handle = loader_add_layer_lib("device", layer_prop);
Jon Ashburn94e70492015-06-10 10:13:10 -06002249 if ((nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
2250 nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr");
2251 if (!nextGPA) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002252 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 -06002253 continue;
2254 }
2255
2256 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002257 "Insert device layer library %s (%s)",
2258 layer_prop->info.layerName,
2259 layer_prop->lib_info.lib_name);
Jon Ashburn94e70492015-06-10 10:13:10 -06002260
2261 }
2262
2263 loader_init_device_dispatch_table(&dev->loader_dispatch, nextGPA,
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06002264 (VkDevice) nextObj, (VkDevice) baseObj);
Jon Ashburn94e70492015-06-10 10:13:10 -06002265 free(wrappedGpus);
2266
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002267 return dev->activated_layer_list.count;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002268}
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002269
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002270VkResult loader_validate_layers(
2271 const uint32_t layer_count,
2272 const char * const *ppEnabledLayerNames,
2273 struct loader_layer_list *list)
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06002274{
2275 struct loader_layer_properties *prop;
2276
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002277 for (uint32_t i = 0; i < layer_count; i++) {
2278 prop = get_layer_property(ppEnabledLayerNames[i],
2279 list);
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06002280 if (!prop) {
2281 return VK_ERROR_INVALID_LAYER;
2282 }
2283 }
2284
2285 return VK_SUCCESS;
2286}
2287
2288VkResult loader_validate_instance_extensions(
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002289 const VkInstanceCreateInfo *pCreateInfo)
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06002290{
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002291 struct loader_extension_property *extension_prop;
2292 struct loader_layer_properties *layer_prop;
2293
2294 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2295 extension_prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
2296 &loader.global_extensions);
2297
2298 if (extension_prop) {
2299 continue;
2300 }
2301
2302 extension_prop = NULL;
2303
2304 /* Not in global list, search layer extension lists */
2305 for (uint32_t j = 0; j < pCreateInfo->layerCount; j++) {
2306 layer_prop = get_layer_property(pCreateInfo->ppEnabledLayerNames[i],
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002307 &loader.scanned_layers);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002308
2309 if (!layer_prop) {
Courtney Goeltzenleuchter6f5b00c2015-07-06 20:46:50 -06002310 /* Should NOT get here, loader_validate_layers
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002311 * should have already filtered this case out.
2312 */
2313 continue;
2314 }
2315
2316 extension_prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
2317 &layer_prop->instance_extension_list);
2318 if (extension_prop) {
2319 /* Found the extension in one of the layers enabled by the app. */
2320 break;
2321 }
2322 }
2323
2324 if (!extension_prop) {
2325 /* Didn't find extension name in any of the global layers, error out */
2326 return VK_ERROR_INVALID_EXTENSION;
2327 }
2328 }
2329 return VK_SUCCESS;
2330}
2331
2332VkResult loader_validate_device_extensions(
2333 struct loader_icd *icd,
Cody Northrope62183e2015-07-09 18:08:05 -06002334 uint32_t gpu_index,
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002335 const VkDeviceCreateInfo *pCreateInfo)
2336{
2337 struct loader_extension_property *extension_prop;
2338 struct loader_layer_properties *layer_prop;
2339
2340 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2341 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
2342 extension_prop = get_extension_property(extension_name,
Courtney Goeltzenleuchterfedb2a52015-07-08 21:13:16 -06002343 &icd->device_extension_cache[gpu_index]);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002344
2345 if (extension_prop) {
2346 continue;
2347 }
2348
2349 /* Not in global list, search layer extension lists */
2350 for (uint32_t j = 0; j < pCreateInfo->layerCount; j++) {
2351 const char *layer_name = pCreateInfo->ppEnabledLayerNames[j];
2352 layer_prop = get_layer_property(layer_name,
2353 &icd->layer_properties_cache);
2354
2355 if (!layer_prop) {
2356 /* Should NOT get here, loader_validate_instance_layers
2357 * should have already filtered this case out.
2358 */
2359 continue;
2360 }
2361
2362 extension_prop = get_extension_property(extension_name,
2363 &layer_prop->device_extension_list);
2364 if (extension_prop) {
2365 /* Found the extension in one of the layers enabled by the app. */
2366 break;
2367 }
2368 }
2369
2370 if (!extension_prop) {
2371 /* Didn't find extension name in any of the device layers, error out */
2372 return VK_ERROR_INVALID_EXTENSION;
2373 }
2374 }
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06002375 return VK_SUCCESS;
2376}
2377
Jon Ashburn27cd5842015-05-12 17:26:48 -06002378VkResult loader_CreateInstance(
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002379 const VkInstanceCreateInfo* pCreateInfo,
2380 VkInstance* pInstance)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002381{
Jon Ashburneed0c002015-05-21 17:42:17 -06002382 struct loader_instance *ptr_instance = *(struct loader_instance **) pInstance;
Jon Ashburn46888392015-01-29 15:45:51 -07002383 struct loader_scanned_icds *scanned_icds;
2384 struct loader_icd *icd;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06002385 struct loader_extension_property *prop;
2386 char **filtered_extension_names = NULL;
2387 VkInstanceCreateInfo icd_create_info;
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002388 VkResult res = VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002389
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06002390 icd_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
2391 icd_create_info.layerCount = 0;
2392 icd_create_info.ppEnabledLayerNames = NULL;
2393 icd_create_info.pAllocCb = pCreateInfo->pAllocCb;
2394 icd_create_info.pAppInfo = pCreateInfo->pAppInfo;
2395 icd_create_info.pNext = pCreateInfo->pNext;
2396
2397 /*
2398 * NOTE: Need to filter the extensions to only those
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002399 * supported by the ICD.
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06002400 * No ICD will advertise support for layers. An ICD
2401 * library could support a layer, but it would be
2402 * independent of the actual ICD, just in the same library.
2403 */
2404 filtered_extension_names = loader_stack_alloc(pCreateInfo->extensionCount * sizeof(char *));
2405 if (!filtered_extension_names) {
2406 return VK_ERROR_OUT_OF_HOST_MEMORY;
2407 }
2408 icd_create_info.ppEnabledExtensionNames = (const char * const *) filtered_extension_names;
2409
Jon Ashburn46888392015-01-29 15:45:51 -07002410 scanned_icds = loader.scanned_icd_list;
2411 while (scanned_icds) {
2412 icd = loader_icd_add(ptr_instance, scanned_icds);
2413 if (icd) {
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06002414
2415 icd_create_info.extensionCount = 0;
2416 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2417 prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
2418 &scanned_icds->global_extension_list);
2419 if (prop) {
2420 filtered_extension_names[icd_create_info.extensionCount] = (char *) pCreateInfo->ppEnabledExtensionNames[i];
2421 icd_create_info.extensionCount++;
2422 }
2423 }
2424
2425 res = scanned_icds->CreateInstance(&icd_create_info,
Jon Ashburn3da71f22015-05-14 12:43:38 -06002426 &(icd->instance));
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06002427 if (res != VK_SUCCESS)
Jon Ashburn46888392015-01-29 15:45:51 -07002428 {
2429 ptr_instance->icds = ptr_instance->icds->next;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002430 loader_icd_destroy(ptr_instance, icd);
Jon Ashburn3da71f22015-05-14 12:43:38 -06002431 icd->instance = VK_NULL_HANDLE;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002432 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Jon Ashburn46888392015-01-29 15:45:51 -07002433 "ICD ignored: failed to CreateInstance on device");
Jon Ashburn3da71f22015-05-14 12:43:38 -06002434 } else
2435 {
2436 loader_icd_init_entrys(icd, scanned_icds);
Jon Ashburn46888392015-01-29 15:45:51 -07002437 }
2438 }
2439 scanned_icds = scanned_icds->next;
2440 }
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002441
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002442 /*
2443 * If no ICDs were added to instance list and res is unchanged
2444 * from it's initial value, the loader was unable to find
2445 * a suitable ICD.
2446 */
Ian Elliotteb450762015-02-05 15:19:15 -07002447 if (ptr_instance->icds == NULL) {
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002448 if (res == VK_SUCCESS) {
2449 return VK_ERROR_INCOMPATIBLE_DRIVER;
2450 } else {
2451 return res;
2452 }
Ian Elliotteb450762015-02-05 15:19:15 -07002453 }
Jon Ashburn46888392015-01-29 15:45:51 -07002454
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002455 return VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002456}
2457
Jon Ashburn27cd5842015-05-12 17:26:48 -06002458VkResult loader_DestroyInstance(
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06002459 VkInstance instance)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002460{
Courtney Goeltzenleuchterdeceded2015-06-08 15:04:02 -06002461 struct loader_instance *ptr_instance = loader_instance(instance);
Jon Ashburn3da71f22015-05-14 12:43:38 -06002462 struct loader_icd *icds = ptr_instance->icds;
Jon Ashburna6fd2612015-06-16 14:43:19 -06002463 struct loader_icd *next_icd;
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06002464 VkResult res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002465
2466 // Remove this instance from the list of instances:
2467 struct loader_instance *prev = NULL;
2468 struct loader_instance *next = loader.instances;
2469 while (next != NULL) {
2470 if (next == ptr_instance) {
2471 // Remove this instance from the list:
2472 if (prev)
2473 prev->next = next->next;
Jon Ashburnc5c49602015-02-03 09:26:59 -07002474 else
2475 loader.instances = next->next;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002476 break;
2477 }
2478 prev = next;
2479 next = next->next;
2480 }
2481 if (next == NULL) {
2482 // This must be an invalid instance handle or empty list
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06002483 return VK_ERROR_INVALID_HANDLE;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002484 }
2485
Jon Ashburn3da71f22015-05-14 12:43:38 -06002486 while (icds) {
2487 if (icds->instance) {
2488 res = icds->DestroyInstance(icds->instance);
Tony Barbourf20f87b2015-04-22 09:02:32 -06002489 if (res != VK_SUCCESS)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002490 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Tony Barbourf20f87b2015-04-22 09:02:32 -06002491 "ICD ignored: failed to DestroyInstance on device");
2492 }
Jon Ashburna6fd2612015-06-16 14:43:19 -06002493 next_icd = icds->next;
Jon Ashburn3da71f22015-05-14 12:43:38 -06002494 icds->instance = VK_NULL_HANDLE;
Jon Ashburna6fd2612015-06-16 14:43:19 -06002495 loader_icd_destroy(ptr_instance, icds);
2496
2497 icds = next_icd;
Jon Ashburn46888392015-01-29 15:45:51 -07002498 }
2499
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002500
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06002501 return VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002502}
2503
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002504VkResult loader_init_physical_device_info(
2505 struct loader_instance *ptr_instance)
2506{
2507 struct loader_icd *icd;
2508 uint32_t n, count = 0;
2509 VkResult res = VK_ERROR_UNKNOWN;
2510
2511 icd = ptr_instance->icds;
2512 while (icd) {
2513 res = icd->EnumeratePhysicalDevices(icd->instance, &n, NULL);
2514 if (res != VK_SUCCESS)
2515 return res;
2516 icd->gpu_count = n;
2517 count += n;
2518 icd = icd->next;
2519 }
2520
2521 ptr_instance->total_gpu_count = count;
2522
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002523 icd = ptr_instance->icds;
2524 while (icd) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002525
2526 n = icd->gpu_count;
Jon Ashburn128f9422015-05-28 19:16:58 -06002527 icd->gpus = (VkPhysicalDevice *) malloc(n * sizeof(VkPhysicalDevice));
2528 if (!icd->gpus) {
2529 /* TODO: Add cleanup code here */
2530 return VK_ERROR_OUT_OF_HOST_MEMORY;
2531 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002532 res = icd->EnumeratePhysicalDevices(
2533 icd->instance,
2534 &n,
Jon Ashburn128f9422015-05-28 19:16:58 -06002535 icd->gpus);
2536 if ((res == VK_SUCCESS) && (n == icd->gpu_count)) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002537
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002538 for (unsigned int i = 0; i < n; i++) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002539
Jon Ashburn128f9422015-05-28 19:16:58 -06002540 loader_init_dispatch(icd->gpus[i], ptr_instance->disp);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002541
2542 if (!loader_init_ext_list(&icd->device_extension_cache[i])) {
2543 /* TODO: Add cleanup code here */
2544 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2545 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002546 if (res == VK_SUCCESS) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002547
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002548 loader_add_physical_device_extensions(
2549 icd->GetPhysicalDeviceExtensionProperties,
2550 icd->gpus[0],
2551 VK_EXTENSION_ORIGIN_ICD,
2552 icd->scanned_icds->lib_name,
2553 &icd->device_extension_cache[i]);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002554
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002555 for (uint32_t l = 0; l < loader.scanned_layers.count; l++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002556 loader_platform_dl_handle lib_handle;
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002557 char *lib_name = loader.scanned_layers.list[l].lib_info.lib_name;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002558
2559 lib_handle = loader_platform_open_library(lib_name);
2560 if (lib_handle == NULL) {
2561 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "open library failed: %s", lib_name);
2562 continue;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002563 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002564 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
2565 "library: %s", lib_name);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002566
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002567 loader_add_physical_device_layer_properties(
2568 icd, lib_name, lib_handle);
2569
2570 loader_platform_close_library(lib_handle);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002571 }
2572 }
2573
2574 if (res != VK_SUCCESS) {
2575 /* clean up any extension lists previously created before this request failed */
2576 for (uint32_t j = 0; j < i; j++) {
2577 loader_destroy_ext_list(&icd->device_extension_cache[i]);
2578 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002579
2580 loader_destroy_layer_list(&icd->layer_properties_cache);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002581 return res;
2582 }
2583 }
2584
2585 count += n;
2586 }
2587
2588 icd = icd->next;
2589 }
2590
2591 return VK_SUCCESS;
2592}
2593
Jon Ashburn27cd5842015-05-12 17:26:48 -06002594VkResult loader_EnumeratePhysicalDevices(
Courtney Goeltzenleuchter5e41f1d2015-04-20 12:48:54 -06002595 VkInstance instance,
2596 uint32_t* pPhysicalDeviceCount,
2597 VkPhysicalDevice* pPhysicalDevices)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002598{
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002599 uint32_t index = 0;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07002600 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002601 struct loader_icd *icd = ptr_instance->icds;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07002602
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002603 if (ptr_instance->total_gpu_count == 0) {
2604 loader_init_physical_device_info(ptr_instance);
Jon Ashburn4c392fb2015-01-28 19:57:09 -07002605 }
2606
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002607 *pPhysicalDeviceCount = ptr_instance->total_gpu_count;
2608 if (!pPhysicalDevices) {
2609 return VK_SUCCESS;
2610 }
Jon Ashburn4c392fb2015-01-28 19:57:09 -07002611
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002612 while (icd) {
2613 assert((index + icd->gpu_count) <= *pPhysicalDeviceCount);
Jon Ashburn128f9422015-05-28 19:16:58 -06002614 memcpy(&pPhysicalDevices[index], icd->gpus, icd->gpu_count * sizeof(VkPhysicalDevice));
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002615 index += icd->gpu_count;
2616 icd = icd->next;
2617 }
2618
2619 return VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002620}
2621
Tony Barbour59a47322015-06-24 16:06:58 -06002622VkResult loader_GetPhysicalDeviceProperties(
Jon Ashburn3da71f22015-05-14 12:43:38 -06002623 VkPhysicalDevice gpu,
Tony Barbour59a47322015-06-24 16:06:58 -06002624 VkPhysicalDeviceProperties* pProperties)
Jon Ashburn3da71f22015-05-14 12:43:38 -06002625{
2626 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06002627 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburn3da71f22015-05-14 12:43:38 -06002628 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2629
Tony Barbour59a47322015-06-24 16:06:58 -06002630 if (icd->GetPhysicalDeviceProperties)
2631 res = icd->GetPhysicalDeviceProperties(gpu, pProperties);
2632
2633 return res;
2634}
2635
2636VkResult loader_GetPhysicalDevicePerformance(
2637 VkPhysicalDevice gpu,
2638 VkPhysicalDevicePerformance* pPerformance)
2639{
2640 uint32_t gpu_index;
2641 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2642 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2643
2644 if (icd->GetPhysicalDevicePerformance)
2645 res = icd->GetPhysicalDevicePerformance(gpu, pPerformance);
2646
2647 return res;
2648}
2649
2650VkResult loader_GetPhysicalDeviceQueueCount(
2651 VkPhysicalDevice gpu,
2652 uint32_t* pCount)
2653{
2654 uint32_t gpu_index;
2655 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2656 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2657
2658 if (icd->GetPhysicalDeviceQueueCount)
2659 res = icd->GetPhysicalDeviceQueueCount(gpu, pCount);
2660
2661 return res;
2662}
2663
2664VkResult loader_GetPhysicalDeviceQueueProperties (
2665 VkPhysicalDevice gpu,
2666 uint32_t count,
2667 VkPhysicalDeviceQueueProperties * pProperties)
2668{
2669 uint32_t gpu_index;
2670 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2671 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2672
2673 if (icd->GetPhysicalDeviceQueueProperties)
2674 res = icd->GetPhysicalDeviceQueueProperties(gpu, count, pProperties);
2675
2676 return res;
2677}
2678
2679VkResult loader_GetPhysicalDeviceMemoryProperties (
2680 VkPhysicalDevice gpu,
2681 VkPhysicalDeviceMemoryProperties* pProperties)
2682{
2683 uint32_t gpu_index;
2684 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2685 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2686
2687 if (icd->GetPhysicalDeviceMemoryProperties)
2688 res = icd->GetPhysicalDeviceMemoryProperties(gpu, pProperties);
Jon Ashburn3da71f22015-05-14 12:43:38 -06002689
2690 return res;
2691}
2692
Chris Forbesbc0bb772015-06-21 22:55:02 +12002693VkResult loader_GetPhysicalDeviceFeatures(
2694 VkPhysicalDevice physicalDevice,
2695 VkPhysicalDeviceFeatures* pFeatures)
2696{
2697 uint32_t gpu_index;
2698 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2699 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2700
2701 if (icd->GetPhysicalDeviceFeatures)
2702 res = icd->GetPhysicalDeviceFeatures(physicalDevice, pFeatures);
2703
2704 return res;
2705}
2706
2707VkResult loader_GetPhysicalDeviceFormatInfo(
2708 VkPhysicalDevice physicalDevice,
2709 VkFormat format,
2710 VkFormatProperties* pFormatInfo)
2711{
2712 uint32_t gpu_index;
2713 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2714 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2715
2716 if (icd->GetPhysicalDeviceFormatInfo)
2717 res = icd->GetPhysicalDeviceFormatInfo(physicalDevice, format, pFormatInfo);
2718
2719 return res;
2720}
2721
2722VkResult loader_GetPhysicalDeviceLimits(
2723 VkPhysicalDevice physicalDevice,
2724 VkPhysicalDeviceLimits* pLimits)
2725{
2726 uint32_t gpu_index;
2727 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2728 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2729
2730 if (icd->GetPhysicalDeviceLimits)
2731 res = icd->GetPhysicalDeviceLimits(physicalDevice, pLimits);
2732
2733 return res;
2734}
2735
Mark Lobodzinski16e8bef2015-07-03 15:58:09 -06002736VkResult loader_GetPhysicalDeviceSparseImageFormatProperties(
2737 VkPhysicalDevice physicalDevice,
2738 VkFormat format,
2739 VkImageType type,
2740 uint32_t samples,
2741 VkImageUsageFlags usage,
2742 VkImageTiling tiling,
2743 uint32_t* pNumProperties,
2744 VkSparseImageFormatProperties* pProperties)
2745{
2746 uint32_t gpu_index;
2747 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2748 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2749
2750 if (icd->GetPhysicalDeviceSparseImageFormatProperties)
2751 res = icd->GetPhysicalDeviceSparseImageFormatProperties(physicalDevice, format, type, samples, usage, tiling, pNumProperties, pProperties);
2752
2753 return res;
2754}
2755
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002756VkResult loader_CreateDevice(
2757 VkPhysicalDevice gpu,
2758 const VkDeviceCreateInfo* pCreateInfo,
2759 VkDevice* pDevice)
2760{
2761 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06002762 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002763 struct loader_device *dev;
Courtney Goeltzenleuchter6f5b00c2015-07-06 20:46:50 -06002764 VkDeviceCreateInfo device_create_info;
2765 char **filtered_extension_names = NULL;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002766 VkResult res;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002767
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002768 if (!icd->CreateDevice) {
2769 return VK_ERROR_INITIALIZATION_FAILED;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002770 }
2771
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002772 res = loader_validate_layers(pCreateInfo->layerCount,
2773 pCreateInfo->ppEnabledLayerNames,
2774 &icd->layer_properties_cache);
2775 if (res != VK_SUCCESS) {
2776 return res;
2777 }
2778
Courtney Goeltzenleuchterfedb2a52015-07-08 21:13:16 -06002779 res = loader_validate_device_extensions(icd, gpu_index, pCreateInfo);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002780 if (res != VK_SUCCESS) {
2781 return res;
2782 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002783
Courtney Goeltzenleuchter6f5b00c2015-07-06 20:46:50 -06002784 /*
2785 * NOTE: Need to filter the extensions to only those
2786 * supported by the ICD.
2787 * No ICD will advertise support for layers. An ICD
2788 * library could support a layer, but it would be
2789 * independent of the actual ICD, just in the same library.
2790 */
2791 filtered_extension_names = loader_stack_alloc(pCreateInfo->extensionCount * sizeof(char *));
2792 if (!filtered_extension_names) {
2793 return VK_ERROR_OUT_OF_HOST_MEMORY;
2794 }
2795
2796 /* Copy user's data */
2797 memcpy(&device_create_info, pCreateInfo, sizeof(VkDeviceCreateInfo));
2798
2799 /* ICD's do not use layers */
2800 device_create_info.layerCount = 0;
2801 device_create_info.ppEnabledLayerNames = NULL;
2802
2803 device_create_info.extensionCount = 0;
2804 device_create_info.ppEnabledExtensionNames = (const char * const *) filtered_extension_names;
2805
2806 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2807 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
2808 struct loader_extension_property *prop = get_extension_property(extension_name,
2809 &icd->device_extension_cache[gpu_index]);
2810 if (prop) {
2811 filtered_extension_names[device_create_info.extensionCount] = (char *) extension_name;
2812 device_create_info.extensionCount++;
2813 }
2814 }
2815
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002816 res = icd->CreateDevice(gpu, pCreateInfo, pDevice);
2817 if (res != VK_SUCCESS) {
2818 return res;
2819 }
2820
2821 dev = loader_add_logical_device(*pDevice, &icd->logical_device_list);
2822 if (dev == NULL) {
2823 return VK_ERROR_OUT_OF_HOST_MEMORY;
2824 }
2825 PFN_vkGetDeviceProcAddr get_proc_addr = icd->GetDeviceProcAddr;
2826 loader_init_device_dispatch_table(&dev->loader_dispatch, get_proc_addr,
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06002827 (VkDevice) icd->gpus[gpu_index], (VkDevice) icd->gpus[gpu_index]);
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002828
2829 dev->loader_dispatch.CreateDevice = scratch_vkCreateDevice;
2830 loader_init_dispatch(*pDevice, &dev->loader_dispatch);
2831
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002832 /*
2833 * Put together the complete list of extensions to enable
2834 * This includes extensions requested via environment variables.
2835 */
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06002836 loader_enable_device_layers(icd, dev, pCreateInfo);
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002837
2838 /*
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002839 * Load the libraries and build the device chain
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002840 * terminating with the selected device.
2841 */
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06002842 loader_activate_device_layers(icd, dev, *pDevice);
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002843
2844 res = dev->loader_dispatch.CreateDevice(gpu, pCreateInfo, pDevice);
2845
2846 dev->loader_dispatch.CreateDevice = icd->CreateDevice;
2847
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002848 return res;
2849}
2850
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -06002851static void * VKAPI loader_GetInstanceProcAddr(VkInstance instance, const char * pName)
Jon Ashburnb0fbe912015-05-06 10:15:07 -06002852{
Jon Ashburn07daee72015-05-21 18:13:33 -06002853 if (instance == VK_NULL_HANDLE)
2854 return NULL;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002855
Jon Ashburn07daee72015-05-21 18:13:33 -06002856 void *addr;
2857 /* get entrypoint addresses that are global (in the loader)*/
2858 addr = globalGetProcAddr(pName);
2859 if (addr)
2860 return addr;
Jon Ashburnb0fbe912015-05-06 10:15:07 -06002861
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002862 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
2863
Jon Ashburn922c8f62015-06-18 09:05:37 -06002864 /* return any extension global entrypoints */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002865 addr = debug_report_instance_gpa(ptr_instance, pName);
2866 if (addr) {
2867 return addr;
2868 }
2869
Jon Ashburn922c8f62015-06-18 09:05:37 -06002870 /* TODO Remove this once WSI has no loader special code */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002871 addr = wsi_lunarg_GetInstanceProcAddr(instance, pName);
David Pinedoa0a8a242015-06-24 15:29:18 -06002872 if (addr) {
Jon Ashburn922c8f62015-06-18 09:05:37 -06002873 return addr;
David Pinedoa0a8a242015-06-24 15:29:18 -06002874 }
Jon Ashburn07daee72015-05-21 18:13:33 -06002875
2876 /* return the instance dispatch table entrypoint for extensions */
2877 const VkLayerInstanceDispatchTable *disp_table = * (VkLayerInstanceDispatchTable **) instance;
2878 if (disp_table == NULL)
2879 return NULL;
2880
2881 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
2882 if (addr)
2883 return addr;
Jon Ashburnb0fbe912015-05-06 10:15:07 -06002884
2885 return NULL;
2886}
2887
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -06002888LOADER_EXPORT void * VKAPI vkGetInstanceProcAddr(VkInstance instance, const char * pName)
2889{
2890 return loader_GetInstanceProcAddr(instance, pName);
2891}
2892
2893static void * VKAPI loader_GetDeviceProcAddr(VkDevice device, const char * pName)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002894{
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06002895 if (device == VK_NULL_HANDLE) {
2896 return NULL;
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07002897 }
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002898
Chia-I Wuf46b81a2015-01-04 11:12:47 +08002899 void *addr;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002900
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002901 /* for entrypoints that loader must handle (ie non-dispatchable or create object)
2902 make sure the loader entrypoint is returned */
2903 addr = loader_non_passthrough_gpa(pName);
Ian Elliotte19c9152015-04-15 12:53:19 -06002904 if (addr) {
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002905 return addr;
Ian Elliotte19c9152015-04-15 12:53:19 -06002906 }
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002907
Jon Ashburn07daee72015-05-21 18:13:33 -06002908 /* return any extension device entrypoints the loader knows about */
Jon Ashburn922c8f62015-06-18 09:05:37 -06002909 /* TODO once WSI has no loader special code remove this */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002910 addr = wsi_lunarg_GetDeviceProcAddr(device, pName);
David Pinedoa0a8a242015-06-24 15:29:18 -06002911 if (addr) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002912 return addr;
David Pinedoa0a8a242015-06-24 15:29:18 -06002913 }
Jon Ashburn07daee72015-05-21 18:13:33 -06002914
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002915 /* return the dispatch table entrypoint for the fastest case */
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06002916 const VkLayerDispatchTable *disp_table = * (VkLayerDispatchTable **) device;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002917 if (disp_table == NULL)
2918 return NULL;
2919
Jon Ashburn27cd5842015-05-12 17:26:48 -06002920 addr = loader_lookup_device_dispatch_table(disp_table, pName);
Chia-I Wuf46b81a2015-01-04 11:12:47 +08002921 if (addr)
2922 return addr;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002923 else {
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06002924 if (disp_table->GetDeviceProcAddr == NULL)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002925 return NULL;
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06002926 return disp_table->GetDeviceProcAddr(device, pName);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002927 }
2928}
2929
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -06002930LOADER_EXPORT void * VKAPI vkGetDeviceProcAddr(VkDevice device, const char * pName)
2931{
2932 return loader_GetDeviceProcAddr(device, pName);
2933}
2934
Tony Barbour59a47322015-06-24 16:06:58 -06002935LOADER_EXPORT VkResult VKAPI vkGetGlobalExtensionProperties(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002936 const char* pLayerName,
2937 uint32_t* pCount,
2938 VkExtensionProperties* pProperties)
2939{
2940 struct loader_extension_list *global_extension_list;
2941
2942 /* Scan/discover all ICD libraries in a single-threaded manner */
2943 loader_platform_thread_once(&once_icd, loader_icd_scan);
2944
2945 /* get layer libraries in a single-threaded manner */
2946 loader_platform_thread_once(&once_layer, loader_layer_scan);
2947
2948 /* merge any duplicate extensions */
2949 loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
2950
2951 uint32_t copy_size;
2952
2953 if (pCount == NULL) {
2954 return VK_ERROR_INVALID_POINTER;
2955 }
2956
2957 loader_platform_thread_lock_mutex(&loader_lock);
2958
2959 global_extension_list = loader_global_extensions(pLayerName);
2960 if (global_extension_list == NULL) {
2961 loader_platform_thread_unlock_mutex(&loader_lock);
2962 return VK_ERROR_INVALID_LAYER;
2963 }
2964
2965 if (pProperties == NULL) {
2966 *pCount = global_extension_list->count;
2967 loader_platform_thread_unlock_mutex(&loader_lock);
2968 return VK_SUCCESS;
2969 }
2970
2971 copy_size = *pCount < global_extension_list->count ? *pCount : global_extension_list->count;
2972 for (uint32_t i = 0; i < copy_size; i++) {
2973 memcpy(&pProperties[i],
2974 &global_extension_list->list[i].info,
2975 sizeof(VkExtensionProperties));
2976 }
2977 *pCount = copy_size;
2978
2979 loader_platform_thread_unlock_mutex(&loader_lock);
2980
2981 if (copy_size < global_extension_list->count) {
2982 return VK_INCOMPLETE;
2983 }
2984
2985 return VK_SUCCESS;
2986}
2987
2988LOADER_EXPORT VkResult VKAPI vkGetGlobalLayerProperties(
2989 uint32_t* pCount,
2990 VkLayerProperties* pProperties)
Tony Barbour59a47322015-06-24 16:06:58 -06002991{
Jon Ashburn6301a0f2015-05-29 13:15:39 -06002992
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06002993 /* Scan/discover all ICD libraries in a single-threaded manner */
2994 loader_platform_thread_once(&once_icd, loader_icd_scan);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07002995
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06002996 /* get layer libraries in a single-threaded manner */
Jon Ashburn5ef20602015-07-02 09:40:15 -06002997 loader_platform_thread_once(&once_layer, loader_layer_scan);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07002998
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06002999 /* merge any duplicate extensions */
3000 loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
3001
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06003002 uint32_t copy_size;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06003003
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06003004 if (pCount == NULL) {
3005 return VK_ERROR_INVALID_POINTER;
3006 }
3007
3008 /* TODO: do we still need to lock */
Jon Ashburn6301a0f2015-05-29 13:15:39 -06003009 loader_platform_thread_lock_mutex(&loader_lock);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06003010
3011 struct loader_layer_list *layer_list;
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003012 layer_list = loader_scanned_layers();
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06003013
3014 if (pProperties == NULL) {
3015 *pCount = layer_list->count;
3016 loader_platform_thread_unlock_mutex(&loader_lock);
3017 return VK_SUCCESS;
3018 }
3019
3020 copy_size = *pCount < layer_list->count ? *pCount : layer_list->count;
3021 for (uint32_t i = 0; i < copy_size; i++) {
3022 memcpy(&pProperties[i], &layer_list->list[i].info, sizeof(VkLayerProperties));
3023 }
3024 *pCount = copy_size;
Tony Barbour59a47322015-06-24 16:06:58 -06003025
Jon Ashburn6301a0f2015-05-29 13:15:39 -06003026 loader_platform_thread_unlock_mutex(&loader_lock);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06003027
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06003028 if (copy_size < layer_list->count) {
3029 return VK_INCOMPLETE;
3030 }
Tony Barbour59a47322015-06-24 16:06:58 -06003031
3032 return VK_SUCCESS;
3033}
3034
3035VkResult loader_GetPhysicalDeviceExtensionProperties(
3036 VkPhysicalDevice gpu,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06003037 const char* pLayerName,
3038 uint32_t* pCount,
Tony Barbour59a47322015-06-24 16:06:58 -06003039 VkExtensionProperties* pProperties)
3040{
3041 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06003042 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06003043 uint32_t copy_size;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07003044
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06003045 if (pCount == NULL) {
3046 return VK_ERROR_INVALID_POINTER;
3047 }
Jon Ashburn95a77ba2015-05-15 15:09:35 -06003048
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06003049 uint32_t count;
3050 struct loader_extension_list *list;
3051 loader_physical_device_extensions(icd, gpu_index, pLayerName, &count, &list);
3052
3053 if (pProperties == NULL) {
3054 *pCount = count;
3055 return VK_SUCCESS;
3056 }
3057
3058 copy_size = *pCount < count ? *pCount : count;
3059 for (uint32_t i = 0; i < copy_size; i++) {
3060 memcpy(&pProperties[i],
3061 &list->list[i].info,
3062 sizeof(VkExtensionProperties));
3063 }
3064 *pCount = copy_size;
3065
3066 if (copy_size < count) {
3067 return VK_INCOMPLETE;
3068 }
3069
3070 return VK_SUCCESS;
3071}
3072
3073VkResult loader_GetPhysicalDeviceLayerProperties(
3074 VkPhysicalDevice gpu,
3075 uint32_t* pCount,
3076 VkLayerProperties* pProperties)
3077{
3078 uint32_t gpu_index;
3079 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
3080 uint32_t copy_size;
3081
3082 if (pCount == NULL) {
3083 return VK_ERROR_INVALID_POINTER;
3084 }
3085
3086 uint32_t count;
3087 struct loader_layer_list *layer_list;
3088 loader_physical_device_layers(icd, &count, &layer_list);
3089
3090 if (pProperties == NULL) {
3091 *pCount = count;
3092 return VK_SUCCESS;
3093 }
3094
3095 copy_size = *pCount < count ? *pCount : count;
3096 for (uint32_t i = 0; i < copy_size; i++) {
3097 memcpy(&pProperties[i],
3098 &layer_list->list[i].info,
3099 sizeof(VkLayerProperties));
3100 }
3101 *pCount = copy_size;
3102
3103 if (copy_size < count) {
3104 return VK_INCOMPLETE;
3105 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06003106
3107 return VK_SUCCESS;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06003108}