blob: 0f3e8068d8a46238c4a32e21ee20375c52ffbfa2 [file] [log] [blame]
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001/*
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06002 * Vulkan
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08003 *
4 * Copyright (C) 2014 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
Chia-I Wu701f3f62014-09-02 08:32:09 +080023 *
24 * Authors:
25 * Chia-I Wu <olv@lunarg.com>
Jon Ashburn01e2d662014-11-14 09:52:42 -070026 * Jon Ashburn <jon@lunarg.com>
Chia-I Wu701f3f62014-09-02 08:32:09 +080027 * Courtney Goeltzenleuchter <courtney@lunarg.com>
Ian Elliott5aa4ea22015-03-31 15:32:41 -060028 * Ian Elliott <ian@lunarg.com>
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080029 */
Jon Ashburn6b4d70c2014-10-22 18:13:16 -060030#define _GNU_SOURCE
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080031#include <stdio.h>
32#include <stdlib.h>
33#include <stdarg.h>
34#include <stdbool.h>
35#include <string.h>
36
Chia-I Wu13a61a52014-08-04 11:18:20 +080037#include <sys/types.h>
Ian Elliott2d4ab1e2015-01-13 17:52:38 -070038#if defined(WIN32)
39#include "dirent_on_windows.h"
40#else // WIN32
Chia-I Wu13a61a52014-08-04 11:18:20 +080041#include <dirent.h>
Ian Elliott2d4ab1e2015-01-13 17:52:38 -070042#endif // WIN32
Tobin Ehlisb835d1b2015-07-03 10:34:49 -060043#include "vk_loader_platform.h"
Chia-I Wu19300602014-08-04 08:03:57 +080044#include "loader.h"
Jon Ashburn27cd5842015-05-12 17:26:48 -060045#include "gpa_helper.h"
46#include "table_ops.h"
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060047#include "debug_report.h"
Tobin Ehlis0c6f9ee2015-07-03 09:42:57 -060048#include "vk_icd.h"
Jon Ashburn2077e382015-06-29 11:25:34 -060049#include "cJSON.h"
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080050
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060051void loader_add_to_ext_list(
52 struct loader_extension_list *ext_list,
53 uint32_t prop_list_count,
54 const struct loader_extension_property *prop_list);
55
Courtney Goeltzenleuchtered488302015-06-01 14:09:34 -060056static loader_platform_dl_handle loader_add_layer_lib(
57 const char *chain_type,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -060058 struct loader_layer_properties *layer_prop);
Courtney Goeltzenleuchtered488302015-06-01 14:09:34 -060059
60static void loader_remove_layer_lib(
61 struct loader_instance *inst,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -060062 struct loader_layer_properties *layer_prop);
Courtney Goeltzenleuchtered488302015-06-01 14:09:34 -060063
Jon Ashburn27cd5842015-05-12 17:26:48 -060064struct loader_struct loader = {0};
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080065
Courtney Goeltzenleuchter2d3ba632015-07-12 14:35:22 -060066static PFN_vkVoidFunction VKAPI loader_GetInstanceProcAddr(VkInstance instance, const char * pName);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -060067static bool loader_init_ext_list(struct loader_extension_list *ext_info);
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -060068
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -060069enum loader_debug {
Courtney Goeltzenleuchterf3387652015-07-08 18:41:08 -060070 LOADER_INFO_BIT = 0x01,
71 LOADER_WARN_BIT = 0x02,
72 LOADER_PERF_BIT = 0x04,
73 LOADER_ERROR_BIT = 0x08,
74 LOADER_DEBUG_BIT = 0x10,
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -060075};
76
77uint32_t g_loader_debug = 0;
78uint32_t g_loader_log_msgs = 0;
79
Jon Ashburn6301a0f2015-05-29 13:15:39 -060080//thread safety lock for accessing global data structures such as "loader"
81// all entrypoints on the instance chain need to be locked except GPA
Jon Ashburn2077e382015-06-29 11:25:34 -060082// additionally CreateDevice and DestroyDevice needs to be locked
Jon Ashburn6301a0f2015-05-29 13:15:39 -060083loader_platform_thread_mutex loader_lock;
84
Ian Elliottd3ef02f2015-07-06 14:36:13 -060085// This table contains the loader's instance dispatch table, which contains
86// default functions if no instance layers are activated. This contains
87// pointers to "terminator functions".
Jon Ashburn6301a0f2015-05-29 13:15:39 -060088const VkLayerInstanceDispatchTable instance_disp = {
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -060089 .GetInstanceProcAddr = loader_GetInstanceProcAddr,
Jon Ashburn27cd5842015-05-12 17:26:48 -060090 .CreateInstance = loader_CreateInstance,
91 .DestroyInstance = loader_DestroyInstance,
92 .EnumeratePhysicalDevices = loader_EnumeratePhysicalDevices,
Chris Forbesbc0bb772015-06-21 22:55:02 +120093 .GetPhysicalDeviceFeatures = loader_GetPhysicalDeviceFeatures,
Courtney Goeltzenleuchter2caec862015-07-12 12:52:09 -060094 .GetPhysicalDeviceFormatProperties = loader_GetPhysicalDeviceFormatProperties,
Jon Ashburn754864f2015-07-23 18:49:07 -060095 .GetPhysicalDeviceImageFormatProperties = loader_GetPhysicalDeviceImageFormatProperties,
Chris Forbesbc0bb772015-06-21 22:55:02 +120096 .GetPhysicalDeviceLimits = loader_GetPhysicalDeviceLimits,
Tony Barbour59a47322015-06-24 16:06:58 -060097 .GetPhysicalDeviceProperties = loader_GetPhysicalDeviceProperties,
Tony Barbour59a47322015-06-24 16:06:58 -060098 .GetPhysicalDeviceQueueCount = loader_GetPhysicalDeviceQueueCount,
99 .GetPhysicalDeviceQueueProperties = loader_GetPhysicalDeviceQueueProperties,
100 .GetPhysicalDeviceMemoryProperties = loader_GetPhysicalDeviceMemoryProperties,
Tony Barbour59a47322015-06-24 16:06:58 -0600101 .GetPhysicalDeviceExtensionProperties = loader_GetPhysicalDeviceExtensionProperties,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600102 .GetPhysicalDeviceLayerProperties = loader_GetPhysicalDeviceLayerProperties,
Mark Lobodzinski16e8bef2015-07-03 15:58:09 -0600103 .GetPhysicalDeviceSparseImageFormatProperties = loader_GetPhysicalDeviceSparseImageFormatProperties,
Ian Elliottd3ef02f2015-07-06 14:36:13 -0600104 .GetPhysicalDeviceSurfaceSupportWSI = loader_GetPhysicalDeviceSurfaceSupportWSI,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600105 .DbgCreateMsgCallback = loader_DbgCreateMsgCallback,
106 .DbgDestroyMsgCallback = loader_DbgDestroyMsgCallback,
Jon Ashburn27cd5842015-05-12 17:26:48 -0600107};
108
109LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_icd);
110LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_layer);
111LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_exts);
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700112
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600113void* loader_heap_alloc(
114 struct loader_instance *instance,
115 size_t size,
116 VkSystemAllocType alloc_type)
117{
118 if (instance && instance->alloc_callbacks.pfnAlloc) {
119 /* TODO: What should default alignment be? 1, 4, 8, other? */
120 return instance->alloc_callbacks.pfnAlloc(instance->alloc_callbacks.pUserData, size, 4, alloc_type);
121 }
122 return malloc(size);
123}
124
125void* loader_aligned_heap_alloc(
126 struct loader_instance *instance,
127 size_t size,
128 size_t alignment,
129 VkSystemAllocType alloc_type)
130{
131 if (!instance && instance->alloc_callbacks.pfnAlloc) {
132 return instance->alloc_callbacks.pfnAlloc(instance->alloc_callbacks.pUserData, size, alignment, alloc_type);
133 }
Cody Northrop33fa0412015-07-08 16:48:37 -0600134#if defined(_WIN32)
135 return _aligned_malloc(alignment, size);
136#else
137 return aligned_alloc(alignment, size);
138#endif
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600139}
140
141void loader_heap_free(
142 struct loader_instance *instance,
143 void *pMem)
144{
145 if (!instance && instance->alloc_callbacks.pfnFree) {
Courtney Goeltzenleuchter922e1452015-07-10 17:39:59 -0600146 instance->alloc_callbacks.pfnFree(instance->alloc_callbacks.pUserData, pMem);
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600147 }
Courtney Goeltzenleuchter922e1452015-07-10 17:39:59 -0600148 free(pMem);
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600149}
150
Jon Ashburnffad94d2015-06-30 14:46:22 -0700151static void loader_log(VkFlags msg_type, int32_t msg_code,
152 const char *format, ...)
153{
Jon Ashburn86723b02015-07-31 15:47:59 -0600154 char msg[512];
Jon Ashburnffad94d2015-06-30 14:46:22 -0700155 va_list ap;
156 int ret;
157
158 if (!(msg_type & g_loader_log_msgs)) {
159 return;
160 }
161
162 va_start(ap, format);
163 ret = vsnprintf(msg, sizeof(msg), format, ap);
164 if ((ret >= (int) sizeof(msg)) || ret < 0) {
165 msg[sizeof(msg)-1] = '\0';
166 }
167 va_end(ap);
168
Ian Elliott4470a302015-02-17 10:33:47 -0700169#if defined(WIN32)
Jon Ashburnffad94d2015-06-30 14:46:22 -0700170 OutputDebugString(msg);
mschottb9cdb782015-07-22 14:11:29 +0200171 OutputDebugString("\n");
Jon Ashburnffad94d2015-06-30 14:46:22 -0700172#endif
173 fputs(msg, stderr);
174 fputc('\n', stderr);
175}
176
177#if defined(WIN32)
Tony Barbourea968902015-07-29 14:26:21 -0600178static char *loader_get_next_path(char *path);
Jon Ashburnffad94d2015-06-30 14:46:22 -0700179/**
180* Find the list of registry files (names within a key) in key "location".
181*
182* This function looks in the registry (hive = DEFAULT_VK_REGISTRY_HIVE) key as given in "location"
183* for a list or name/values which are added to a returned list (function return value).
184* The DWORD values within the key must be 0 or they are skipped.
185* Function return is a string with a ';' seperated list of filenames.
186* Function return is NULL if no valid name/value pairs are found in the key,
187* or the key is not found.
188*
189* \returns
190* A string list of filenames as pointer.
191* When done using the returned string list, pointer should be freed.
192*/
Jon Ashburn24265ac2015-07-31 09:33:21 -0600193static char *loader_get_registry_files(char *location)
Jon Ashburnffad94d2015-06-30 14:46:22 -0700194{
195 LONG rtn_value;
196 HKEY hive, key;
197 DWORD access_flags = KEY_QUERY_VALUE;
198 char name[2048];
199 char *out = NULL;
Tony Barbourea968902015-07-29 14:26:21 -0600200 char *loc = location;
201 char *next;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700202 DWORD idx = 0;
203 DWORD name_size = sizeof(name);
204 DWORD value;
205 DWORD total_size = 4096;
206 DWORD value_size = sizeof(value);
Tony Barbourea968902015-07-29 14:26:21 -0600207
208 while(*loc)
209 {
210 next = loader_get_next_path(loc);
211 hive = DEFAULT_VK_REGISTRY_HIVE;
212 rtn_value = RegOpenKeyEx(hive, loc, 0, access_flags, &key);
213 if (rtn_value != ERROR_SUCCESS) {
214 // We didn't find the key. Try the 32-bit hive (where we've seen the
215 // key end up on some people's systems):
216 access_flags |= KEY_WOW64_32KEY;
217 rtn_value = RegOpenKeyEx(hive, loc, 0, access_flags, &key);
218 if (rtn_value != ERROR_SUCCESS) {
219 // We still couldn't find the key, so give up:
220 loc = next;
221 continue;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700222 }
Jon Ashburnffad94d2015-06-30 14:46:22 -0700223 }
Tony Barbourea968902015-07-29 14:26:21 -0600224
225 while((rtn_value = RegEnumValue(key, idx++, name, &name_size, NULL, NULL, (LPBYTE) &value, &value_size)) == ERROR_SUCCESS) {
226 if (value_size == sizeof(value) && value == 0) {
227 if (out == NULL) {
228 out = malloc(total_size);
229 out[0] = '\0';
230 }
231 else if (strlen(out) + name_size + 1 > total_size) {
232 out = realloc(out, total_size * 2);
233 total_size *= 2;
234 }
235 if (out == NULL) {
236 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory, failed loader_get_registry_files");
237 return NULL;
238 }
239 if (strlen(out) == 0)
240 snprintf(out, name_size + 1, "%s", name);
241 else
242 snprintf(out + strlen(out), name_size + 2, "%c%s", PATH_SEPERATOR, name);
243 }
244 name_size = 2048;
245 }
246 loc = next;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700247 }
Tony Barbourea968902015-07-29 14:26:21 -0600248
Jon Ashburnffad94d2015-06-30 14:46:22 -0700249 return out;
250}
251
Ian Elliott4470a302015-02-17 10:33:47 -0700252#endif // WIN32
253
Jon Ashburnc7237a72015-08-03 09:08:46 -0600254/**
255 * Given string of three part form "maj.min.pat" convert to a vulkan version
256 * number.
257 */
258static uint32_t loader_make_version(const char *vers_str)
259{
260 uint32_t vers = 0, major, minor, patch;
261 char *minor_str= NULL;
262 char *patch_str = NULL;
263 char *cstr;
264 char *str;
265
266 if (!vers_str)
267 return vers;
268 cstr = loader_stack_alloc(strlen(vers_str) + 1);
269 strcpy(cstr, vers_str);
270 while ((str = strchr(cstr, '.')) != NULL) {
271 if (minor_str == NULL) {
272 minor_str = str + 1;
273 *str = '\0';
274 major = atoi(cstr);
275 }
276 else if (patch_str == NULL) {
277 patch_str = str + 1;
278 *str = '\0';
279 minor = atoi(minor_str);
280 }
281 else {
282 return vers;
283 }
284 cstr = str + 1;
285 }
286 patch = atoi(patch_str);
287
288 return VK_MAKE_VERSION(major, minor, patch);
289
290}
291
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600292bool compare_vk_extension_properties(const VkExtensionProperties *op1, const VkExtensionProperties *op2)
293{
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600294 return strcmp(op1->extName, op2->extName) == 0 ? true : false;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600295}
296
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -0600297/**
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600298 * Search the given ext_array for an extension
299 * matching the given vk_ext_prop
300 */
301bool has_vk_extension_property_array(
302 const VkExtensionProperties *vk_ext_prop,
303 const uint32_t count,
304 const VkExtensionProperties *ext_array)
305{
306 for (uint32_t i = 0; i < count; i++) {
307 if (compare_vk_extension_properties(vk_ext_prop, &ext_array[i]))
308 return true;
309 }
310 return false;
311}
312
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -0600313/**
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600314 * Search the given ext_list for an extension
315 * matching the given vk_ext_prop
316 */
317bool has_vk_extension_property(
318 const VkExtensionProperties *vk_ext_prop,
319 const struct loader_extension_list *ext_list)
320{
321 for (uint32_t i = 0; i < ext_list->count; i++) {
322 if (compare_vk_extension_properties(&ext_list->list[i].info, vk_ext_prop))
323 return true;
324 }
325 return false;
326}
327
Jon Ashburnb2ef1372015-07-16 17:19:31 -0600328static inline bool loader_is_layer_type_device(const enum layer_type type) {
329 if ((type & VK_LAYER_TYPE_DEVICE_EXPLICIT) ||
330 (type & VK_LAYER_TYPE_DEVICE_IMPLICIT))
331 return true;
332 return false;
333}
334
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600335/*
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -0600336 * Search the given layer list for a layer matching the given layer name
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600337 */
Jon Ashburne13ecc92015-08-03 17:19:30 -0600338static struct loader_layer_properties *loader_get_layer_property(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600339 const char *name,
340 const struct loader_layer_list *layer_list)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600341{
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600342 for (uint32_t i = 0; i < layer_list->count; i++) {
343 const VkLayerProperties *item = &layer_list->list[i].info;
344 if (strcmp(name, item->layerName) == 0)
345 return &layer_list->list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600346 }
347 return NULL;
348}
349
Jon Ashburne13ecc92015-08-03 17:19:30 -0600350/**
351 * Get the next unused layer property in the list. Init the property to zero.
352 */
353static struct loader_layer_properties *loader_get_next_layer_property(
354 struct loader_layer_list *layer_list)
355{
356 if (layer_list->capacity == 0) {
357 layer_list->list = malloc(sizeof(struct loader_layer_properties) * 64);
358 if (layer_list->list == NULL) {
359 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't add any layer properties to list");
360 return NULL;
361 }
362 memset(layer_list->list, 0, sizeof(struct loader_layer_properties) * 64);
363 layer_list->capacity = sizeof(struct loader_layer_properties) * 64;
364 }
365
366 // ensure enough room to add an entry
367 if ((layer_list->count + 1) * sizeof (struct loader_layer_properties)
368 > layer_list->capacity) {
369 layer_list->list = realloc(layer_list->list, layer_list->capacity * 2);
370 if (layer_list->list == NULL) {
371 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
372 "realloc failed for layer list");
373 }
374 layer_list->capacity *= 2;
375 }
376
377 layer_list->count++;
378 return &(layer_list->list[layer_list->count - 1]);
379}
380
381/**
382 * Remove all layer properties entrys from the list
383 */
384static void loader_delete_layer_properties(struct loader_layer_list *layer_list)
385{
386 uint32_t i;
387
388 //TODO make sure everything is cleaned up properly
389 for (i = 0; i < layer_list->count; i++) {
390 if (layer_list->list[i].lib_info.lib_name != NULL)
391 free(layer_list->list[i].lib_info.lib_name);
392 loader_destroy_ext_list(&layer_list->list[i].instance_extension_list);
393 loader_destroy_ext_list(&layer_list->list[i].device_extension_list);
394 layer_list->list[i].lib_info.lib_name = NULL;
395 }
396 layer_list->count = 0;
397
398 layer_list->capacity = 0;
399 free(layer_list->list);
400
401}
402
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600403static void loader_add_global_extensions(
Tony Barbour59a47322015-06-24 16:06:58 -0600404 const PFN_vkGetGlobalExtensionProperties fp_get_props,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600405 const char *lib_name,
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600406 const loader_platform_dl_handle lib_handle,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600407 const enum extension_origin origin,
408 struct loader_extension_list *ext_list)
409{
410 uint32_t i, count;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600411 struct loader_extension_property ext_props;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600412 VkExtensionProperties *extension_properties;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600413 VkResult res;
414
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -0600415 if (!fp_get_props) {
416 /* No GetGlobalExtensionProperties defined */
417 return;
418 }
419
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600420 res = fp_get_props(NULL, &count, NULL);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600421 if (res != VK_SUCCESS) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600422 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extension count from %s", lib_name);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600423 return;
424 }
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600425
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -0600426 if (count == 0) {
427 /* No ExtensionProperties to report */
428 return;
429 }
430
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600431 extension_properties = loader_stack_alloc(count * sizeof(VkExtensionProperties));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600432
433 res = fp_get_props(NULL, &count, extension_properties);
434 if (res != VK_SUCCESS) {
435 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extensions from %s", lib_name);
436 return;
437 }
Tony Barbour59a47322015-06-24 16:06:58 -0600438
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600439 for (i = 0; i < count; i++) {
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600440 memset(&ext_props, 0, sizeof(ext_props));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600441 memcpy(&ext_props.info, &extension_properties[i], sizeof(VkExtensionProperties));
442 //TODO eventually get this from the layer config file
443 ext_props.origin = origin;
444 ext_props.lib_name = lib_name;
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600445
Courtney Goeltzenleuchter53043732015-07-12 13:20:05 -0600446 char spec_version[64];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600447
448 snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
449 VK_MAJOR(ext_props.info.specVersion),
450 VK_MINOR(ext_props.info.specVersion),
451 VK_PATCH(ext_props.info.specVersion));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600452
453 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter53043732015-07-12 13:20:05 -0600454 "Global Extension: %s (%s) version %s",
455 ext_props.info.extName, lib_name, spec_version);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600456 loader_add_to_ext_list(ext_list, 1, &ext_props);
457 }
458
459 return;
460}
461
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600462static void loader_add_physical_device_extensions(
463 PFN_vkGetPhysicalDeviceExtensionProperties get_phys_dev_ext_props,
464 VkPhysicalDevice physical_device,
465 const enum extension_origin origin,
466 const char *lib_name,
467 struct loader_extension_list *ext_list)
468{
469 uint32_t i, count;
470 VkResult res;
471 struct loader_extension_property ext_props;
472 VkExtensionProperties *extension_properties;
473
474 memset(&ext_props, 0, sizeof(ext_props));
475 ext_props.origin = origin;
476 ext_props.lib_name = lib_name;
477
478 if (get_phys_dev_ext_props) {
479 res = get_phys_dev_ext_props(physical_device, NULL, &count, NULL);
480 if (res == VK_SUCCESS && count > 0) {
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600481
482 extension_properties = loader_stack_alloc(count * sizeof(VkExtensionProperties));
483
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600484 res = get_phys_dev_ext_props(physical_device, NULL, &count, extension_properties);
485 for (i = 0; i < count; i++) {
Courtney Goeltzenleuchter53043732015-07-12 13:20:05 -0600486 char spec_version[64];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600487
488 memcpy(&ext_props.info, &extension_properties[i], sizeof(VkExtensionProperties));
489
490 snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
491 VK_MAJOR(ext_props.info.specVersion),
492 VK_MINOR(ext_props.info.specVersion),
493 VK_PATCH(ext_props.info.specVersion));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600494
495 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter53043732015-07-12 13:20:05 -0600496 "PhysicalDevice Extension: %s (%s) version %s",
497 ext_props.info.extName, lib_name, spec_version);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600498 loader_add_to_ext_list(ext_list, 1, &ext_props);
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600499 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600500 } else {
501 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 -0600502 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600503 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600504
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600505 return;
506}
507
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600508static bool loader_init_ext_list(struct loader_extension_list *ext_info)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600509{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600510 ext_info->capacity = 32 * sizeof(struct loader_extension_property);
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600511 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600512 ext_info->list = malloc(ext_info->capacity);
513 if (ext_info->list == NULL) {
514 return false;
515 }
516 memset(ext_info->list, 0, ext_info->capacity);
517 ext_info->count = 0;
518 return true;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600519}
520
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -0600521void loader_destroy_ext_list(struct loader_extension_list *ext_info)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600522{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600523 free(ext_info->list);
524 ext_info->count = 0;
525 ext_info->capacity = 0;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600526}
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600527
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600528/**
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600529 * Search the given search_list for any layers in the props list.
530 * Add these to the output layer_list. Don't add duplicates to the output layer_list.
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600531 */
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -0600532static VkResult loader_add_layer_names_to_list(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600533 struct loader_layer_list *output_list,
534 uint32_t name_count,
535 const char * const *names,
536 const struct loader_layer_list *search_list)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600537{
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600538 struct loader_layer_properties *layer_prop;
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -0600539 VkResult err = VK_SUCCESS;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600540
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600541 for (uint32_t i = 0; i < name_count; i++) {
542 const char *search_target = names[i];
Jon Ashburne13ecc92015-08-03 17:19:30 -0600543 layer_prop = loader_get_layer_property(search_target, search_list);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600544 if (!layer_prop) {
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -0600545 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Unable to find layer %s", search_target);
546 err = VK_ERROR_INVALID_LAYER;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600547 continue;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600548 }
549
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600550 loader_add_to_layer_list(output_list, 1, layer_prop);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600551 }
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -0600552
553 return err;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600554}
555
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600556/*
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -0600557 * Append non-duplicate extension properties defined in props
558 * to the given ext_list.
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600559 */
560void loader_add_to_ext_list(
561 struct loader_extension_list *ext_list,
562 uint32_t prop_list_count,
563 const struct loader_extension_property *props)
564{
565 uint32_t i;
566 struct loader_extension_property *cur_ext;
567
568 if (ext_list->list == NULL || ext_list->capacity == 0) {
569 loader_init_ext_list(ext_list);
570 }
571
572 if (ext_list->list == NULL)
573 return;
574
575 for (i = 0; i < prop_list_count; i++) {
576 cur_ext = (struct loader_extension_property *) &props[i];
577
578 // look for duplicates
579 if (has_vk_extension_property(&cur_ext->info, ext_list)) {
580 continue;
581 }
582
583 // add to list at end
584 // check for enough capacity
585 if (ext_list->count * sizeof(struct loader_extension_property)
586 >= ext_list->capacity) {
587 // double capacity
588 ext_list->capacity *= 2;
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600589 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600590 ext_list->list = realloc(ext_list->list, ext_list->capacity);
591 }
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600592
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600593 memcpy(&ext_list->list[ext_list->count], cur_ext, sizeof(struct loader_extension_property));
594 ext_list->count++;
595 }
596}
597
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600598/*
599 * Manage lists of VkLayerProperties
600 */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600601static bool loader_init_layer_list(struct loader_layer_list *list)
602{
603 list->capacity = 32 * sizeof(struct loader_layer_properties);
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600604 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600605 list->list = malloc(list->capacity);
606 if (list->list == NULL) {
607 return false;
608 }
609 memset(list->list, 0, list->capacity);
610 list->count = 0;
611 return true;
612}
613
614void loader_destroy_layer_list(struct loader_layer_list *layer_list)
615{
616 free(layer_list->list);
617 layer_list->count = 0;
618 layer_list->capacity = 0;
619}
620
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600621/*
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600622 * Manage list of layer libraries (loader_lib_info)
623 */
624static bool loader_init_layer_library_list(struct loader_layer_library_list *list)
625{
626 list->capacity = 32 * sizeof(struct loader_lib_info);
627 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
628 list->list = malloc(list->capacity);
629 if (list->list == NULL) {
630 return false;
631 }
632 memset(list->list, 0, list->capacity);
633 list->count = 0;
634 return true;
635}
636
637void loader_destroy_layer_library_list(struct loader_layer_library_list *list)
638{
639 for (uint32_t i = 0; i < list->count; i++) {
640 free(list->list[i].lib_name);
641 }
642 free(list->list);
643 list->count = 0;
644 list->capacity = 0;
645}
646
647void loader_add_to_layer_library_list(
648 struct loader_layer_library_list *list,
649 uint32_t item_count,
650 const struct loader_lib_info *new_items)
651{
652 uint32_t i;
653 struct loader_lib_info *item;
654
655 if (list->list == NULL || list->capacity == 0) {
656 loader_init_layer_library_list(list);
657 }
658
659 if (list->list == NULL)
660 return;
661
662 for (i = 0; i < item_count; i++) {
663 item = (struct loader_lib_info *) &new_items[i];
664
665 // look for duplicates
666 for (uint32_t j = 0; j < list->count; j++) {
667 if (strcmp(list->list[i].lib_name, new_items->lib_name) == 0) {
668 continue;
669 }
670 }
671
672 // add to list at end
673 // check for enough capacity
674 if (list->count * sizeof(struct loader_lib_info)
675 >= list->capacity) {
676 // double capacity
677 list->capacity *= 2;
678 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
679 list->list = realloc(list->list, list->capacity);
680 }
681
682 memcpy(&list->list[list->count], item, sizeof(struct loader_lib_info));
683 list->count++;
684 }
685}
686
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600687
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -0600688/*
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600689 * Search the given layer list for a list
690 * matching the given VkLayerProperties
691 */
692bool has_vk_layer_property(
693 const VkLayerProperties *vk_layer_prop,
694 const struct loader_layer_list *list)
695{
696 for (uint32_t i = 0; i < list->count; i++) {
697 if (strcmp(vk_layer_prop->layerName, list->list[i].info.layerName) == 0)
698 return true;
699 }
700 return false;
701}
702
703/*
704 * Search the given layer list for a layer
705 * matching the given name
706 */
707bool has_layer_name(
708 const char *name,
709 const struct loader_layer_list *list)
710{
711 for (uint32_t i = 0; i < list->count; i++) {
712 if (strcmp(name, list->list[i].info.layerName) == 0)
713 return true;
714 }
715 return false;
716}
717
718/*
719 * Append non-duplicate layer properties defined in prop_list
720 * to the given layer_info list
721 */
722void loader_add_to_layer_list(
723 struct loader_layer_list *list,
724 uint32_t prop_list_count,
725 const struct loader_layer_properties *props)
726{
727 uint32_t i;
728 struct loader_layer_properties *layer;
729
730 if (list->list == NULL || list->capacity == 0) {
731 loader_init_layer_list(list);
732 }
733
734 if (list->list == NULL)
735 return;
736
737 for (i = 0; i < prop_list_count; i++) {
738 layer = (struct loader_layer_properties *) &props[i];
739
740 // look for duplicates
741 if (has_vk_layer_property(&layer->info, list)) {
742 continue;
743 }
744
745 // add to list at end
746 // check for enough capacity
747 if (list->count * sizeof(struct loader_layer_properties)
748 >= list->capacity) {
749 // double capacity
750 list->capacity *= 2;
751 list->list = realloc(list->list, list->capacity);
752 }
753
754 memcpy(&list->list[list->count], layer, sizeof(struct loader_layer_properties));
755 list->count++;
756 }
757}
758
Jon Ashburnbd332cc2015-07-07 10:27:45 -0600759/**
760 * Search the search_list for any layer with a name
761 * that matches the given name and a type that matches the given type
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600762 * Add all matching layers to the found_list
Jon Ashburnbd332cc2015-07-07 10:27:45 -0600763 * Do not add if found loader_layer_properties is already
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600764 * on the found_list.
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600765 */
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600766static void loader_find_layer_name_add_list(
767 const char *name,
Jon Ashburnbd332cc2015-07-07 10:27:45 -0600768 const enum layer_type type,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600769 const struct loader_layer_list *search_list,
770 struct loader_layer_list *found_list)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600771{
772 for (uint32_t i = 0; i < search_list->count; i++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600773 struct loader_layer_properties *layer_prop = &search_list->list[i];
Jon Ashburnbd332cc2015-07-07 10:27:45 -0600774 if (0 == strcmp(layer_prop->info.layerName, name) &&
775 (layer_prop->type & type)) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600776 /* Found a layer with the same name, add to found_list */
777 loader_add_to_layer_list(found_list, 1, layer_prop);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600778 }
779 }
780}
781
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -0600782static struct loader_extension_property *get_extension_property(
783 const char *name,
784 const struct loader_extension_list *list)
Jon Ashburnfc2e38c2015-04-14 09:15:32 -0600785{
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -0600786 for (uint32_t i = 0; i < list->count; i++) {
787 const VkExtensionProperties *item = &list->list[i].info;
788 if (strcmp(name, item->extName) == 0)
789 return &list->list[i];
Jon Ashburnfc2e38c2015-04-14 09:15:32 -0600790 }
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -0600791 return NULL;
Jon Ashburnfc2e38c2015-04-14 09:15:32 -0600792}
793
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600794/*
795 * For global exenstions implemented within the loader (i.e. DEBUG_REPORT
796 * the extension must provide two entry points for the loader to use:
797 * - "trampoline" entry point - this is the address returned by GetProcAddr
798 * and will always do what's necessary to support a global call.
799 * - "terminator" function - this function will be put at the end of the
800 * instance chain and will contain the necessary logica to call / process
801 * the extension for the appropriate ICDs that are available.
802 * There is no generic mechanism for including these functions, the references
803 * must be placed into the appropriate loader entry points.
804 * GetInstanceProcAddr: call extension GetInstanceProcAddr to check for GetProcAddr requests
805 * loader_coalesce_extensions(void) - add extension records to the list of global
806 * extension available to the app.
807 * instance_disp - add function pointer for terminator function to this array.
808 * The extension itself should be in a separate file that will be
809 * linked directly with the loader.
810 */
Jon Ashburn27cd5842015-05-12 17:26:48 -0600811void loader_coalesce_extensions(void)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600812{
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600813 struct loader_scanned_icds *icd_list = loader.scanned_icd_list;
814
815 // traverse scanned icd list adding non-duplicate extensions to the list
816 while (icd_list != NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600817 loader_add_to_ext_list(&loader.global_extensions,
818 icd_list->global_extension_list.count,
819 icd_list->global_extension_list.list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600820 icd_list = icd_list->next;
821 };
822
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600823 // Traverse loader's extensions, adding non-duplicate extensions to the list
Ian Elliottd3ef02f2015-07-06 14:36:13 -0600824 wsi_swapchain_add_instance_extensions(&loader.global_extensions);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600825 debug_report_add_instance_extensions(&loader.global_extensions);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600826}
827
Jon Ashburndc6fcad2015-06-10 10:06:06 -0600828static struct loader_icd *loader_get_icd_and_device(const VkDevice device,
829 struct loader_device **found_dev)
830{
831 *found_dev = NULL;
832 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
833 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
834 for (struct loader_device *dev = icd->logical_device_list; dev; dev = dev->next)
835 if (dev->device == device) {
836 *found_dev = dev;
837 return icd;
838 }
839 }
840 }
841 return NULL;
842}
843
844static void loader_destroy_logical_device(struct loader_device *dev)
845{
846 free(dev->app_extension_props);
Jon Ashburndc6fcad2015-06-10 10:06:06 -0600847 if (dev->activated_layer_list.count)
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600848 loader_destroy_layer_list(&dev->activated_layer_list);
Jon Ashburndc6fcad2015-06-10 10:06:06 -0600849 free(dev);
850}
851
852static struct loader_device *loader_add_logical_device(const VkDevice dev, struct loader_device **device_list)
853{
854 struct loader_device *new_dev;
855
856 new_dev = malloc(sizeof(struct loader_device));
857 if (!new_dev) {
858 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc struct laoder-device");
859 return NULL;
860 }
861
862 memset(new_dev, 0, sizeof(struct loader_device));
863
864 new_dev->next = *device_list;
865 new_dev->device = dev;
866 *device_list = new_dev;
867 return new_dev;
868}
869
870void loader_remove_logical_device(VkDevice device)
871{
872 struct loader_device *found_dev, *dev, *prev_dev;
873 struct loader_icd *icd;
874 icd = loader_get_icd_and_device(device, &found_dev);
875
876 if (!icd || !found_dev)
877 return;
878
879 prev_dev = NULL;
880 dev = icd->logical_device_list;
881 while (dev && dev != found_dev) {
882 prev_dev = dev;
883 dev = dev->next;
884 }
885
886 if (prev_dev)
887 prev_dev->next = found_dev->next;
888 else
889 icd->logical_device_list = found_dev->next;
890 loader_destroy_logical_device(found_dev);
891}
892
893
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600894static void loader_icd_destroy(
895 struct loader_instance *ptr_inst,
896 struct loader_icd *icd)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800897{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600898 ptr_inst->total_icd_count--;
Jon Ashburn128f9422015-05-28 19:16:58 -0600899 free(icd->gpus);
Courtney Goeltzenleuchter1f157ac2015-06-14 19:57:15 -0600900 for (struct loader_device *dev = icd->logical_device_list; dev; ) {
901 struct loader_device *next_dev = dev->next;
Jon Ashburndc6fcad2015-06-10 10:06:06 -0600902 loader_destroy_logical_device(dev);
Courtney Goeltzenleuchter1f157ac2015-06-14 19:57:15 -0600903 dev = next_dev;
904 }
Jon Ashburndc6fcad2015-06-10 10:06:06 -0600905
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800906 free(icd);
907}
908
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600909static struct loader_icd * loader_icd_create(const struct loader_scanned_icds *scanned)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800910{
911 struct loader_icd *icd;
912
913 icd = malloc(sizeof(*icd));
914 if (!icd)
915 return NULL;
916
Courtney Goeltzenleuchter55001bb2014-10-28 10:29:27 -0600917 memset(icd, 0, sizeof(*icd));
918
Jon Ashburn46d1f582015-01-28 11:01:35 -0700919 icd->scanned_icds = scanned;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800920
921 return icd;
922}
923
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600924static struct loader_icd *loader_icd_add(
925 struct loader_instance *ptr_inst,
926 const struct loader_scanned_icds *scanned)
Chia-I Wu13a61a52014-08-04 11:18:20 +0800927{
928 struct loader_icd *icd;
929
Jon Ashburn46d1f582015-01-28 11:01:35 -0700930 icd = loader_icd_create(scanned);
Chia-I Wu13a61a52014-08-04 11:18:20 +0800931 if (!icd)
932 return NULL;
933
Chia-I Wu13a61a52014-08-04 11:18:20 +0800934 /* prepend to the list */
Jon Ashburn46888392015-01-29 15:45:51 -0700935 icd->next = ptr_inst->icds;
936 ptr_inst->icds = icd;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600937 ptr_inst->total_icd_count++;
Chia-I Wu13a61a52014-08-04 11:18:20 +0800938
939 return icd;
940}
941
Jon Ashburn46d1f582015-01-28 11:01:35 -0700942static void loader_scanned_icd_add(const char *filename)
943{
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700944 loader_platform_dl_handle handle;
Tony Barbour1d2cd3f2015-07-03 10:33:54 -0600945 PFN_vkCreateInstance fp_create_inst;
946 PFN_vkGetGlobalExtensionProperties fp_get_global_ext_props;
Jon Ashburnc624c882015-07-16 10:17:29 -0600947 PFN_vkGetInstanceProcAddr fp_get_proc_addr;
Jon Ashburn46d1f582015-01-28 11:01:35 -0700948 struct loader_scanned_icds *new_node;
949
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700950 // Used to call: dlopen(filename, RTLD_LAZY);
951 handle = loader_platform_open_library(filename);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700952 if (!handle) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600953 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_open_library_error(filename));
Jon Ashburn46d1f582015-01-28 11:01:35 -0700954 return;
955 }
956
Jon Ashburnc624c882015-07-16 10:17:29 -0600957#define LOOKUP_LD(func_ptr, func) do { \
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600958 func_ptr = (PFN_vk ##func) loader_platform_get_proc_address(handle, "vk" #func); \
Jon Ashburn46d1f582015-01-28 11:01:35 -0700959 if (!func_ptr) { \
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600960 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
Jon Ashburn46d1f582015-01-28 11:01:35 -0700961 return; \
962 } \
963} while (0)
964
Jon Ashburnc624c882015-07-16 10:17:29 -0600965 LOOKUP_LD(fp_get_proc_addr, GetInstanceProcAddr);
966 LOOKUP_LD(fp_create_inst, CreateInstance);
967 LOOKUP_LD(fp_get_global_ext_props, GetGlobalExtensionProperties);
968
969#undef LOOKUP_LD
Jon Ashburn46d1f582015-01-28 11:01:35 -0700970
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600971 new_node = (struct loader_scanned_icds *) malloc(sizeof(struct loader_scanned_icds)
972 + strlen(filename) + 1);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700973 if (!new_node) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600974 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
Jon Ashburn46d1f582015-01-28 11:01:35 -0700975 return;
976 }
977
978 new_node->handle = handle;
Jon Ashburnc624c882015-07-16 10:17:29 -0600979 new_node->GetInstanceProcAddr = fp_get_proc_addr;
Jon Ashburn46888392015-01-29 15:45:51 -0700980 new_node->CreateInstance = fp_create_inst;
Tony Barbour59a47322015-06-24 16:06:58 -0600981 new_node->GetGlobalExtensionProperties = fp_get_global_ext_props;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600982 loader_init_ext_list(&new_node->global_extension_list);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600983 loader_init_ext_list(&new_node->device_extension_list);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700984 new_node->next = loader.scanned_icd_list;
Jon Ashburn46d1f582015-01-28 11:01:35 -0700985
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600986 new_node->lib_name = (char *) (new_node + 1);
987 if (!new_node->lib_name) {
988 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
989 return;
990 }
991 strcpy(new_node->lib_name, filename);
992
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600993 loader.scanned_icd_list = new_node;
994
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600995 loader_add_global_extensions(
Tony Barbour59a47322015-06-24 16:06:58 -0600996 (PFN_vkGetGlobalExtensionProperties) fp_get_global_ext_props,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600997 new_node->lib_name,
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600998 handle,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600999 VK_EXTENSION_ORIGIN_ICD,
1000 &new_node->global_extension_list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001001}
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001002
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001003static struct loader_extension_list *loader_global_extensions(const char *pLayerName)
1004{
1005 if (pLayerName == NULL || (strlen(pLayerName) == 0)) {
1006 return &loader.global_extensions;
1007 }
1008
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06001009 /* Find and return global extension list for given layer */
Jon Ashburnb2ef1372015-07-16 17:19:31 -06001010 for (uint32_t i = 0; i < loader.scanned_instance_layers.count; i++) {
1011 struct loader_layer_properties *props = &loader.scanned_instance_layers.list[i];
1012 if (strcmp(props->info.layerName, pLayerName) == 0) {
1013 return &props->instance_extension_list;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001014 }
1015 }
1016
1017 return NULL;
1018}
1019
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001020
1021static void loader_physical_device_extensions(
1022 struct loader_icd *icd,
1023 uint32_t gpu_idx,
1024 const char *layer_name,
1025 uint32_t *count,
1026 struct loader_extension_list **list)
1027{
Tony Barbourb5d2c942015-07-14 13:34:05 -06001028 *count = 0;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001029 if (layer_name == NULL || (strlen(layer_name) == 0)) {
1030 *count = icd->device_extension_cache[gpu_idx].count;
1031 *list = &icd->device_extension_cache[gpu_idx];
1032 return;
1033 }
Jon Ashburnb2ef1372015-07-16 17:19:31 -06001034 for (uint32_t i = 0; i < loader.scanned_device_layers.count; i++) {
1035 struct loader_layer_properties *props = &(loader.scanned_device_layers.list[i]);
1036 if ((strcmp(layer_name, props->info.layerName) == 0)) {
1037 *count = props->device_extension_list.count;
1038 *list = &props->device_extension_list;
Courtney Goeltzenleuchtercc44f2a2015-07-10 10:11:50 -06001039 break;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001040 }
1041 }
1042}
1043
Jon Ashburnc624c882015-07-16 10:17:29 -06001044static bool loader_icd_init_entrys(struct loader_icd *icd,
1045 VkInstance inst,
1046 const PFN_vkGetInstanceProcAddr fp_gipa)
Jon Ashburn3da71f22015-05-14 12:43:38 -06001047{
1048 /* initialize entrypoint function pointers */
1049
Jon Ashburnc624c882015-07-16 10:17:29 -06001050 #define LOOKUP_GIPA(func, required) do { \
1051 icd->func = (PFN_vk ##func) fp_gipa(inst, "vk" #func); \
1052 if (!icd->func && required) { \
1053 loader_log(VK_DBG_REPORT_WARN_BIT, 0, \
1054 loader_platform_get_proc_address_error("vk" #func)); \
1055 return false; \
1056 } \
Jon Ashburn3da71f22015-05-14 12:43:38 -06001057 } while (0)
1058
Jon Ashburnc624c882015-07-16 10:17:29 -06001059 LOOKUP_GIPA(GetDeviceProcAddr, true);
1060 LOOKUP_GIPA(DestroyInstance, true);
1061 LOOKUP_GIPA(EnumeratePhysicalDevices, true);
1062 LOOKUP_GIPA(GetPhysicalDeviceFeatures, true);
1063 LOOKUP_GIPA(GetPhysicalDeviceFormatProperties, true);
Jon Ashburn754864f2015-07-23 18:49:07 -06001064 LOOKUP_GIPA(GetPhysicalDeviceImageFormatProperties, true);
Jon Ashburnc624c882015-07-16 10:17:29 -06001065 LOOKUP_GIPA(GetPhysicalDeviceLimits, true);
1066 LOOKUP_GIPA(CreateDevice, true);
1067 LOOKUP_GIPA(GetPhysicalDeviceProperties, true);
1068 LOOKUP_GIPA(GetPhysicalDeviceMemoryProperties, true);
1069 LOOKUP_GIPA(GetPhysicalDeviceQueueCount, true);
1070 LOOKUP_GIPA(GetPhysicalDeviceQueueProperties, true);
1071 LOOKUP_GIPA(GetPhysicalDeviceExtensionProperties, true);
1072 LOOKUP_GIPA(GetPhysicalDeviceSparseImageFormatProperties, true);
1073 LOOKUP_GIPA(DbgCreateMsgCallback, false);
1074 LOOKUP_GIPA(DbgDestroyMsgCallback, false);
1075 LOOKUP_GIPA(GetPhysicalDeviceSurfaceSupportWSI, false);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001076
Jon Ashburnc624c882015-07-16 10:17:29 -06001077#undef LOOKUP_GIPA
Ian Elliottd3ef02f2015-07-06 14:36:13 -06001078
Jon Ashburnc624c882015-07-16 10:17:29 -06001079 return true;
Jon Ashburn3da71f22015-05-14 12:43:38 -06001080}
1081
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001082static void loader_debug_init(void)
1083{
1084 const char *env;
1085
1086 if (g_loader_debug > 0)
1087 return;
1088
1089 g_loader_debug = 0;
1090
1091 /* parse comma-separated debug options */
Courtney Goeltzenleuchterfce60db2015-07-29 09:08:22 -06001092 env = getenv("VK_LOADER_DEBUG");
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001093 while (env) {
1094 const char *p = strchr(env, ',');
1095 size_t len;
1096
1097 if (p)
1098 len = p - env;
1099 else
1100 len = strlen(env);
1101
1102 if (len > 0) {
1103 if (strncmp(env, "warn", len) == 0) {
1104 g_loader_debug |= LOADER_WARN_BIT;
1105 g_loader_log_msgs |= VK_DBG_REPORT_WARN_BIT;
1106 } else if (strncmp(env, "info", len) == 0) {
1107 g_loader_debug |= LOADER_INFO_BIT;
1108 g_loader_log_msgs |= VK_DBG_REPORT_INFO_BIT;
1109 } else if (strncmp(env, "perf", len) == 0) {
1110 g_loader_debug |= LOADER_PERF_BIT;
1111 g_loader_log_msgs |= VK_DBG_REPORT_PERF_WARN_BIT;
1112 } else if (strncmp(env, "error", len) == 0) {
1113 g_loader_debug |= LOADER_ERROR_BIT;
1114 g_loader_log_msgs |= VK_DBG_REPORT_ERROR_BIT;
1115 } else if (strncmp(env, "debug", len) == 0) {
1116 g_loader_debug |= LOADER_DEBUG_BIT;
1117 g_loader_log_msgs |= VK_DBG_REPORT_DEBUG_BIT;
1118 }
1119 }
1120
1121 if (!p)
1122 break;
1123
1124 env = p + 1;
1125 }
1126}
1127
Jon Ashburn2077e382015-06-29 11:25:34 -06001128struct loader_manifest_files {
1129 uint32_t count;
1130 char **filename_list;
1131};
1132
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001133/**
Jon Ashburn2077e382015-06-29 11:25:34 -06001134 * Get next file or dirname given a string list or registry key path
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001135 *
1136 * \returns
Jon Ashburn2077e382015-06-29 11:25:34 -06001137 * A pointer to first char in the next path.
1138 * The next path (or NULL) in the list is returned in next_path.
1139 * Note: input string is modified in some cases. PASS IN A COPY!
1140 */
Jon Ashburn2077e382015-06-29 11:25:34 -06001141static char *loader_get_next_path(char *path)
1142{
1143 uint32_t len;
1144 char *next;
1145
1146 if (path == NULL)
1147 return NULL;
1148 next = strchr(path, PATH_SEPERATOR);
1149 if (next == NULL) {
1150 len = (uint32_t) strlen(path);
1151 next = path + len;
1152 }
1153 else {
1154 *next = '\0';
1155 next++;
1156 }
1157
1158 return next;
1159}
1160
1161/**
Jon Ashburn15315172015-07-07 15:06:25 -06001162 * Given a path which is absolute or relative. Expand the path if relative otherwise
1163 * leave the path unmodified if absolute. The path which is relative from is
1164 * given in rel_base and should include trailing directory seperator '/'
1165 *
1166 * \returns
1167 * A string in out_fullpath of the full absolute path
1168 * Side effect is that dir string maybe modified.
1169 */
1170static void loader_expand_path(const char *path,
1171 const char *rel_base,
1172 size_t out_size,
1173 char *out_fullpath)
1174{
1175 if (loader_platform_is_path_absolute(path)) {
1176 strncpy(out_fullpath, path, out_size);
1177 out_fullpath[out_size - 1] = '\0';
1178 }
1179 else {
1180 // convert relative to absolute path based on rel_base
1181 size_t len = strlen(path);
1182 strncpy(out_fullpath, rel_base, out_size);
1183 out_fullpath[out_size - 1] = '\0';
1184 assert(out_size >= strlen(out_fullpath) + len + 1);
1185 strncat(out_fullpath, path, len);
1186 }
1187}
1188
1189/**
Jon Ashburn2077e382015-06-29 11:25:34 -06001190 * Given a filename (file) and a list of paths (dir), try to find an existing
1191 * file in the paths. If filename already is a path then no
1192 * searching in the given paths.
1193 *
1194 * \returns
1195 * A string in out_fullpath of either the full path or file.
1196 * Side effect is that dir string maybe modified.
1197 */
1198static void loader_get_fullpath(const char *file,
1199 char *dir,
1200 size_t out_size,
1201 char *out_fullpath)
1202{
1203 char *next_dir;
1204 if (strchr(file,DIRECTORY_SYMBOL) == NULL) {
1205 //find file exists with prepending given path
1206 while (*dir) {
1207 next_dir = loader_get_next_path(dir);
1208 snprintf(out_fullpath, out_size, "%s%c%s",
1209 dir, DIRECTORY_SYMBOL, file);
1210 if (loader_platform_file_exists(out_fullpath)) {
1211 return;
1212 }
1213 dir = next_dir;
1214 }
1215 }
1216 snprintf(out_fullpath, out_size, "%s", file);
1217}
1218
1219/**
1220 * Read a JSON file into a buffer.
1221 *
1222 * \returns
1223 * A pointer to a cJSON object representing the JSON parse tree.
1224 * This returned buffer should be freed by caller.
1225 */
1226static cJSON *loader_get_json(const char *filename)
1227{
1228 FILE *file;
1229 char *json_buf;
1230 cJSON *json;
1231 uint64_t len;
1232 file = fopen(filename,"rb");
1233 fseek(file, 0, SEEK_END);
1234 len = ftell(file);
1235 fseek(file, 0, SEEK_SET);
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -06001236 json_buf = (char*) loader_stack_alloc(len+1);
Jon Ashburn2077e382015-06-29 11:25:34 -06001237 if (json_buf == NULL) {
1238 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get JSON file");
1239 fclose(file);
1240 return NULL;
1241 }
1242 if (fread(json_buf, sizeof(char), len, file) != len) {
1243 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "fread failed can't get JSON file");
1244 fclose(file);
1245 return NULL;
1246 }
1247 fclose(file);
1248 json_buf[len] = '\0';
1249
1250 //parse text from file
1251 json = cJSON_Parse(json_buf);
1252 if (json == NULL)
1253 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Can't parse JSON file %s", filename);
1254 return json;
1255}
1256
1257/**
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001258 * Given a cJSON struct (json) of the top level JSON object from layer manifest
1259 * file, add entry to the layer_list.
Jon Ashburne13ecc92015-08-03 17:19:30 -06001260 * Fill out the layer_properties in this list entry from the input cJSON object.
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001261 *
1262 * \returns
1263 * void
1264 * layer_list has a new entry and initialized accordingly.
1265 * If the json input object does not have all the required fields no entry
1266 * is added to the list.
1267 */
Jon Ashburnb2ef1372015-07-16 17:19:31 -06001268static void loader_add_layer_properties(struct loader_layer_list *layer_instance_list,
1269 struct loader_layer_list *layer_device_list,
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001270 cJSON *json,
1271 bool is_implicit,
1272 char *filename)
1273{
1274 /* Fields in layer manifest file that are required:
1275 * (required) “file_format_version”
1276 * following are required in the "layer" object:
1277 * (required) "name"
1278 * (required) "type"
1279 * (required) “library_path”
1280 * (required) “abi_versions”
1281 * (required) “implementation_version”
1282 * (required) “description”
1283 * (required for implicit layers) “disable_environment”
1284 *
1285 * First get all required items and if any missing abort
1286 */
1287
1288 cJSON *item, *layer_node, *ext_item;
1289 char *temp;
1290 char *name, *type, *library_path, *abi_versions;
1291 char *implementation_version, *description;
1292 cJSON *disable_environment;
1293 int i;
1294 struct loader_extension_property ext_prop;
1295 item = cJSON_GetObjectItem(json, "file_format_version");
1296 if (item == NULL) {
1297 return;
1298 }
1299 char *file_vers = cJSON_PrintUnformatted(item);
1300 loader_log(VK_DBG_REPORT_INFO_BIT, 0, "Found manifest file %s, version %s",
1301 filename, file_vers);
1302 if (strcmp(file_vers, "\"0.9.0\"") != 0)
Jon Ashburne13ecc92015-08-03 17:19:30 -06001303 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unexpected manifest file version (expected 0.9.0), may cause errors");
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001304 free(file_vers);
1305
Jon Ashburnc7237a72015-08-03 09:08:46 -06001306 //TODO handle freeing the allocations: disable_env , enable_env, GIPA, GDPA, library_path
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001307 //TODO handle multiple layer nodes in the file
1308 //TODO handle scanned libraries not one per layer property
1309 layer_node = cJSON_GetObjectItem(json, "layer");
1310 if (layer_node == NULL) {
1311 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"layer\" object in manifest JSON file, skipping");
1312 return;
1313 }
1314#define GET_JSON_OBJECT(node, var) { \
1315 var = cJSON_GetObjectItem(node, #var); \
1316 if (var == NULL) \
1317 return; \
1318 }
1319#define GET_JSON_ITEM(node, var) { \
1320 item = cJSON_GetObjectItem(node, #var); \
1321 if (item == NULL) \
1322 return; \
1323 temp = cJSON_Print(item); \
1324 temp[strlen(temp) - 1] = '\0'; \
1325 var = malloc(strlen(temp) + 1); \
1326 strcpy(var, &temp[1]); \
1327 free(temp); \
1328 }
1329 GET_JSON_ITEM(layer_node, name)
1330 GET_JSON_ITEM(layer_node, type)
1331 GET_JSON_ITEM(layer_node, library_path)
1332 GET_JSON_ITEM(layer_node, abi_versions)
1333 GET_JSON_ITEM(layer_node, implementation_version)
1334 GET_JSON_ITEM(layer_node, description)
1335 if (is_implicit) {
1336 GET_JSON_OBJECT(layer_node, disable_environment)
1337 }
1338#undef GET_JSON_ITEM
1339#undef GET_JSON_OBJECT
1340
Jon Ashburnb2ef1372015-07-16 17:19:31 -06001341 // add list entry
1342 struct loader_layer_properties *props;
1343 if (!strcmp(type, "DEVICE")) {
Jon Ashburne13ecc92015-08-03 17:19:30 -06001344 props = loader_get_next_layer_property(layer_device_list);
Jon Ashburnb2ef1372015-07-16 17:19:31 -06001345 props->type = (is_implicit) ? VK_LAYER_TYPE_DEVICE_IMPLICIT : VK_LAYER_TYPE_DEVICE_EXPLICIT;
1346 }
1347 if (!strcmp(type, "INSTANCE")) {
Jon Ashburne13ecc92015-08-03 17:19:30 -06001348 props = loader_get_next_layer_property(layer_instance_list);
Jon Ashburnb2ef1372015-07-16 17:19:31 -06001349 props->type = (is_implicit) ? VK_LAYER_TYPE_INSTANCE_IMPLICIT : VK_LAYER_TYPE_INSTANCE_EXPLICIT;
Jon Ashburnb2ef1372015-07-16 17:19:31 -06001350 }
1351 if (!strcmp(type, "GLOBAL")) {
Jon Ashburne13ecc92015-08-03 17:19:30 -06001352 props = loader_get_next_layer_property(layer_instance_list);
Jon Ashburnb2ef1372015-07-16 17:19:31 -06001353 props->type = (is_implicit) ? VK_LAYER_TYPE_GLOBAL_IMPLICIT : VK_LAYER_TYPE_GLOBAL_EXPLICIT;
1354 }
1355 free(type);
1356
Jon Ashburn15315172015-07-07 15:06:25 -06001357 strncpy(props->info.layerName, name, sizeof(props->info.layerName));
1358 props->info.layerName[sizeof(props->info.layerName) - 1] = '\0';
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001359 free(name);
Jon Ashburn15315172015-07-07 15:06:25 -06001360
Jon Ashburn15315172015-07-07 15:06:25 -06001361 char *fullpath = malloc(2048);
1362 char *rel_base;
1363 if (strchr(library_path, DIRECTORY_SYMBOL) == NULL) {
1364 // a filename which is assumed in the system directory
Jon Ashburn5e1f63d2015-07-09 14:06:55 -06001365 char *def_path = loader_stack_alloc(strlen(DEFAULT_VK_LAYERS_PATH) + 1);
1366 strcpy(def_path, DEFAULT_VK_LAYERS_PATH);
1367 loader_get_fullpath(library_path, def_path, 2048, fullpath);
Jon Ashburn15315172015-07-07 15:06:25 -06001368 }
1369 else {
1370 // a relative or absolute path
1371 char *name_copy = loader_stack_alloc(strlen(filename) + 2);
1372 size_t len;
1373 strcpy(name_copy, filename);
1374 rel_base = loader_platform_dirname(name_copy);
1375 len = strlen(rel_base);
1376 rel_base[len] = DIRECTORY_SYMBOL;
1377 rel_base[len + 1] = '\0';
1378 loader_expand_path(library_path, rel_base, 2048, fullpath);
1379 }
1380 props->lib_info.lib_name = fullpath;
Jon Ashburnc7237a72015-08-03 09:08:46 -06001381 props->info.specVersion = loader_make_version(abi_versions);
1382 props->info.implVersion = loader_make_version(implementation_version);
1383 free(abi_versions);
1384 free(implementation_version);
Courtney Goeltzenleuchter53043732015-07-12 13:20:05 -06001385 strncpy((char *) props->info.description, description, sizeof(props->info.description));
Jon Ashburn15315172015-07-07 15:06:25 -06001386 props->info.description[sizeof(props->info.description) - 1] = '\0';
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001387 free(description);
1388 if (is_implicit) {
1389 props->disable_env_var.name = disable_environment->child->string;
1390 props->disable_env_var.value = disable_environment->child->valuestring;
1391 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001392
1393 /**
1394 * Now get all optional items and objects and put in list:
1395 * functions
1396 * instance_extensions
1397 * device_extensions
1398 * enable_environment (implicit layers only)
1399 */
1400#define GET_JSON_OBJECT(node, var) { \
1401 var = cJSON_GetObjectItem(node, #var); \
1402 }
1403#define GET_JSON_ITEM(node, var) { \
1404 item = cJSON_GetObjectItem(node, #var); \
1405 if (item != NULL) \
1406 temp = cJSON_Print(item); \
1407 temp[strlen(temp) - 1] = '\0'; \
1408 var = malloc(strlen(temp) + 1); \
1409 strcpy(var, &temp[1]); \
1410 free(temp); \
1411 }
1412
1413 cJSON *instance_extensions, *device_extensions, *functions, *enable_environment;
1414 char *vkGetInstanceProcAddr, *vkGetDeviceProcAddr, *version;
1415 GET_JSON_OBJECT(layer_node, functions)
1416 if (functions != NULL) {
1417 GET_JSON_ITEM(functions, vkGetInstanceProcAddr)
1418 GET_JSON_ITEM(functions, vkGetDeviceProcAddr)
1419 props->functions.str_gipa = vkGetInstanceProcAddr;
1420 props->functions.str_gdpa = vkGetDeviceProcAddr;
1421 }
1422 GET_JSON_OBJECT(layer_node, instance_extensions)
1423 if (instance_extensions != NULL) {
1424 int count = cJSON_GetArraySize(instance_extensions);
1425 for (i = 0; i < count; i++) {
1426 ext_item = cJSON_GetArrayItem(instance_extensions, i);
1427 GET_JSON_ITEM(ext_item, name)
1428 GET_JSON_ITEM(ext_item, version)
1429 ext_prop.origin = VK_EXTENSION_ORIGIN_LAYER;
1430 ext_prop.lib_name = library_path;
1431 strcpy(ext_prop.info.extName, name);
Jon Ashburnc7237a72015-08-03 09:08:46 -06001432 ext_prop.info.specVersion = loader_make_version(version);
1433 free(version);
1434 free(name);
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001435 loader_add_to_ext_list(&props->instance_extension_list, 1, &ext_prop);
1436 }
1437 }
1438 GET_JSON_OBJECT(layer_node, device_extensions)
1439 if (device_extensions != NULL) {
1440 int count = cJSON_GetArraySize(device_extensions);
1441 for (i = 0; i < count; i++) {
1442 ext_item = cJSON_GetArrayItem(device_extensions, i);
1443 GET_JSON_ITEM(ext_item, name);
1444 GET_JSON_ITEM(ext_item, version);
1445 ext_prop.origin = VK_EXTENSION_ORIGIN_LAYER;
1446 ext_prop.lib_name = library_path;
1447 strcpy(ext_prop.info.extName, name);
Jon Ashburnc7237a72015-08-03 09:08:46 -06001448 ext_prop.info.specVersion = loader_make_version(version);
1449 free(version);
1450 free(name);
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001451 loader_add_to_ext_list(&props->device_extension_list, 1, &ext_prop);
1452 }
1453 }
1454 if (is_implicit) {
1455 GET_JSON_OBJECT(layer_node, enable_environment)
1456 props->enable_env_var.name = enable_environment->child->string;
1457 props->enable_env_var.value = enable_environment->child->valuestring;
1458 }
1459#undef GET_JSON_ITEM
1460#undef GET_JSON_OBJECT
Jon Ashburnb2ef1372015-07-16 17:19:31 -06001461 // for global layers need to add them to both device and instance list
1462 if (props->type & (VK_LAYER_TYPE_GLOBAL_IMPLICIT | VK_LAYER_TYPE_GLOBAL_EXPLICIT)) {
Jon Ashburne13ecc92015-08-03 17:19:30 -06001463 struct loader_layer_properties *dev_props;
1464 dev_props = loader_get_next_layer_property(layer_device_list);
Jon Ashburnb2ef1372015-07-16 17:19:31 -06001465 //copy into device layer list
Jon Ashburne13ecc92015-08-03 17:19:30 -06001466 memcpy(dev_props, props, sizeof(*props));
Jon Ashburnb2ef1372015-07-16 17:19:31 -06001467 }
1468
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001469}
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) {
Jon Ashburn3b78e462015-07-31 10:11:24 -06001534 loc = loader_stack_alloc(strlen(location) + 1);
Jon Ashburnffad94d2015-06-30 14:46:22 -07001535 if (loc == NULL) {
1536 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1537 return;
1538 }
1539 strcpy(loc, location);
Jon Ashburn24265ac2015-07-31 09:33:21 -06001540#if defined (_WIN32)
1541 loc = loader_get_registry_files(loc);
1542 if (loc == NULL) {
1543 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Registry lookup failed can't get manifest files");
1544 return;
1545 }
Jon Ashburnffad94d2015-06-30 14:46:22 -07001546#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06001547 }
Jon Ashburnffad94d2015-06-30 14:46:22 -07001548 else {
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -06001549 loc = loader_stack_alloc(strlen(override) + 1);
Jon Ashburnffad94d2015-06-30 14:46:22 -07001550 if (loc == NULL) {
1551 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1552 return;
1553 }
1554 strcpy(loc, override);
1555 }
Jon Ashburn2077e382015-06-29 11:25:34 -06001556
Liam Middlebrook9b14e892015-07-23 18:32:20 -07001557 // Print out the paths being searched if debugging is enabled
Jon Ashburn46e20d82015-07-31 09:41:31 -06001558 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Searching the following paths for manifest files: %s\n", loc);
Liam Middlebrook9b14e892015-07-23 18:32:20 -07001559
Jon Ashburn2077e382015-06-29 11:25:34 -06001560 file = loc;
1561 while (*file) {
1562 next_file = loader_get_next_path(file);
Jon Ashburnffad94d2015-06-30 14:46:22 -07001563 if (list_is_dirs) {
Jon Ashburn2077e382015-06-29 11:25:34 -06001564 sysdir = opendir(file);
1565 name = NULL;
1566 if (sysdir) {
1567 dent = readdir(sysdir);
1568 if (dent == NULL)
1569 break;
1570 name = &(dent->d_name[0]);
1571 loader_get_fullpath(name, file, sizeof(full_path), full_path);
1572 name = full_path;
1573 }
1574 }
1575 else {
Jon Ashburnffad94d2015-06-30 14:46:22 -07001576#if defined(__linux__)
1577 // only Linux has relative paths
Jon Ashburn2077e382015-06-29 11:25:34 -06001578 char *dir;
1579 // make a copy of location so it isn't modified
1580 dir = alloca(strlen(location) + 1);
1581 if (dir == NULL) {
1582 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1583 return;
1584 }
1585 strcpy(dir, location);
1586
1587 loader_get_fullpath(file, dir, sizeof(full_path), full_path);
1588
1589 name = full_path;
Jon Ashburnffad94d2015-06-30 14:46:22 -07001590#else // WIN32
1591 name = file;
1592#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06001593 }
1594 while (name) {
1595 /* Look for files ending with ".json" suffix */
1596 uint32_t nlen = (uint32_t) strlen(name);
1597 const char *suf = name + nlen - 5;
1598 if ((nlen > 5) && !strncmp(suf, ".json", 5)) {
1599 if (out_files->count == 0) {
1600 out_files->filename_list = malloc(alloced_count * sizeof(char *));
1601 }
1602 else if (out_files->count == alloced_count) {
1603 out_files->filename_list = realloc(out_files->filename_list,
1604 alloced_count * sizeof(char *) * 2);
1605 alloced_count *= 2;
1606 }
1607 if (out_files->filename_list == NULL) {
1608 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't alloc manifest file list");
1609 return;
1610 }
1611 out_files->filename_list[out_files->count] = malloc(strlen(name) + 1);
1612 if (out_files->filename_list[out_files->count] == NULL) {
1613 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1614 return;
1615 }
1616 strcpy(out_files->filename_list[out_files->count], name);
1617 out_files->count++;
Jon Ashburnf70f3612015-07-02 10:08:47 -06001618 } else if (!list_is_dirs) {
1619 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 -06001620 }
Jon Ashburnffad94d2015-06-30 14:46:22 -07001621 if (list_is_dirs) {
Jon Ashburn2077e382015-06-29 11:25:34 -06001622 dent = readdir(sysdir);
1623 if (dent == NULL)
1624 break;
1625 name = &(dent->d_name[0]);
1626 loader_get_fullpath(name, file, sizeof(full_path), full_path);
1627 name = full_path;
1628 }
1629 else {
1630 break;
1631 }
1632 }
1633 if (sysdir)
1634 closedir(sysdir);
1635 file = next_file;
1636 }
1637 return;
1638}
1639
1640/**
1641 * Try to find the Vulkan ICD driver(s).
1642 *
1643 * This function scans the default system loader path(s) or path
1644 * specified by the \c VK_ICD_FILENAMES environment variable in
1645 * order to find loadable VK ICDs manifest files. From these
1646 * manifest files it finds the ICD libraries.
1647 *
1648 * \returns
Jon Ashburn3a37aee2015-06-30 16:44:28 -06001649 * void
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001650 */
Jon Ashburn27cd5842015-05-12 17:26:48 -06001651void loader_icd_scan(void)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001652{
Jon Ashburn2077e382015-06-29 11:25:34 -06001653 char *file_str;
1654 struct loader_manifest_files manifest_files;
1655
Jon Ashburn6301a0f2015-05-29 13:15:39 -06001656
1657 // convenient place to initialize a mutex
1658 loader_platform_thread_create_mutex(&loader_lock);
1659
Jon Ashburn2077e382015-06-29 11:25:34 -06001660 // convenient place to initialize logging
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001661 loader_debug_init();
1662
Jon Ashburn2077e382015-06-29 11:25:34 -06001663 // Get a list of manifest files for ICDs
1664 loader_get_manifest_files("VK_ICD_FILENAMES", false, DEFAULT_VK_DRIVERS_INFO,
1665 &manifest_files);
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001666 if (manifest_files.count == 0)
1667 return;
Jon Ashburn2077e382015-06-29 11:25:34 -06001668 for (uint32_t i = 0; i < manifest_files.count; i++) {
1669 file_str = manifest_files.filename_list[i];
1670 if (file_str == NULL)
1671 continue;
1672
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001673 cJSON *json;
Jon Ashburn2077e382015-06-29 11:25:34 -06001674 json = loader_get_json(file_str);
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001675 cJSON *item;
1676 item = cJSON_GetObjectItem(json, "file_format_version");
1677 if (item == NULL)
1678 return;
1679 char *file_vers = cJSON_Print(item);
1680 loader_log(VK_DBG_REPORT_INFO_BIT, 0, "Found manifest file %s, version %s",
1681 file_str, file_vers);
1682 if (strcmp(file_vers, "\"1.0.0\"") != 0)
1683 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unexpected manifest file version (expected 1.0.0), may cause errors");
1684 free(file_vers);
1685 item = cJSON_GetObjectItem(json, "ICD");
1686 if (item != NULL) {
1687 item = cJSON_GetObjectItem(item, "library_path");
1688 if (item != NULL) {
1689 char *icd_filename = cJSON_PrintUnformatted(item);
Jon Ashburn2077e382015-06-29 11:25:34 -06001690 char *icd_file = icd_filename;
1691 if (icd_filename != NULL) {
Jon Ashburn2077e382015-06-29 11:25:34 -06001692 char def_dir[] = DEFAULT_VK_DRIVERS_PATH;
1693 char *dir = def_dir;
Liam Middlebrook9b14e892015-07-23 18:32:20 -07001694
1695 // Print out the paths being searched if debugging is enabled
1696 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Searching for ICD drivers named %s at %s\n", icd_file, dir);
1697
Jon Ashburn2077e382015-06-29 11:25:34 -06001698 // strip off extra quotes
1699 if (icd_filename[strlen(icd_filename) - 1] == '"')
1700 icd_filename[strlen(icd_filename) - 1] = '\0';
1701 if (icd_filename[0] == '"')
1702 icd_filename++;
Jon Ashburnffad94d2015-06-30 14:46:22 -07001703#if defined(__linux__)
1704 char full_path[2048];
Jon Ashburn2077e382015-06-29 11:25:34 -06001705 loader_get_fullpath(icd_filename, dir, sizeof(full_path), full_path);
1706 loader_scanned_icd_add(full_path);
Jon Ashburnffad94d2015-06-30 14:46:22 -07001707#else // WIN32
1708 loader_scanned_icd_add(icd_filename);
1709#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06001710 free(icd_file);
1711 }
1712 }
1713 else
1714 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"library_path\" in ICD JSON file %s, skipping", file_str);
1715 }
1716 else
1717 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"ICD\" object in ICD JSON file %s, skipping", file_str);
1718
1719 free(file_str);
1720 cJSON_Delete(json);
1721 }
1722 free(manifest_files.filename_list);
1723
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001724}
1725
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001726
Jon Ashburn5ef20602015-07-02 09:40:15 -06001727void loader_layer_scan(void)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001728{
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001729 char *file_str;
1730 struct loader_manifest_files manifest_files;
1731 cJSON *json;
1732 uint32_t i;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001733
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001734 // Get a list of manifest files for layers
1735 loader_get_manifest_files(LAYERS_PATH_ENV, true, DEFAULT_VK_LAYERS_INFO,
1736 &manifest_files);
1737 if (manifest_files.count == 0)
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -07001738 return;
Jon Ashburn90c6a0e2015-06-04 15:30:58 -06001739
Jon Ashburne13ecc92015-08-03 17:19:30 -06001740#if 0 //TODO
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001741 /**
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06001742 * We need a list of the layer libraries, not just a list of
1743 * the layer properties (a layer library could expose more than
1744 * one layer property). This list of scanned layers would be
1745 * used to check for global and physicaldevice layer properties.
1746 */
1747 if (!loader_init_layer_library_list(&loader.scanned_layer_libraries)) {
1748 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1749 "Malloc for layer list failed: %s line: %d", __FILE__, __LINE__);
1750 return;
Jon Ashburn5ef20602015-07-02 09:40:15 -06001751 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001752#endif
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001753
Jon Ashburne13ecc92015-08-03 17:19:30 -06001754 /* cleanup any previously scanned libraries */
1755 loader_delete_layer_properties(&loader.scanned_instance_layers);
1756 loader_delete_layer_properties(&loader.scanned_device_layers);
Jon Ashburnb2ef1372015-07-16 17:19:31 -06001757
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001758
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001759 for (i = 0; i < manifest_files.count; i++) {
1760 file_str = manifest_files.filename_list[i];
1761 if (file_str == NULL)
1762 continue;
Courtney Goeltzenleuchtera9e4af42015-06-01 14:49:17 -06001763
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001764 // parse file into JSON struct
1765 json = loader_get_json(file_str);
1766 if (!json) {
1767 continue;
1768 }
Jon Ashburne13ecc92015-08-03 17:19:30 -06001769
1770
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001771 //TODO pass in implicit versus explicit bool
Jon Ashburnb2ef1372015-07-16 17:19:31 -06001772 //TODO error if device layers expose instance_extensions
1773 //TODO error if instance layers expose device extensions
1774 loader_add_layer_properties(&loader.scanned_instance_layers,
1775 &loader.scanned_device_layers,
1776 json,
1777 false,
1778 file_str);
1779
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06001780
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001781 free(file_str);
1782 cJSON_Delete(json);
1783 }
1784 free(manifest_files.filename_list);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001785
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001786}
1787
Courtney Goeltzenleuchter2d3ba632015-07-12 14:35:22 -06001788static PFN_vkVoidFunction VKAPI loader_gpa_instance_internal(VkInstance inst, const char * pName)
Jon Ashburn27cd5842015-05-12 17:26:48 -06001789{
1790 // inst is not wrapped
1791 if (inst == VK_NULL_HANDLE) {
1792 return NULL;
1793 }
1794 VkLayerInstanceDispatchTable* disp_table = * (VkLayerInstanceDispatchTable **) inst;
1795 void *addr;
1796
Jon Ashburn8fd08252015-05-28 16:25:02 -06001797 if (!strcmp(pName, "vkGetInstanceProcAddr"))
1798 return (void *) loader_gpa_instance_internal;
1799
Jon Ashburn27cd5842015-05-12 17:26:48 -06001800 if (disp_table == NULL)
1801 return NULL;
1802
1803 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001804 if (addr) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06001805 return addr;
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001806 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001807
1808 if (disp_table->GetInstanceProcAddr == NULL) {
1809 return NULL;
1810 }
1811 return disp_table->GetInstanceProcAddr(inst, pName);
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001812}
1813
Jon Ashburn128f9422015-05-28 19:16:58 -06001814struct loader_icd * loader_get_icd(const VkPhysicalDevice gpu, uint32_t *gpu_index)
Jon Ashburn876b1ac2014-10-17 15:09:07 -06001815{
Jon Ashburn128f9422015-05-28 19:16:58 -06001816
Tony Barbourb5d2c942015-07-14 13:34:05 -06001817 *gpu_index = 0;
Jon Ashburn98bd4542015-01-29 16:44:24 -07001818 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
1819 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
1820 for (uint32_t i = 0; i < icd->gpu_count; i++)
Jon Ashburn128f9422015-05-28 19:16:58 -06001821 if (icd->gpus[i] == gpu) {
Jon Ashburn98bd4542015-01-29 16:44:24 -07001822 *gpu_index = i;
1823 return icd;
1824 }
1825 }
Jon Ashburn876b1ac2014-10-17 15:09:07 -06001826 }
1827 return NULL;
1828}
1829
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001830static loader_platform_dl_handle loader_add_layer_lib(
Jon Ashburn4f67d742015-05-27 13:19:22 -06001831 const char *chain_type,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001832 struct loader_layer_properties *layer_prop)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001833{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001834 struct loader_lib_info *new_layer_lib_list, *my_lib;
1835
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06001836 /*
1837 * TODO: We can now track this information in the
1838 * scanned_layer_libraries list.
1839 */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001840 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001841 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, layer_prop->lib_info.lib_name) == 0) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001842 /* Have already loaded this library, just increment ref count */
1843 loader.loaded_layer_lib_list[i].ref_count++;
Courtney Goeltzenleuchterca8c81a2015-06-14 11:59:07 -06001844 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001845 "%s Chain: Increment layer reference count for layer library %s",
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001846 chain_type, layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001847 return loader.loaded_layer_lib_list[i].lib_handle;
1848 }
1849 }
1850
1851 /* Haven't seen this library so load it */
1852 new_layer_lib_list = realloc(loader.loaded_layer_lib_list,
1853 (loader.loaded_layer_lib_count + 1) * sizeof(struct loader_lib_info));
1854 if (!new_layer_lib_list) {
1855 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1856 return NULL;
1857 }
1858
1859 my_lib = &new_layer_lib_list[loader.loaded_layer_lib_count];
1860
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001861 /* NOTE: We require that the layer property be immutable */
1862 my_lib->lib_name = (char *) layer_prop->lib_info.lib_name;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001863 my_lib->ref_count = 0;
1864 my_lib->lib_handle = NULL;
1865
1866 if ((my_lib->lib_handle = loader_platform_open_library(my_lib->lib_name)) == NULL) {
1867 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1868 loader_platform_open_library_error(my_lib->lib_name));
1869 return NULL;
1870 } else {
Courtney Goeltzenleuchterca8c81a2015-06-14 11:59:07 -06001871 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001872 "Chain: %s: Loading layer library %s",
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001873 chain_type, layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001874 }
1875 loader.loaded_layer_lib_count++;
1876 loader.loaded_layer_lib_list = new_layer_lib_list;
1877 my_lib->ref_count++;
1878
1879 return my_lib->lib_handle;
1880}
1881
1882static void loader_remove_layer_lib(
1883 struct loader_instance *inst,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001884 struct loader_layer_properties *layer_prop)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001885{
1886 uint32_t idx;
Tony Barbourb5d2c942015-07-14 13:34:05 -06001887 struct loader_lib_info *new_layer_lib_list, *my_lib = NULL;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001888
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001889 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001890 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, layer_prop->lib_info.lib_name) == 0) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001891 /* found matching library */
1892 idx = i;
1893 my_lib = &loader.loaded_layer_lib_list[i];
1894 break;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001895 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001896 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001897
Tony Barbourb5d2c942015-07-14 13:34:05 -06001898 if (my_lib) {
1899 my_lib->ref_count--;
1900 if (my_lib->ref_count > 0) {
1901 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
1902 "Decrement reference count for layer library %s", layer_prop->lib_info.lib_name);
1903 return;
1904 }
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001905 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001906 loader_platform_close_library(my_lib->lib_handle);
Courtney Goeltzenleuchterca8c81a2015-06-14 11:59:07 -06001907 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001908 "Unloading layer library %s", layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001909
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001910 /* Need to remove unused library from list */
1911 new_layer_lib_list = malloc((loader.loaded_layer_lib_count - 1) * sizeof(struct loader_lib_info));
1912 if (!new_layer_lib_list) {
1913 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1914 return;
1915 }
1916
1917 if (idx > 0) {
1918 /* Copy records before idx */
1919 memcpy(new_layer_lib_list, &loader.loaded_layer_lib_list[0],
1920 sizeof(struct loader_lib_info) * idx);
1921 }
1922 if (idx < (loader.loaded_layer_lib_count - 1)) {
1923 /* Copy records after idx */
1924 memcpy(&new_layer_lib_list[idx], &loader.loaded_layer_lib_list[idx+1],
1925 sizeof(struct loader_lib_info) * (loader.loaded_layer_lib_count - idx - 1));
1926 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001927
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001928 free(loader.loaded_layer_lib_list);
1929 loader.loaded_layer_lib_count--;
1930 loader.loaded_layer_lib_list = new_layer_lib_list;
Jon Ashburnb8358052014-11-18 09:06:04 -07001931}
1932
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06001933
1934/**
1935 * Go through the search_list and find any layers which match type. If layer
1936 * type match is found in then add it to ext_list.
1937 */
1938//TODO need to handle implict layer enable env var and disable env var
Jon Ashburn0c26e712015-07-02 16:10:32 -06001939static void loader_add_layer_implicit(
1940 const enum layer_type type,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001941 struct loader_layer_list *list,
1942 struct loader_layer_list *search_list)
Jon Ashburn0c26e712015-07-02 16:10:32 -06001943{
1944 uint32_t i;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001945 for (i = 0; i < search_list->count; i++) {
1946 const struct loader_layer_properties *prop = &search_list->list[i];
Jon Ashburn0c26e712015-07-02 16:10:32 -06001947 if (prop->type & type) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001948 /* Found an layer with the same type, add to layer_list */
1949 loader_add_to_layer_list(list, 1, prop);
Jon Ashburn0c26e712015-07-02 16:10:32 -06001950 }
1951 }
1952
1953}
1954
1955/**
1956 * Get the layer name(s) from the env_name environment variable. If layer
Jon Ashburnbd332cc2015-07-07 10:27:45 -06001957 * is found in search_list then add it to layer_list. But only add it to
1958 * layer_list if type matches.
Jon Ashburn0c26e712015-07-02 16:10:32 -06001959 */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001960static void loader_add_layer_env(
Jon Ashburnbd332cc2015-07-07 10:27:45 -06001961 const enum layer_type type,
Jon Ashburneb6d5682015-07-02 14:10:53 -06001962 const char *env_name,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001963 struct loader_layer_list *layer_list,
1964 const struct loader_layer_list *search_list)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001965{
Ian Elliott4470a302015-02-17 10:33:47 -07001966 char *layerEnv;
Jon Ashburneb6d5682015-07-02 14:10:53 -06001967 char *next, *name;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001968
Jon Ashburneb6d5682015-07-02 14:10:53 -06001969 layerEnv = getenv(env_name);
Ian Elliott4470a302015-02-17 10:33:47 -07001970 if (layerEnv == NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001971 return;
Ian Elliott4470a302015-02-17 10:33:47 -07001972 }
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -06001973 name = loader_stack_alloc(strlen(layerEnv) + 1);
Jon Ashburneb6d5682015-07-02 14:10:53 -06001974 if (name == NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001975 return;
Ian Elliott4470a302015-02-17 10:33:47 -07001976 }
Jon Ashburneb6d5682015-07-02 14:10:53 -06001977 strcpy(name, layerEnv);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001978
Jon Ashburneb6d5682015-07-02 14:10:53 -06001979 while (name && *name ) {
1980 next = loader_get_next_path(name);
Jon Ashburnbd332cc2015-07-07 10:27:45 -06001981 loader_find_layer_name_add_list(name, type, search_list, layer_list);
Jon Ashburneb6d5682015-07-02 14:10:53 -06001982 name = next;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001983 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001984
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001985 return;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001986}
1987
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -06001988void loader_deactivate_instance_layers(struct loader_instance *instance)
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001989{
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001990 if (!instance->activated_layer_list.count) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001991 return;
1992 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001993
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001994 /* Create instance chain of enabled layers */
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -06001995 for (uint32_t i = 0; i < instance->activated_layer_list.count; i++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001996 struct loader_layer_properties *layer_prop = &instance->activated_layer_list.list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001997
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001998 loader_remove_layer_lib(instance, layer_prop);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001999 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002000 loader_destroy_layer_list(&instance->activated_layer_list);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002001}
2002
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002003VkResult loader_enable_instance_layers(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002004 struct loader_instance *inst,
2005 const VkInstanceCreateInfo *pCreateInfo)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002006{
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002007 VkResult err;
2008
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002009 if (inst == NULL)
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002010 return VK_ERROR_UNKNOWN;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002011
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002012 if (!loader_init_layer_list(&inst->activated_layer_list)) {
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002013 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance activated layer list");
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002014 return VK_ERROR_OUT_OF_HOST_MEMORY;
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002015 }
2016
Jon Ashburn0c26e712015-07-02 16:10:32 -06002017 /* Add any implicit layers first */
2018 loader_add_layer_implicit(
2019 VK_LAYER_TYPE_INSTANCE_IMPLICIT,
2020 &inst->activated_layer_list,
Jon Ashburnb2ef1372015-07-16 17:19:31 -06002021 &loader.scanned_instance_layers);
Jon Ashburn0c26e712015-07-02 16:10:32 -06002022
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002023 /* Add any layers specified via environment variable next */
Jon Ashburneb6d5682015-07-02 14:10:53 -06002024 loader_add_layer_env(
Jon Ashburnbd332cc2015-07-07 10:27:45 -06002025 VK_LAYER_TYPE_INSTANCE_EXPLICIT,
Jon Ashburneb6d5682015-07-02 14:10:53 -06002026 "VK_INSTANCE_LAYERS",
2027 &inst->activated_layer_list,
Jon Ashburnb2ef1372015-07-16 17:19:31 -06002028 &loader.scanned_instance_layers);
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002029
2030 /* Add layers specified by the application */
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002031 err = loader_add_layer_names_to_list(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002032 &inst->activated_layer_list,
2033 pCreateInfo->layerCount,
2034 pCreateInfo->ppEnabledLayerNames,
Jon Ashburnb2ef1372015-07-16 17:19:31 -06002035 &loader.scanned_instance_layers);
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002036
2037 return err;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002038}
2039
Jon Ashburn27cd5842015-05-12 17:26:48 -06002040uint32_t loader_activate_instance_layers(struct loader_instance *inst)
2041{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002042 uint32_t layer_idx;
Jon Ashburn128f9422015-05-28 19:16:58 -06002043 VkBaseLayerObject *wrappedInstance;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002044
David Pinedoa0a8a242015-06-24 15:29:18 -06002045 if (inst == NULL) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06002046 return 0;
David Pinedoa0a8a242015-06-24 15:29:18 -06002047 }
Jon Ashburn27cd5842015-05-12 17:26:48 -06002048
2049 // NOTE inst is unwrapped at this point in time
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06002050 void* baseObj = (void*) inst;
2051 void* nextObj = (void*) inst;
Jon Ashburn27cd5842015-05-12 17:26:48 -06002052 VkBaseLayerObject *nextInstObj;
2053 PFN_vkGetInstanceProcAddr nextGPA = loader_gpa_instance_internal;
2054
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002055 if (!inst->activated_layer_list.count) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06002056 return 0;
2057 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002058
Courtney Goeltzenleuchter6f460c52015-07-06 09:04:55 -06002059 wrappedInstance = loader_stack_alloc(sizeof(VkBaseLayerObject)
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002060 * inst->activated_layer_list.count);
Jon Ashburn128f9422015-05-28 19:16:58 -06002061 if (!wrappedInstance) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002062 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance objects for layer");
2063 return 0;
2064 }
2065
2066 /* Create instance chain of enabled layers */
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002067 layer_idx = inst->activated_layer_list.count - 1;
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06002068 for (int32_t i = inst->activated_layer_list.count - 1; i >= 0; i--) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002069 struct loader_layer_properties *layer_prop = &inst->activated_layer_list.list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002070 loader_platform_dl_handle lib_handle;
2071
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002072 /*
Courtney Goeltzenleuchteree3b16a2015-06-01 14:12:42 -06002073 * Note: An extension's Get*ProcAddr should not return a function pointer for
2074 * any extension entry points until the extension has been enabled.
2075 * To do this requires a different behavior from Get*ProcAddr functions implemented
2076 * in layers.
2077 * The very first call to a layer will be it's Get*ProcAddr function requesting
2078 * the layer's vkGet*ProcAddr. The layer should intialize it's internal dispatch table
2079 * with the wrapped object given (either Instance or Device) and return the layer's
2080 * Get*ProcAddr function. The layer should also use this opportunity to record the
2081 * baseObject so that it can find the correct local dispatch table on future calls.
2082 * Subsequent calls to Get*ProcAddr, CreateInstance, CreateDevice
2083 * will not use a wrapped object and must look up their local dispatch table from
2084 * the given baseObject.
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002085 */
Jon Ashburn128f9422015-05-28 19:16:58 -06002086 nextInstObj = (wrappedInstance + layer_idx);
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06002087 nextInstObj->pGPA = (PFN_vkGPA) nextGPA;
Jon Ashburn27cd5842015-05-12 17:26:48 -06002088 nextInstObj->baseObject = baseObj;
2089 nextInstObj->nextObject = nextObj;
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06002090 nextObj = (void*) nextInstObj;
Jon Ashburn27cd5842015-05-12 17:26:48 -06002091
2092 char funcStr[256];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002093 snprintf(funcStr, 256, "%sGetInstanceProcAddr", layer_prop->info.layerName);
2094 lib_handle = loader_add_layer_lib("instance", layer_prop);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002095 if ((nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
2096 nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
Jon Ashburn27cd5842015-05-12 17:26:48 -06002097 if (!nextGPA) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002098 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 -06002099
2100 /* TODO: Should we return nextObj, nextGPA to previous? */
Jon Ashburn27cd5842015-05-12 17:26:48 -06002101 continue;
2102 }
2103
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002104 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002105 "Insert instance layer %s (%s)",
2106 layer_prop->info.layerName,
2107 layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002108
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002109 layer_idx--;
Jon Ashburn27cd5842015-05-12 17:26:48 -06002110 }
2111
Jon Ashburn8fd08252015-05-28 16:25:02 -06002112 loader_init_instance_core_dispatch_table(inst->disp, nextGPA, (VkInstance) nextObj, (VkInstance) baseObj);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002113
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002114 return inst->activated_layer_list.count;
Jon Ashburn27cd5842015-05-12 17:26:48 -06002115}
2116
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002117void loader_activate_instance_layer_extensions(struct loader_instance *inst)
2118{
2119
2120 loader_init_instance_extension_dispatch_table(inst->disp,
2121 inst->disp->GetInstanceProcAddr,
Jon Ashburn128f9422015-05-28 19:16:58 -06002122 (VkInstance) inst);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002123}
2124
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002125static VkResult loader_enable_device_layers(
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06002126 struct loader_icd *icd,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002127 struct loader_device *dev,
2128 const VkDeviceCreateInfo *pCreateInfo)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002129{
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002130 VkResult err;
2131
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002132 if (dev == NULL)
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002133 return VK_ERROR_UNKNOWN;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002134
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002135 if (dev->activated_layer_list.list == NULL || dev->activated_layer_list.capacity == 0) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002136 loader_init_layer_list(&dev->activated_layer_list);
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002137 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002138
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002139 if (dev->activated_layer_list.list == NULL) {
2140 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc device activated layer list");
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002141 return VK_ERROR_OUT_OF_HOST_MEMORY;
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002142 }
2143
Jon Ashburn0c26e712015-07-02 16:10:32 -06002144 /* Add any implicit layers first */
2145 loader_add_layer_implicit(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002146 VK_LAYER_TYPE_DEVICE_IMPLICIT,
2147 &dev->activated_layer_list,
Jon Ashburnb2ef1372015-07-16 17:19:31 -06002148 &loader.scanned_device_layers);
Jon Ashburn0c26e712015-07-02 16:10:32 -06002149
2150 /* Add any layers specified via environment variable next */
Jon Ashburneb6d5682015-07-02 14:10:53 -06002151 loader_add_layer_env(
Jon Ashburnbd332cc2015-07-07 10:27:45 -06002152 VK_LAYER_TYPE_DEVICE_EXPLICIT,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002153 "VK_DEVICE_LAYERS",
2154 &dev->activated_layer_list,
Jon Ashburnb2ef1372015-07-16 17:19:31 -06002155 &loader.scanned_device_layers);
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002156
2157 /* Add layers specified by the application */
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002158 err = loader_add_layer_names_to_list(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002159 &dev->activated_layer_list,
2160 pCreateInfo->layerCount,
2161 pCreateInfo->ppEnabledLayerNames,
Jon Ashburnb2ef1372015-07-16 17:19:31 -06002162 &loader.scanned_device_layers);
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002163
2164 return err;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002165}
2166
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002167/*
2168 * This function terminates the device chain fro CreateDevice.
2169 * CreateDevice is a special case and so the loader call's
2170 * the ICD's CreateDevice before creating the chain. Since
2171 * we can't call CreateDevice twice we must terminate the
2172 * device chain with something else.
2173 */
Dan Ginsburg78556e82015-07-23 13:15:00 -04002174static VkResult VKAPI scratch_vkCreateDevice(
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002175 VkPhysicalDevice gpu,
2176 const VkDeviceCreateInfo *pCreateInfo,
2177 VkDevice *pDevice)
2178{
2179 return VK_SUCCESS;
2180}
2181
Courtney Goeltzenleuchter2d3ba632015-07-12 14:35:22 -06002182static PFN_vkVoidFunction VKAPI loader_GetDeviceChainProcAddr(VkDevice device, const char * name)
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002183{
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002184 if (!strcmp(name, "vkGetDeviceProcAddr"))
Courtney Goeltzenleuchter2d3ba632015-07-12 14:35:22 -06002185 return (PFN_vkVoidFunction) loader_GetDeviceChainProcAddr;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002186 if (!strcmp(name, "vkCreateDevice"))
Courtney Goeltzenleuchter2d3ba632015-07-12 14:35:22 -06002187 return (PFN_vkVoidFunction) scratch_vkCreateDevice;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002188
Courtney Goeltzenleuchter3e029d12015-06-29 16:09:23 -06002189 struct loader_device *found_dev;
2190 struct loader_icd *icd = loader_get_icd_and_device(device, &found_dev);
2191 return icd->GetDeviceProcAddr(device, name);
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002192}
2193
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002194static uint32_t loader_activate_device_layers(
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06002195 struct loader_icd *icd,
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002196 struct loader_device *dev,
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06002197 VkDevice device)
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002198{
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002199 if (!icd)
2200 return 0;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002201
David Pinedoa0a8a242015-06-24 15:29:18 -06002202 if (!dev) {
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002203 return 0;
David Pinedoa0a8a242015-06-24 15:29:18 -06002204 }
Jon Ashburn94e70492015-06-10 10:13:10 -06002205
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002206 /* activate any layer libraries */
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06002207 void* nextObj = (void*) device;
2208 void* baseObj = nextObj;
Jon Ashburn94e70492015-06-10 10:13:10 -06002209 VkBaseLayerObject *nextGpuObj;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002210 PFN_vkGetDeviceProcAddr nextGPA = loader_GetDeviceChainProcAddr;
Jon Ashburn94e70492015-06-10 10:13:10 -06002211 VkBaseLayerObject *wrappedGpus;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002212
Jon Ashburn94e70492015-06-10 10:13:10 -06002213 if (!dev->activated_layer_list.count)
2214 return 0;
2215
2216 wrappedGpus = malloc(sizeof (VkBaseLayerObject) * dev->activated_layer_list.count);
2217 if (!wrappedGpus) {
2218 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Gpu objects for layer");
2219 return 0;
2220 }
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002221
Jon Ashburn94e70492015-06-10 10:13:10 -06002222 for (int32_t i = dev->activated_layer_list.count - 1; i >= 0; i--) {
2223
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002224 struct loader_layer_properties *layer_prop = &dev->activated_layer_list.list[i];
Jon Ashburn94e70492015-06-10 10:13:10 -06002225 loader_platform_dl_handle lib_handle;
2226
Jon Ashburn94e70492015-06-10 10:13:10 -06002227 nextGpuObj = (wrappedGpus + i);
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06002228 nextGpuObj->pGPA = (PFN_vkGPA)nextGPA;
Jon Ashburn94e70492015-06-10 10:13:10 -06002229 nextGpuObj->baseObject = baseObj;
2230 nextGpuObj->nextObject = nextObj;
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06002231 nextObj = (void*) nextGpuObj;
Jon Ashburn94e70492015-06-10 10:13:10 -06002232
2233 char funcStr[256];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002234 snprintf(funcStr, 256, "%sGetDeviceProcAddr", layer_prop->info.layerName);
2235 lib_handle = loader_add_layer_lib("device", layer_prop);
Jon Ashburn94e70492015-06-10 10:13:10 -06002236 if ((nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
2237 nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr");
2238 if (!nextGPA) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002239 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 -06002240 continue;
2241 }
2242
2243 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002244 "Insert device layer library %s (%s)",
2245 layer_prop->info.layerName,
2246 layer_prop->lib_info.lib_name);
Jon Ashburn94e70492015-06-10 10:13:10 -06002247
2248 }
2249
2250 loader_init_device_dispatch_table(&dev->loader_dispatch, nextGPA,
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06002251 (VkDevice) nextObj, (VkDevice) baseObj);
Jon Ashburn94e70492015-06-10 10:13:10 -06002252 free(wrappedGpus);
2253
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002254 return dev->activated_layer_list.count;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002255}
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002256
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002257VkResult loader_validate_layers(
2258 const uint32_t layer_count,
2259 const char * const *ppEnabledLayerNames,
2260 struct loader_layer_list *list)
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06002261{
2262 struct loader_layer_properties *prop;
2263
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002264 for (uint32_t i = 0; i < layer_count; i++) {
Jon Ashburne13ecc92015-08-03 17:19:30 -06002265 prop = loader_get_layer_property(ppEnabledLayerNames[i],
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002266 list);
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06002267 if (!prop) {
2268 return VK_ERROR_INVALID_LAYER;
2269 }
2270 }
2271
2272 return VK_SUCCESS;
2273}
2274
2275VkResult loader_validate_instance_extensions(
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002276 const VkInstanceCreateInfo *pCreateInfo)
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06002277{
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002278 struct loader_extension_property *extension_prop;
2279 struct loader_layer_properties *layer_prop;
2280
2281 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2282 extension_prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
2283 &loader.global_extensions);
2284
2285 if (extension_prop) {
2286 continue;
2287 }
2288
2289 extension_prop = NULL;
2290
2291 /* Not in global list, search layer extension lists */
2292 for (uint32_t j = 0; j < pCreateInfo->layerCount; j++) {
Jon Ashburne13ecc92015-08-03 17:19:30 -06002293 layer_prop = loader_get_layer_property(pCreateInfo->ppEnabledLayerNames[i],
Jon Ashburnb2ef1372015-07-16 17:19:31 -06002294 &loader.scanned_instance_layers);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002295
2296 if (!layer_prop) {
Courtney Goeltzenleuchter6f5b00c2015-07-06 20:46:50 -06002297 /* Should NOT get here, loader_validate_layers
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002298 * should have already filtered this case out.
2299 */
2300 continue;
2301 }
2302
2303 extension_prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
2304 &layer_prop->instance_extension_list);
2305 if (extension_prop) {
2306 /* Found the extension in one of the layers enabled by the app. */
2307 break;
2308 }
2309 }
2310
2311 if (!extension_prop) {
2312 /* Didn't find extension name in any of the global layers, error out */
2313 return VK_ERROR_INVALID_EXTENSION;
2314 }
2315 }
2316 return VK_SUCCESS;
2317}
2318
2319VkResult loader_validate_device_extensions(
2320 struct loader_icd *icd,
Cody Northrope62183e2015-07-09 18:08:05 -06002321 uint32_t gpu_index,
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002322 const VkDeviceCreateInfo *pCreateInfo)
2323{
2324 struct loader_extension_property *extension_prop;
2325 struct loader_layer_properties *layer_prop;
2326
2327 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2328 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
2329 extension_prop = get_extension_property(extension_name,
Courtney Goeltzenleuchterfedb2a52015-07-08 21:13:16 -06002330 &icd->device_extension_cache[gpu_index]);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002331
2332 if (extension_prop) {
2333 continue;
2334 }
2335
2336 /* Not in global list, search layer extension lists */
2337 for (uint32_t j = 0; j < pCreateInfo->layerCount; j++) {
2338 const char *layer_name = pCreateInfo->ppEnabledLayerNames[j];
Jon Ashburne13ecc92015-08-03 17:19:30 -06002339 layer_prop = loader_get_layer_property(layer_name,
Jon Ashburnb2ef1372015-07-16 17:19:31 -06002340 &loader.scanned_device_layers);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002341
2342 if (!layer_prop) {
2343 /* Should NOT get here, loader_validate_instance_layers
2344 * should have already filtered this case out.
2345 */
2346 continue;
2347 }
2348
2349 extension_prop = get_extension_property(extension_name,
2350 &layer_prop->device_extension_list);
2351 if (extension_prop) {
2352 /* Found the extension in one of the layers enabled by the app. */
2353 break;
2354 }
2355 }
2356
2357 if (!extension_prop) {
2358 /* Didn't find extension name in any of the device layers, error out */
2359 return VK_ERROR_INVALID_EXTENSION;
2360 }
2361 }
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06002362 return VK_SUCCESS;
2363}
2364
Dan Ginsburg78556e82015-07-23 13:15:00 -04002365VkResult VKAPI loader_CreateInstance(
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002366 const VkInstanceCreateInfo* pCreateInfo,
2367 VkInstance* pInstance)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002368{
Jon Ashburneed0c002015-05-21 17:42:17 -06002369 struct loader_instance *ptr_instance = *(struct loader_instance **) pInstance;
Jon Ashburn46888392015-01-29 15:45:51 -07002370 struct loader_scanned_icds *scanned_icds;
2371 struct loader_icd *icd;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06002372 struct loader_extension_property *prop;
2373 char **filtered_extension_names = NULL;
2374 VkInstanceCreateInfo icd_create_info;
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002375 VkResult res = VK_SUCCESS;
Jon Ashburnc624c882015-07-16 10:17:29 -06002376 bool success;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002377
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06002378 icd_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
2379 icd_create_info.layerCount = 0;
2380 icd_create_info.ppEnabledLayerNames = NULL;
2381 icd_create_info.pAllocCb = pCreateInfo->pAllocCb;
2382 icd_create_info.pAppInfo = pCreateInfo->pAppInfo;
2383 icd_create_info.pNext = pCreateInfo->pNext;
2384
2385 /*
2386 * NOTE: Need to filter the extensions to only those
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002387 * supported by the ICD.
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06002388 * No ICD will advertise support for layers. An ICD
2389 * library could support a layer, but it would be
2390 * independent of the actual ICD, just in the same library.
2391 */
2392 filtered_extension_names = loader_stack_alloc(pCreateInfo->extensionCount * sizeof(char *));
2393 if (!filtered_extension_names) {
2394 return VK_ERROR_OUT_OF_HOST_MEMORY;
2395 }
2396 icd_create_info.ppEnabledExtensionNames = (const char * const *) filtered_extension_names;
2397
Jon Ashburn46888392015-01-29 15:45:51 -07002398 scanned_icds = loader.scanned_icd_list;
2399 while (scanned_icds) {
2400 icd = loader_icd_add(ptr_instance, scanned_icds);
2401 if (icd) {
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06002402 icd_create_info.extensionCount = 0;
2403 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2404 prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
2405 &scanned_icds->global_extension_list);
2406 if (prop) {
2407 filtered_extension_names[icd_create_info.extensionCount] = (char *) pCreateInfo->ppEnabledExtensionNames[i];
2408 icd_create_info.extensionCount++;
2409 }
2410 }
2411
2412 res = scanned_icds->CreateInstance(&icd_create_info,
Jon Ashburn3da71f22015-05-14 12:43:38 -06002413 &(icd->instance));
Jon Ashburnc624c882015-07-16 10:17:29 -06002414 success = loader_icd_init_entrys(
2415 icd,
2416 icd->instance,
2417 scanned_icds->GetInstanceProcAddr);
2418
2419 if (res != VK_SUCCESS || !success)
Jon Ashburn46888392015-01-29 15:45:51 -07002420 {
2421 ptr_instance->icds = ptr_instance->icds->next;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002422 loader_icd_destroy(ptr_instance, icd);
Jon Ashburn3da71f22015-05-14 12:43:38 -06002423 icd->instance = VK_NULL_HANDLE;
Jon Ashburnc624c882015-07-16 10:17:29 -06002424 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
2425 "ICD ignored: failed to CreateInstance and find entrypoints with ICD");
Jon Ashburn46888392015-01-29 15:45:51 -07002426 }
2427 }
2428 scanned_icds = scanned_icds->next;
2429 }
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002430
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002431 /*
2432 * If no ICDs were added to instance list and res is unchanged
2433 * from it's initial value, the loader was unable to find
2434 * a suitable ICD.
2435 */
Ian Elliotteb450762015-02-05 15:19:15 -07002436 if (ptr_instance->icds == NULL) {
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002437 if (res == VK_SUCCESS) {
2438 return VK_ERROR_INCOMPATIBLE_DRIVER;
2439 } else {
2440 return res;
2441 }
Ian Elliotteb450762015-02-05 15:19:15 -07002442 }
Jon Ashburn46888392015-01-29 15:45:51 -07002443
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06002444 return VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002445}
2446
Dan Ginsburg78556e82015-07-23 13:15:00 -04002447VkResult VKAPI loader_DestroyInstance(
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06002448 VkInstance instance)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002449{
Courtney Goeltzenleuchterdeceded2015-06-08 15:04:02 -06002450 struct loader_instance *ptr_instance = loader_instance(instance);
Jon Ashburn3da71f22015-05-14 12:43:38 -06002451 struct loader_icd *icds = ptr_instance->icds;
Jon Ashburna6fd2612015-06-16 14:43:19 -06002452 struct loader_icd *next_icd;
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06002453 VkResult res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002454
2455 // Remove this instance from the list of instances:
2456 struct loader_instance *prev = NULL;
2457 struct loader_instance *next = loader.instances;
2458 while (next != NULL) {
2459 if (next == ptr_instance) {
2460 // Remove this instance from the list:
2461 if (prev)
2462 prev->next = next->next;
Jon Ashburnc5c49602015-02-03 09:26:59 -07002463 else
2464 loader.instances = next->next;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002465 break;
2466 }
2467 prev = next;
2468 next = next->next;
2469 }
2470 if (next == NULL) {
2471 // This must be an invalid instance handle or empty list
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06002472 return VK_ERROR_INVALID_HANDLE;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002473 }
2474
Jon Ashburn3da71f22015-05-14 12:43:38 -06002475 while (icds) {
2476 if (icds->instance) {
2477 res = icds->DestroyInstance(icds->instance);
Tony Barbourf20f87b2015-04-22 09:02:32 -06002478 if (res != VK_SUCCESS)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002479 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Tony Barbourf20f87b2015-04-22 09:02:32 -06002480 "ICD ignored: failed to DestroyInstance on device");
2481 }
Jon Ashburna6fd2612015-06-16 14:43:19 -06002482 next_icd = icds->next;
Jon Ashburn3da71f22015-05-14 12:43:38 -06002483 icds->instance = VK_NULL_HANDLE;
Jon Ashburna6fd2612015-06-16 14:43:19 -06002484 loader_icd_destroy(ptr_instance, icds);
2485
2486 icds = next_icd;
Jon Ashburn46888392015-01-29 15:45:51 -07002487 }
2488
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002489
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06002490 return VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002491}
2492
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002493VkResult loader_init_physical_device_info(
2494 struct loader_instance *ptr_instance)
2495{
2496 struct loader_icd *icd;
2497 uint32_t n, count = 0;
2498 VkResult res = VK_ERROR_UNKNOWN;
2499
2500 icd = ptr_instance->icds;
2501 while (icd) {
2502 res = icd->EnumeratePhysicalDevices(icd->instance, &n, NULL);
2503 if (res != VK_SUCCESS)
2504 return res;
2505 icd->gpu_count = n;
2506 count += n;
2507 icd = icd->next;
2508 }
2509
2510 ptr_instance->total_gpu_count = count;
2511
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002512 icd = ptr_instance->icds;
2513 while (icd) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002514
2515 n = icd->gpu_count;
Jon Ashburn128f9422015-05-28 19:16:58 -06002516 icd->gpus = (VkPhysicalDevice *) malloc(n * sizeof(VkPhysicalDevice));
2517 if (!icd->gpus) {
2518 /* TODO: Add cleanup code here */
2519 return VK_ERROR_OUT_OF_HOST_MEMORY;
2520 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002521 res = icd->EnumeratePhysicalDevices(
2522 icd->instance,
2523 &n,
Jon Ashburn128f9422015-05-28 19:16:58 -06002524 icd->gpus);
2525 if ((res == VK_SUCCESS) && (n == icd->gpu_count)) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002526
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002527 for (unsigned int i = 0; i < n; i++) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002528
Jon Ashburn128f9422015-05-28 19:16:58 -06002529 loader_init_dispatch(icd->gpus[i], ptr_instance->disp);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002530
2531 if (!loader_init_ext_list(&icd->device_extension_cache[i])) {
2532 /* TODO: Add cleanup code here */
2533 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2534 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002535 if (res == VK_SUCCESS) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002536
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002537 loader_add_physical_device_extensions(
2538 icd->GetPhysicalDeviceExtensionProperties,
2539 icd->gpus[0],
2540 VK_EXTENSION_ORIGIN_ICD,
2541 icd->scanned_icds->lib_name,
2542 &icd->device_extension_cache[i]);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002543
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002544 }
2545
2546 if (res != VK_SUCCESS) {
2547 /* clean up any extension lists previously created before this request failed */
2548 for (uint32_t j = 0; j < i; j++) {
2549 loader_destroy_ext_list(&icd->device_extension_cache[i]);
2550 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002551
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002552 return res;
2553 }
2554 }
2555
2556 count += n;
2557 }
2558
2559 icd = icd->next;
2560 }
2561
2562 return VK_SUCCESS;
2563}
2564
Dan Ginsburg78556e82015-07-23 13:15:00 -04002565VkResult VKAPI loader_EnumeratePhysicalDevices(
Courtney Goeltzenleuchter5e41f1d2015-04-20 12:48:54 -06002566 VkInstance instance,
2567 uint32_t* pPhysicalDeviceCount,
2568 VkPhysicalDevice* pPhysicalDevices)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002569{
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002570 uint32_t index = 0;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07002571 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002572 struct loader_icd *icd = ptr_instance->icds;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07002573
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002574 if (ptr_instance->total_gpu_count == 0) {
2575 loader_init_physical_device_info(ptr_instance);
Jon Ashburn4c392fb2015-01-28 19:57:09 -07002576 }
2577
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002578 *pPhysicalDeviceCount = ptr_instance->total_gpu_count;
2579 if (!pPhysicalDevices) {
2580 return VK_SUCCESS;
2581 }
Jon Ashburn4c392fb2015-01-28 19:57:09 -07002582
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002583 while (icd) {
2584 assert((index + icd->gpu_count) <= *pPhysicalDeviceCount);
Jon Ashburn128f9422015-05-28 19:16:58 -06002585 memcpy(&pPhysicalDevices[index], icd->gpus, icd->gpu_count * sizeof(VkPhysicalDevice));
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002586 index += icd->gpu_count;
2587 icd = icd->next;
2588 }
2589
2590 return VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002591}
2592
Dan Ginsburg78556e82015-07-23 13:15:00 -04002593VkResult VKAPI loader_GetPhysicalDeviceProperties(
Jon Ashburn3da71f22015-05-14 12:43:38 -06002594 VkPhysicalDevice gpu,
Tony Barbour59a47322015-06-24 16:06:58 -06002595 VkPhysicalDeviceProperties* pProperties)
Jon Ashburn3da71f22015-05-14 12:43:38 -06002596{
2597 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06002598 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburn3da71f22015-05-14 12:43:38 -06002599 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2600
Tony Barbour59a47322015-06-24 16:06:58 -06002601 if (icd->GetPhysicalDeviceProperties)
2602 res = icd->GetPhysicalDeviceProperties(gpu, pProperties);
2603
2604 return res;
2605}
2606
Dan Ginsburg78556e82015-07-23 13:15:00 -04002607VkResult VKAPI loader_GetPhysicalDeviceQueueCount(
Tony Barbour59a47322015-06-24 16:06:58 -06002608 VkPhysicalDevice gpu,
2609 uint32_t* pCount)
2610{
2611 uint32_t gpu_index;
2612 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2613 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2614
2615 if (icd->GetPhysicalDeviceQueueCount)
2616 res = icd->GetPhysicalDeviceQueueCount(gpu, pCount);
2617
2618 return res;
2619}
2620
Dan Ginsburg78556e82015-07-23 13:15:00 -04002621VkResult VKAPI loader_GetPhysicalDeviceQueueProperties (
Tony Barbour59a47322015-06-24 16:06:58 -06002622 VkPhysicalDevice gpu,
2623 uint32_t count,
2624 VkPhysicalDeviceQueueProperties * pProperties)
2625{
2626 uint32_t gpu_index;
2627 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2628 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2629
2630 if (icd->GetPhysicalDeviceQueueProperties)
2631 res = icd->GetPhysicalDeviceQueueProperties(gpu, count, pProperties);
2632
2633 return res;
2634}
2635
Dan Ginsburg78556e82015-07-23 13:15:00 -04002636VkResult VKAPI loader_GetPhysicalDeviceMemoryProperties (
Tony Barbour59a47322015-06-24 16:06:58 -06002637 VkPhysicalDevice gpu,
2638 VkPhysicalDeviceMemoryProperties* pProperties)
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->GetPhysicalDeviceMemoryProperties)
2645 res = icd->GetPhysicalDeviceMemoryProperties(gpu, pProperties);
Jon Ashburn3da71f22015-05-14 12:43:38 -06002646
2647 return res;
2648}
2649
Dan Ginsburg78556e82015-07-23 13:15:00 -04002650VkResult VKAPI loader_GetPhysicalDeviceFeatures(
Chris Forbesbc0bb772015-06-21 22:55:02 +12002651 VkPhysicalDevice physicalDevice,
2652 VkPhysicalDeviceFeatures* pFeatures)
2653{
2654 uint32_t gpu_index;
2655 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2656 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2657
2658 if (icd->GetPhysicalDeviceFeatures)
2659 res = icd->GetPhysicalDeviceFeatures(physicalDevice, pFeatures);
2660
2661 return res;
2662}
2663
Dan Ginsburg78556e82015-07-23 13:15:00 -04002664VkResult VKAPI loader_GetPhysicalDeviceFormatProperties(
Chris Forbesbc0bb772015-06-21 22:55:02 +12002665 VkPhysicalDevice physicalDevice,
2666 VkFormat format,
2667 VkFormatProperties* pFormatInfo)
2668{
2669 uint32_t gpu_index;
2670 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2671 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2672
Courtney Goeltzenleuchter2caec862015-07-12 12:52:09 -06002673 if (icd->GetPhysicalDeviceFormatProperties)
2674 res = icd->GetPhysicalDeviceFormatProperties(physicalDevice, format, pFormatInfo);
Chris Forbesbc0bb772015-06-21 22:55:02 +12002675
2676 return res;
2677}
2678
Jon Ashburn754864f2015-07-23 18:49:07 -06002679VkResult VKAPI loader_GetPhysicalDeviceImageFormatProperties(
2680 VkPhysicalDevice physicalDevice,
2681 VkFormat format,
2682 VkImageType type,
2683 VkImageTiling tiling,
2684 VkImageUsageFlags usage,
2685 VkImageFormatProperties* pImageFormatProperties)
2686{
2687 uint32_t gpu_index;
2688 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2689 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2690
2691 if (icd->GetPhysicalDeviceImageFormatProperties)
2692 res = icd->GetPhysicalDeviceImageFormatProperties(physicalDevice, format,
2693 type, tiling, usage, pImageFormatProperties);
2694
2695 return res;
2696}
2697
Dan Ginsburg78556e82015-07-23 13:15:00 -04002698VkResult VKAPI loader_GetPhysicalDeviceLimits(
Chris Forbesbc0bb772015-06-21 22:55:02 +12002699 VkPhysicalDevice physicalDevice,
2700 VkPhysicalDeviceLimits* pLimits)
2701{
2702 uint32_t gpu_index;
2703 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2704 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2705
2706 if (icd->GetPhysicalDeviceLimits)
2707 res = icd->GetPhysicalDeviceLimits(physicalDevice, pLimits);
2708
2709 return res;
2710}
2711
Dan Ginsburg78556e82015-07-23 13:15:00 -04002712VkResult VKAPI loader_GetPhysicalDeviceSparseImageFormatProperties(
Mark Lobodzinski16e8bef2015-07-03 15:58:09 -06002713 VkPhysicalDevice physicalDevice,
2714 VkFormat format,
2715 VkImageType type,
2716 uint32_t samples,
2717 VkImageUsageFlags usage,
2718 VkImageTiling tiling,
2719 uint32_t* pNumProperties,
2720 VkSparseImageFormatProperties* pProperties)
2721{
2722 uint32_t gpu_index;
2723 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2724 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2725
2726 if (icd->GetPhysicalDeviceSparseImageFormatProperties)
2727 res = icd->GetPhysicalDeviceSparseImageFormatProperties(physicalDevice, format, type, samples, usage, tiling, pNumProperties, pProperties);
2728
2729 return res;
2730}
2731
Dan Ginsburg78556e82015-07-23 13:15:00 -04002732VkResult VKAPI loader_CreateDevice(
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002733 VkPhysicalDevice gpu,
2734 const VkDeviceCreateInfo* pCreateInfo,
2735 VkDevice* pDevice)
2736{
2737 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06002738 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002739 struct loader_device *dev;
Courtney Goeltzenleuchter6f5b00c2015-07-06 20:46:50 -06002740 VkDeviceCreateInfo device_create_info;
2741 char **filtered_extension_names = NULL;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002742 VkResult res;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002743
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002744 if (!icd->CreateDevice) {
2745 return VK_ERROR_INITIALIZATION_FAILED;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002746 }
2747
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002748 res = loader_validate_layers(pCreateInfo->layerCount,
2749 pCreateInfo->ppEnabledLayerNames,
Jon Ashburnb2ef1372015-07-16 17:19:31 -06002750 &loader.scanned_device_layers);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002751 if (res != VK_SUCCESS) {
2752 return res;
2753 }
2754
Courtney Goeltzenleuchterfedb2a52015-07-08 21:13:16 -06002755 res = loader_validate_device_extensions(icd, gpu_index, pCreateInfo);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06002756 if (res != VK_SUCCESS) {
2757 return res;
2758 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002759
Courtney Goeltzenleuchter6f5b00c2015-07-06 20:46:50 -06002760 /*
2761 * NOTE: Need to filter the extensions to only those
2762 * supported by the ICD.
2763 * No ICD will advertise support for layers. An ICD
2764 * library could support a layer, but it would be
2765 * independent of the actual ICD, just in the same library.
2766 */
2767 filtered_extension_names = loader_stack_alloc(pCreateInfo->extensionCount * sizeof(char *));
2768 if (!filtered_extension_names) {
2769 return VK_ERROR_OUT_OF_HOST_MEMORY;
2770 }
2771
2772 /* Copy user's data */
2773 memcpy(&device_create_info, pCreateInfo, sizeof(VkDeviceCreateInfo));
2774
2775 /* ICD's do not use layers */
2776 device_create_info.layerCount = 0;
2777 device_create_info.ppEnabledLayerNames = NULL;
2778
2779 device_create_info.extensionCount = 0;
2780 device_create_info.ppEnabledExtensionNames = (const char * const *) filtered_extension_names;
2781
2782 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2783 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
2784 struct loader_extension_property *prop = get_extension_property(extension_name,
2785 &icd->device_extension_cache[gpu_index]);
2786 if (prop) {
2787 filtered_extension_names[device_create_info.extensionCount] = (char *) extension_name;
2788 device_create_info.extensionCount++;
2789 }
2790 }
2791
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002792 res = icd->CreateDevice(gpu, pCreateInfo, pDevice);
2793 if (res != VK_SUCCESS) {
2794 return res;
2795 }
2796
2797 dev = loader_add_logical_device(*pDevice, &icd->logical_device_list);
2798 if (dev == NULL) {
2799 return VK_ERROR_OUT_OF_HOST_MEMORY;
2800 }
2801 PFN_vkGetDeviceProcAddr get_proc_addr = icd->GetDeviceProcAddr;
2802 loader_init_device_dispatch_table(&dev->loader_dispatch, get_proc_addr,
Courtney Goeltzenleuchtere315d3c2015-07-16 10:36:57 -06002803 *pDevice, *pDevice);
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002804
2805 dev->loader_dispatch.CreateDevice = scratch_vkCreateDevice;
2806 loader_init_dispatch(*pDevice, &dev->loader_dispatch);
2807
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002808 /*
2809 * Put together the complete list of extensions to enable
2810 * This includes extensions requested via environment variables.
2811 */
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06002812 loader_enable_device_layers(icd, dev, pCreateInfo);
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002813
2814 /*
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002815 * Load the libraries and build the device chain
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002816 * terminating with the selected device.
2817 */
Courtney Goeltzenleuchter371de702015-07-05 12:53:31 -06002818 loader_activate_device_layers(icd, dev, *pDevice);
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002819
2820 res = dev->loader_dispatch.CreateDevice(gpu, pCreateInfo, pDevice);
2821
2822 dev->loader_dispatch.CreateDevice = icd->CreateDevice;
2823
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002824 return res;
2825}
2826
Courtney Goeltzenleuchter2d3ba632015-07-12 14:35:22 -06002827static PFN_vkVoidFunction VKAPI loader_GetInstanceProcAddr(VkInstance instance, const char * pName)
Jon Ashburnb0fbe912015-05-06 10:15:07 -06002828{
Jon Ashburn07daee72015-05-21 18:13:33 -06002829 if (instance == VK_NULL_HANDLE)
2830 return NULL;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002831
Jon Ashburn07daee72015-05-21 18:13:33 -06002832 void *addr;
2833 /* get entrypoint addresses that are global (in the loader)*/
2834 addr = globalGetProcAddr(pName);
2835 if (addr)
2836 return addr;
Jon Ashburnb0fbe912015-05-06 10:15:07 -06002837
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002838 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
2839
Jon Ashburn922c8f62015-06-18 09:05:37 -06002840 /* return any extension global entrypoints */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002841 addr = debug_report_instance_gpa(ptr_instance, pName);
2842 if (addr) {
2843 return addr;
2844 }
2845
Ian Elliottd3ef02f2015-07-06 14:36:13 -06002846 addr = wsi_swapchain_GetInstanceProcAddr(ptr_instance, pName);
David Pinedoa0a8a242015-06-24 15:29:18 -06002847 if (addr) {
Jon Ashburn922c8f62015-06-18 09:05:37 -06002848 return addr;
David Pinedoa0a8a242015-06-24 15:29:18 -06002849 }
Jon Ashburn07daee72015-05-21 18:13:33 -06002850
2851 /* return the instance dispatch table entrypoint for extensions */
2852 const VkLayerInstanceDispatchTable *disp_table = * (VkLayerInstanceDispatchTable **) instance;
2853 if (disp_table == NULL)
2854 return NULL;
2855
2856 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
2857 if (addr)
2858 return addr;
Jon Ashburnb0fbe912015-05-06 10:15:07 -06002859
2860 return NULL;
2861}
2862
Courtney Goeltzenleuchter2d3ba632015-07-12 14:35:22 -06002863LOADER_EXPORT PFN_vkVoidFunction VKAPI vkGetInstanceProcAddr(VkInstance instance, const char * pName)
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -06002864{
2865 return loader_GetInstanceProcAddr(instance, pName);
2866}
2867
Courtney Goeltzenleuchter2d3ba632015-07-12 14:35:22 -06002868static PFN_vkVoidFunction VKAPI loader_GetDeviceProcAddr(VkDevice device, const char * pName)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002869{
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06002870 if (device == VK_NULL_HANDLE) {
2871 return NULL;
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07002872 }
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002873
Chia-I Wuf46b81a2015-01-04 11:12:47 +08002874 void *addr;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002875
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002876 /* for entrypoints that loader must handle (ie non-dispatchable or create object)
2877 make sure the loader entrypoint is returned */
2878 addr = loader_non_passthrough_gpa(pName);
Ian Elliotte19c9152015-04-15 12:53:19 -06002879 if (addr) {
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002880 return addr;
Ian Elliotte19c9152015-04-15 12:53:19 -06002881 }
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002882
2883 /* return the dispatch table entrypoint for the fastest case */
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06002884 const VkLayerDispatchTable *disp_table = * (VkLayerDispatchTable **) device;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002885 if (disp_table == NULL)
2886 return NULL;
2887
Jon Ashburn27cd5842015-05-12 17:26:48 -06002888 addr = loader_lookup_device_dispatch_table(disp_table, pName);
Chia-I Wuf46b81a2015-01-04 11:12:47 +08002889 if (addr)
2890 return addr;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002891 else {
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06002892 if (disp_table->GetDeviceProcAddr == NULL)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002893 return NULL;
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06002894 return disp_table->GetDeviceProcAddr(device, pName);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002895 }
2896}
2897
Courtney Goeltzenleuchter2d3ba632015-07-12 14:35:22 -06002898LOADER_EXPORT PFN_vkVoidFunction VKAPI vkGetDeviceProcAddr(VkDevice device, const char * pName)
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -06002899{
2900 return loader_GetDeviceProcAddr(device, pName);
2901}
2902
Tony Barbour59a47322015-06-24 16:06:58 -06002903LOADER_EXPORT VkResult VKAPI vkGetGlobalExtensionProperties(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002904 const char* pLayerName,
2905 uint32_t* pCount,
2906 VkExtensionProperties* pProperties)
2907{
2908 struct loader_extension_list *global_extension_list;
2909
2910 /* Scan/discover all ICD libraries in a single-threaded manner */
2911 loader_platform_thread_once(&once_icd, loader_icd_scan);
2912
2913 /* get layer libraries in a single-threaded manner */
2914 loader_platform_thread_once(&once_layer, loader_layer_scan);
2915
2916 /* merge any duplicate extensions */
2917 loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
2918
2919 uint32_t copy_size;
2920
2921 if (pCount == NULL) {
2922 return VK_ERROR_INVALID_POINTER;
2923 }
2924
2925 loader_platform_thread_lock_mutex(&loader_lock);
2926
2927 global_extension_list = loader_global_extensions(pLayerName);
2928 if (global_extension_list == NULL) {
2929 loader_platform_thread_unlock_mutex(&loader_lock);
2930 return VK_ERROR_INVALID_LAYER;
2931 }
2932
2933 if (pProperties == NULL) {
2934 *pCount = global_extension_list->count;
2935 loader_platform_thread_unlock_mutex(&loader_lock);
2936 return VK_SUCCESS;
2937 }
2938
2939 copy_size = *pCount < global_extension_list->count ? *pCount : global_extension_list->count;
2940 for (uint32_t i = 0; i < copy_size; i++) {
2941 memcpy(&pProperties[i],
2942 &global_extension_list->list[i].info,
2943 sizeof(VkExtensionProperties));
2944 }
2945 *pCount = copy_size;
2946
2947 loader_platform_thread_unlock_mutex(&loader_lock);
2948
2949 if (copy_size < global_extension_list->count) {
2950 return VK_INCOMPLETE;
2951 }
2952
2953 return VK_SUCCESS;
2954}
2955
2956LOADER_EXPORT VkResult VKAPI vkGetGlobalLayerProperties(
2957 uint32_t* pCount,
2958 VkLayerProperties* pProperties)
Tony Barbour59a47322015-06-24 16:06:58 -06002959{
Jon Ashburn6301a0f2015-05-29 13:15:39 -06002960
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06002961 /* Scan/discover all ICD libraries in a single-threaded manner */
2962 loader_platform_thread_once(&once_icd, loader_icd_scan);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07002963
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06002964 /* get layer libraries in a single-threaded manner */
Jon Ashburn5ef20602015-07-02 09:40:15 -06002965 loader_platform_thread_once(&once_layer, loader_layer_scan);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07002966
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06002967 /* merge any duplicate extensions */
2968 loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
2969
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002970 uint32_t copy_size;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06002971
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002972 if (pCount == NULL) {
2973 return VK_ERROR_INVALID_POINTER;
2974 }
2975
2976 /* TODO: do we still need to lock */
Jon Ashburn6301a0f2015-05-29 13:15:39 -06002977 loader_platform_thread_lock_mutex(&loader_lock);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002978
2979 struct loader_layer_list *layer_list;
Jon Ashburnb2ef1372015-07-16 17:19:31 -06002980 layer_list = &loader.scanned_instance_layers;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002981
2982 if (pProperties == NULL) {
2983 *pCount = layer_list->count;
2984 loader_platform_thread_unlock_mutex(&loader_lock);
2985 return VK_SUCCESS;
2986 }
2987
2988 copy_size = *pCount < layer_list->count ? *pCount : layer_list->count;
2989 for (uint32_t i = 0; i < copy_size; i++) {
2990 memcpy(&pProperties[i], &layer_list->list[i].info, sizeof(VkLayerProperties));
2991 }
2992 *pCount = copy_size;
Tony Barbour59a47322015-06-24 16:06:58 -06002993
Jon Ashburn6301a0f2015-05-29 13:15:39 -06002994 loader_platform_thread_unlock_mutex(&loader_lock);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002995
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002996 if (copy_size < layer_list->count) {
2997 return VK_INCOMPLETE;
2998 }
Tony Barbour59a47322015-06-24 16:06:58 -06002999
3000 return VK_SUCCESS;
3001}
3002
Dan Ginsburg78556e82015-07-23 13:15:00 -04003003VkResult VKAPI loader_GetPhysicalDeviceExtensionProperties(
Tony Barbour59a47322015-06-24 16:06:58 -06003004 VkPhysicalDevice gpu,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06003005 const char* pLayerName,
3006 uint32_t* pCount,
Tony Barbour59a47322015-06-24 16:06:58 -06003007 VkExtensionProperties* pProperties)
3008{
3009 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06003010 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06003011 uint32_t copy_size;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07003012
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06003013 if (pCount == NULL) {
3014 return VK_ERROR_INVALID_POINTER;
3015 }
Jon Ashburn95a77ba2015-05-15 15:09:35 -06003016
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06003017 uint32_t count;
3018 struct loader_extension_list *list;
3019 loader_physical_device_extensions(icd, gpu_index, pLayerName, &count, &list);
3020
3021 if (pProperties == NULL) {
3022 *pCount = count;
3023 return VK_SUCCESS;
3024 }
3025
3026 copy_size = *pCount < count ? *pCount : count;
3027 for (uint32_t i = 0; i < copy_size; i++) {
3028 memcpy(&pProperties[i],
3029 &list->list[i].info,
3030 sizeof(VkExtensionProperties));
3031 }
3032 *pCount = copy_size;
3033
3034 if (copy_size < count) {
3035 return VK_INCOMPLETE;
3036 }
3037
3038 return VK_SUCCESS;
3039}
3040
Dan Ginsburg78556e82015-07-23 13:15:00 -04003041VkResult VKAPI loader_GetPhysicalDeviceLayerProperties(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06003042 VkPhysicalDevice gpu,
3043 uint32_t* pCount,
3044 VkLayerProperties* pProperties)
3045{
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06003046 uint32_t copy_size;
3047
3048 if (pCount == NULL) {
3049 return VK_ERROR_INVALID_POINTER;
3050 }
3051
Jon Ashburnb2ef1372015-07-16 17:19:31 -06003052 uint32_t count = loader.scanned_device_layers.count;
3053 struct loader_layer_list *layer_list = &loader.scanned_device_layers;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06003054
3055 if (pProperties == NULL) {
3056 *pCount = count;
3057 return VK_SUCCESS;
3058 }
3059
3060 copy_size = *pCount < count ? *pCount : count;
3061 for (uint32_t i = 0; i < copy_size; i++) {
3062 memcpy(&pProperties[i],
3063 &layer_list->list[i].info,
3064 sizeof(VkLayerProperties));
3065 }
3066 *pCount = copy_size;
3067
3068 if (copy_size < count) {
3069 return VK_INCOMPLETE;
3070 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06003071
3072 return VK_SUCCESS;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06003073}