blob: c5e9dfc50be271fcc14dc4b02114046d53288d4e [file] [log] [blame]
Mark Lobodzinski317574e2016-08-29 14:21:14 -06001/*
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08002 *
Jon Ashburn23d36b12016-02-02 17:47:28 -07003 * Copyright (c) 2014-2016 The Khronos Group Inc.
4 * Copyright (c) 2014-2016 Valve Corporation
5 * Copyright (c) 2014-2016 LunarG, Inc.
Courtney Goeltzenleuchterf821dad2015-12-02 14:53:22 -07006 * Copyright (C) 2015 Google Inc.
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08007 *
Jon Ashburn3ebf1252016-04-19 11:30:31 -06008 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080011 *
Jon Ashburn3ebf1252016-04-19 11:30:31 -060012 * http://www.apache.org/licenses/LICENSE-2.0
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080013 *
Jon Ashburn3ebf1252016-04-19 11:30:31 -060014 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19
Jon Ashburn23d36b12016-02-02 17:47:28 -070020 *
Courtney Goeltzenleuchter05559522015-10-30 11:14:30 -060021 * Author: Jon Ashburn <jon@lunarg.com>
Jon Ashburn23d36b12016-02-02 17:47:28 -070022 * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
Courtney Goeltzenleuchter05559522015-10-30 11:14:30 -060023 *
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080024 */
Mark Lobodzinskifaa90812015-11-25 13:26:15 -070025
Jon Ashburn6b4d70c2014-10-22 18:13:16 -060026#define _GNU_SOURCE
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080027#include <stdio.h>
28#include <stdlib.h>
29#include <stdarg.h>
30#include <stdbool.h>
31#include <string.h>
32
Chia-I Wu13a61a52014-08-04 11:18:20 +080033#include <sys/types.h>
Johannes van Waveren9bd805012015-10-28 11:45:00 -050034#if defined(_WIN32)
Ian Elliott2d4ab1e2015-01-13 17:52:38 -070035#include "dirent_on_windows.h"
Johannes van Waveren9bd805012015-10-28 11:45:00 -050036#else // _WIN32
Chia-I Wu13a61a52014-08-04 11:18:20 +080037#include <dirent.h>
Johannes van Waveren9bd805012015-10-28 11:45:00 -050038#endif // _WIN32
Tobin Ehlisb835d1b2015-07-03 10:34:49 -060039#include "vk_loader_platform.h"
Chia-I Wu19300602014-08-04 08:03:57 +080040#include "loader.h"
Jon Ashburn27cd5842015-05-12 17:26:48 -060041#include "gpa_helper.h"
42#include "table_ops.h"
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060043#include "debug_report.h"
Ian Elliott954fa342015-10-30 15:28:23 -060044#include "wsi.h"
Mark Lobodzinski317574e2016-08-29 14:21:14 -060045#include "extensions.h"
David Pinedo9316d3b2015-11-06 12:54:48 -070046#include "vulkan/vk_icd.h"
Jon Ashburn2077e382015-06-29 11:25:34 -060047#include "cJSON.h"
Jon Ashburnfc1031e2015-11-17 15:31:02 -070048#include "murmurhash.h"
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080049
Jon Ashburnd8ed7992016-04-04 13:52:53 -060050#if defined(__GNUC__)
Jon Ashburn10b3f832016-05-09 11:31:40 -060051#if (__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 17))
Jon Ashburncc407a22016-04-15 09:25:03 -060052#define secure_getenv __secure_getenv
53#endif
Jon Ashburnd8ed7992016-04-04 13:52:53 -060054#endif
55
Jon Ashburn27cd5842015-05-12 17:26:48 -060056struct loader_struct loader = {0};
Jon Ashburn87d6aa92015-08-28 15:19:27 -060057// TLS for instance for alloc/free callbacks
58THREAD_LOCAL_DECL struct loader_instance *tls_instance;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080059
Courtney Goeltzenleuchter0ef13a02015-12-16 16:19:46 -070060static size_t loader_platform_combine_path(char *dest, size_t len, ...);
Daniel Dadap00b4aba2015-09-30 11:50:51 -050061
Jon Ashburn24cd4be2015-11-01 14:04:06 -070062struct loader_phys_dev_per_icd {
63 uint32_t count;
64 VkPhysicalDevice *phys_devs;
Mark Young0153e0b2016-11-03 14:27:13 -060065 struct loader_icd_term *this_icd_term;
Jon Ashburn24cd4be2015-11-01 14:04:06 -070066};
67
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -060068enum loader_debug {
Jon Ashburn23d36b12016-02-02 17:47:28 -070069 LOADER_INFO_BIT = 0x01,
70 LOADER_WARN_BIT = 0x02,
71 LOADER_PERF_BIT = 0x04,
72 LOADER_ERROR_BIT = 0x08,
73 LOADER_DEBUG_BIT = 0x10,
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -060074};
75
76uint32_t g_loader_debug = 0;
77uint32_t g_loader_log_msgs = 0;
78
Jon Ashburn23d36b12016-02-02 17:47:28 -070079// thread safety lock for accessing global data structures such as "loader"
Jon Ashburn6301a0f2015-05-29 13:15:39 -060080// all entrypoints on the instance chain need to be locked except GPA
Jon Ashburn2077e382015-06-29 11:25:34 -060081// additionally CreateDevice and DestroyDevice needs to be locked
Jon Ashburn6301a0f2015-05-29 13:15:39 -060082loader_platform_thread_mutex loader_lock;
Jon Ashburn6461ef22015-09-22 13:11:00 -060083loader_platform_thread_mutex loader_json_lock;
Jon Ashburn6301a0f2015-05-29 13:15:39 -060084
Jon Ashburn86a527a2016-02-10 20:59:26 -070085const char *std_validation_str = "VK_LAYER_LUNARG_standard_validation";
86
Ian Elliottd3ef02f2015-07-06 14:36:13 -060087// This table contains the loader's instance dispatch table, which contains
88// default functions if no instance layers are activated. This contains
89// pointers to "terminator functions".
Jon Ashburn6301a0f2015-05-29 13:15:39 -060090const VkLayerInstanceDispatchTable instance_disp = {
Jon Ashburn69e9ea22015-09-28 16:15:00 -060091 .GetInstanceProcAddr = vkGetInstanceProcAddr,
Jon Ashburn1530c342016-02-26 13:14:27 -070092 .DestroyInstance = terminator_DestroyInstance,
93 .EnumeratePhysicalDevices = terminator_EnumeratePhysicalDevices,
94 .GetPhysicalDeviceFeatures = terminator_GetPhysicalDeviceFeatures,
Jon Ashburn23d36b12016-02-02 17:47:28 -070095 .GetPhysicalDeviceFormatProperties =
Jon Ashburn1530c342016-02-26 13:14:27 -070096 terminator_GetPhysicalDeviceFormatProperties,
Jon Ashburn23d36b12016-02-02 17:47:28 -070097 .GetPhysicalDeviceImageFormatProperties =
Jon Ashburn1530c342016-02-26 13:14:27 -070098 terminator_GetPhysicalDeviceImageFormatProperties,
99 .GetPhysicalDeviceProperties = terminator_GetPhysicalDeviceProperties,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700100 .GetPhysicalDeviceQueueFamilyProperties =
Jon Ashburn1530c342016-02-26 13:14:27 -0700101 terminator_GetPhysicalDeviceQueueFamilyProperties,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700102 .GetPhysicalDeviceMemoryProperties =
Jon Ashburn1530c342016-02-26 13:14:27 -0700103 terminator_GetPhysicalDeviceMemoryProperties,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700104 .EnumerateDeviceExtensionProperties =
Jon Ashburn1530c342016-02-26 13:14:27 -0700105 terminator_EnumerateDeviceExtensionProperties,
106 .EnumerateDeviceLayerProperties = terminator_EnumerateDeviceLayerProperties,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700107 .GetPhysicalDeviceSparseImageFormatProperties =
Jon Ashburn1530c342016-02-26 13:14:27 -0700108 terminator_GetPhysicalDeviceSparseImageFormatProperties,
109 .DestroySurfaceKHR = terminator_DestroySurfaceKHR,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700110 .GetPhysicalDeviceSurfaceSupportKHR =
Jon Ashburn1530c342016-02-26 13:14:27 -0700111 terminator_GetPhysicalDeviceSurfaceSupportKHR,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700112 .GetPhysicalDeviceSurfaceCapabilitiesKHR =
Jon Ashburn1530c342016-02-26 13:14:27 -0700113 terminator_GetPhysicalDeviceSurfaceCapabilitiesKHR,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700114 .GetPhysicalDeviceSurfaceFormatsKHR =
Jon Ashburn1530c342016-02-26 13:14:27 -0700115 terminator_GetPhysicalDeviceSurfaceFormatsKHR,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700116 .GetPhysicalDeviceSurfacePresentModesKHR =
Jon Ashburn1530c342016-02-26 13:14:27 -0700117 terminator_GetPhysicalDeviceSurfacePresentModesKHR,
118 .CreateDebugReportCallbackEXT = terminator_CreateDebugReportCallback,
119 .DestroyDebugReportCallbackEXT = terminator_DestroyDebugReportCallback,
120 .DebugReportMessageEXT = terminator_DebugReportMessage,
Mark Lobodzinski317574e2016-08-29 14:21:14 -0600121 .GetPhysicalDeviceExternalImageFormatPropertiesNV =
122 terminator_GetPhysicalDeviceExternalImageFormatPropertiesNV,
Ian Elliottdb4300a2015-11-23 10:17:23 -0700123#ifdef VK_USE_PLATFORM_MIR_KHR
Jon Ashburn1530c342016-02-26 13:14:27 -0700124 .CreateMirSurfaceKHR = terminator_CreateMirSurfaceKHR,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700125 .GetPhysicalDeviceMirPresentationSupportKHR =
Jon Ashburn1530c342016-02-26 13:14:27 -0700126 terminator_GetPhysicalDeviceMirPresentationSupportKHR,
Ian Elliottdb4300a2015-11-23 10:17:23 -0700127#endif
128#ifdef VK_USE_PLATFORM_WAYLAND_KHR
Jon Ashburn1530c342016-02-26 13:14:27 -0700129 .CreateWaylandSurfaceKHR = terminator_CreateWaylandSurfaceKHR,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700130 .GetPhysicalDeviceWaylandPresentationSupportKHR =
Jon Ashburn1530c342016-02-26 13:14:27 -0700131 terminator_GetPhysicalDeviceWaylandPresentationSupportKHR,
Ian Elliottdb4300a2015-11-23 10:17:23 -0700132#endif
133#ifdef VK_USE_PLATFORM_WIN32_KHR
Jon Ashburn1530c342016-02-26 13:14:27 -0700134 .CreateWin32SurfaceKHR = terminator_CreateWin32SurfaceKHR,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700135 .GetPhysicalDeviceWin32PresentationSupportKHR =
Jon Ashburn1530c342016-02-26 13:14:27 -0700136 terminator_GetPhysicalDeviceWin32PresentationSupportKHR,
Ian Elliottdb4300a2015-11-23 10:17:23 -0700137#endif
138#ifdef VK_USE_PLATFORM_XCB_KHR
Jon Ashburn1530c342016-02-26 13:14:27 -0700139 .CreateXcbSurfaceKHR = terminator_CreateXcbSurfaceKHR,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700140 .GetPhysicalDeviceXcbPresentationSupportKHR =
Jon Ashburn1530c342016-02-26 13:14:27 -0700141 terminator_GetPhysicalDeviceXcbPresentationSupportKHR,
Ian Elliottdb4300a2015-11-23 10:17:23 -0700142#endif
143#ifdef VK_USE_PLATFORM_XLIB_KHR
Jon Ashburn1530c342016-02-26 13:14:27 -0700144 .CreateXlibSurfaceKHR = terminator_CreateXlibSurfaceKHR,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700145 .GetPhysicalDeviceXlibPresentationSupportKHR =
Jon Ashburn1530c342016-02-26 13:14:27 -0700146 terminator_GetPhysicalDeviceXlibPresentationSupportKHR,
Ian Elliottdb4300a2015-11-23 10:17:23 -0700147#endif
Mark Lobodzinskia8a5f852015-12-10 16:25:21 -0700148#ifdef VK_USE_PLATFORM_ANDROID_KHR
Jon Ashburn1530c342016-02-26 13:14:27 -0700149 .CreateAndroidSurfaceKHR = terminator_CreateAndroidSurfaceKHR,
Mark Lobodzinskia8a5f852015-12-10 16:25:21 -0700150#endif
Jon Ashburnc7d3e732016-03-08 09:30:30 -0700151 .GetPhysicalDeviceDisplayPropertiesKHR =
152 terminator_GetPhysicalDeviceDisplayPropertiesKHR,
153 .GetPhysicalDeviceDisplayPlanePropertiesKHR =
154 terminator_GetPhysicalDeviceDisplayPlanePropertiesKHR,
155 .GetDisplayPlaneSupportedDisplaysKHR =
156 terminator_GetDisplayPlaneSupportedDisplaysKHR,
Jon Ashburncc407a22016-04-15 09:25:03 -0600157 .GetDisplayModePropertiesKHR = terminator_GetDisplayModePropertiesKHR,
158 .CreateDisplayModeKHR = terminator_CreateDisplayModeKHR,
159 .GetDisplayPlaneCapabilitiesKHR = terminator_GetDisplayPlaneCapabilitiesKHR,
160 .CreateDisplayPlaneSurfaceKHR = terminator_CreateDisplayPlaneSurfaceKHR,
Mark Youngfa552782016-12-12 16:14:55 -0700161
162 // NVX_device_generated_commands
163 .GetPhysicalDeviceGeneratedCommandsPropertiesNVX =
164 terminator_GetPhysicalDeviceGeneratedCommandsPropertiesNVX,
Jon Ashburn27cd5842015-05-12 17:26:48 -0600165};
166
Lenny Komow4053b812016-12-29 16:27:28 -0700167// A null-terminated list of all of the instance extensions supported by the
168// loader
169static const char *const LOADER_INSTANCE_EXTENSIONS[] = {
170 VK_KHR_SURFACE_EXTENSION_NAME,
171 VK_KHR_DISPLAY_EXTENSION_NAME,
172#ifdef VK_USE_PLATFORM_XLIB_KHR
173 VK_KHR_XLIB_SURFACE_EXTENSION_NAME,
174#endif
175#ifdef VK_USE_PLATFORM_XCB_KHR
176 VK_KHR_XCB_SURFACE_EXTENSION_NAME,
177#endif
178#ifdef VK_USE_PLATFORM_WAYLAND_KHR
179 VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
180#endif
181#ifdef VK_USE_PLATFORM_MIR_KHR
182 VK_KHR_MIR_SURFACE_EXTENSION_NAME,
183#endif
184#ifdef VK_USE_PLATFORM_ANDROID_KHR
185 VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
186#endif
187#ifdef VK_USE_PLATFORM_WIN32_KHR
188 VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
189#endif
190 VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
191 VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME,
192 VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME,
193 NULL};
194
Jon Ashburn8810c5f2015-08-18 18:04:47 -0600195LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_init);
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700196
Mark Young0ad83132016-06-30 13:02:42 -0600197void *loader_instance_heap_alloc(const struct loader_instance *instance,
198 size_t size,
199 VkSystemAllocationScope alloc_scope) {
200 void *pMemory = NULL;
201#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
202 {
203#else
Chia-I Wu3432a0c2015-10-27 18:04:07 +0800204 if (instance && instance->alloc_callbacks.pfnAllocation) {
Mark Young0ad83132016-06-30 13:02:42 -0600205 /* These are internal structures, so it's best to align everything to
206 * the largest unit size which is the size of a uint64_t.
207 */
208 pMemory = instance->alloc_callbacks.pfnAllocation(
209 instance->alloc_callbacks.pUserData, size, sizeof(uint64_t),
Jon Ashburn23d36b12016-02-02 17:47:28 -0700210 alloc_scope);
Mark Young0ad83132016-06-30 13:02:42 -0600211 } else {
212#endif
213 pMemory = malloc(size);
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600214 }
Mark Young0ad83132016-06-30 13:02:42 -0600215 return pMemory;
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600216}
217
Mark Young0ad83132016-06-30 13:02:42 -0600218void loader_instance_heap_free(const struct loader_instance *instance,
219 void *pMemory) {
220 if (pMemory != NULL) {
221#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
222 {
223#else
224 if (instance && instance->alloc_callbacks.pfnFree) {
225 instance->alloc_callbacks.pfnFree(
226 instance->alloc_callbacks.pUserData, pMemory);
227 } else {
228#endif
229 free(pMemory);
Mark Youngd077f992016-06-30 11:03:59 -0600230 }
Mark Young4b0b9222016-06-29 18:33:53 -0600231 }
Mark Young4b0b9222016-06-29 18:33:53 -0600232}
233
Mark Young0ad83132016-06-30 13:02:42 -0600234void *loader_instance_heap_realloc(const struct loader_instance *instance,
235 void *pMemory, size_t orig_size, size_t size,
236 VkSystemAllocationScope alloc_scope) {
237 void *pNewMem = NULL;
238 if (pMemory == NULL || orig_size == 0) {
239 pNewMem = loader_instance_heap_alloc(instance, size, alloc_scope);
240 } else if (size == 0) {
241 loader_instance_heap_free(instance, pMemory);
242#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
243#else
244 } else if (instance && instance->alloc_callbacks.pfnReallocation) {
245 /* These are internal structures, so it's best to align everything to
246 * the largest unit size which is the size of a uint64_t.
247 */
248 pNewMem = instance->alloc_callbacks.pfnReallocation(
249 instance->alloc_callbacks.pUserData, pMemory, size,
250 sizeof(uint64_t), alloc_scope);
251#endif
252 } else {
253 pNewMem = realloc(pMemory, size);
254 }
255 return pNewMem;
Mark Young4b0b9222016-06-29 18:33:53 -0600256}
257
Mark Young0ad83132016-06-30 13:02:42 -0600258void *loader_instance_tls_heap_alloc(size_t size) {
259 return loader_instance_heap_alloc(tls_instance, size,
260 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Mark Young4b0b9222016-06-29 18:33:53 -0600261}
Mark Young4b0b9222016-06-29 18:33:53 -0600262
Mark Young0ad83132016-06-30 13:02:42 -0600263void loader_instance_tls_heap_free(void *pMemory) {
264 loader_instance_heap_free(tls_instance, pMemory);
265}
266
267void *loader_device_heap_alloc(const struct loader_device *device, size_t size,
268 VkSystemAllocationScope alloc_scope) {
269 void *pMemory = NULL;
270#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
271 {
272#else
273 if (device && device->alloc_callbacks.pfnAllocation) {
274 /* These are internal structures, so it's best to align everything to
275 * the largest unit size which is the size of a uint64_t.
276 */
277 pMemory = device->alloc_callbacks.pfnAllocation(
278 device->alloc_callbacks.pUserData, size, sizeof(uint64_t),
279 alloc_scope);
280 } else {
281#endif
282 pMemory = malloc(size);
283 }
284 return pMemory;
285}
286
287void loader_device_heap_free(const struct loader_device *device,
288 void *pMemory) {
289 if (pMemory != NULL) {
290#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
291 {
292#else
293 if (device && device->alloc_callbacks.pfnFree) {
294 device->alloc_callbacks.pfnFree(device->alloc_callbacks.pUserData,
295 pMemory);
296 } else {
297#endif
298 free(pMemory);
299 }
300 }
301}
302
303void *loader_device_heap_realloc(const struct loader_device *device,
304 void *pMemory, size_t orig_size, size_t size,
305 VkSystemAllocationScope alloc_scope) {
306 void *pNewMem = NULL;
307 if (pMemory == NULL || orig_size == 0) {
308 pNewMem = loader_device_heap_alloc(device, size, alloc_scope);
309 } else if (size == 0) {
310 loader_device_heap_free(device, pMemory);
311#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
312#else
313 } else if (device && device->alloc_callbacks.pfnReallocation) {
314 /* These are internal structures, so it's best to align everything to
315 * the largest unit size which is the size of a uint64_t.
316 */
317 pNewMem = device->alloc_callbacks.pfnReallocation(
318 device->alloc_callbacks.pUserData, pMemory, size, sizeof(uint64_t),
319 alloc_scope);
320#endif
321 } else {
322 pNewMem = realloc(pMemory, size);
323 }
324 return pNewMem;
325}
326
327// Environment variables
328#if defined(__linux__)
329
330static inline char *loader_getenv(const char *name,
331 const struct loader_instance *inst) {
332 // No allocation of memory necessary for Linux, but we should at least touch
333 // the inst pointer to get rid of compiler warnings.
334 (void)inst;
335 return getenv(name);
336}
Frank Henigmanb1c27cb2016-11-24 20:02:09 -0500337static inline void loader_free_getenv(char *val,
Mark Young0ad83132016-06-30 13:02:42 -0600338 const struct loader_instance *inst) {
339 // No freeing of memory necessary for Linux, but we should at least touch
340 // the val and inst pointers to get rid of compiler warnings.
341 (void)val;
342 (void)inst;
343}
344
345#elif defined(WIN32)
346
347static inline char *loader_getenv(const char *name,
348 const struct loader_instance *inst) {
349 char *retVal;
350 DWORD valSize;
351
352 valSize = GetEnvironmentVariableA(name, NULL, 0);
353
354 // valSize DOES include the null terminator, so for any set variable
355 // will always be at least 1. If it's 0, the variable wasn't set.
356 if (valSize == 0)
357 return NULL;
358
359 // Allocate the space necessary for the registry entry
360 if (NULL != inst && NULL != inst->alloc_callbacks.pfnAllocation) {
361 retVal = (char *)inst->alloc_callbacks.pfnAllocation(
362 inst->alloc_callbacks.pUserData, valSize, sizeof(char *),
363 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
364 } else {
365 retVal = (char *)malloc(valSize);
366 }
367
368 if (NULL != retVal) {
369 GetEnvironmentVariableA(name, retVal, valSize);
370 }
371
372 return retVal;
373}
374
375static inline void loader_free_getenv(char *val,
376 const struct loader_instance *inst) {
377 if (NULL != inst && NULL != inst->alloc_callbacks.pfnFree) {
378 inst->alloc_callbacks.pfnFree(inst->alloc_callbacks.pUserData, val);
379 } else {
380 free((void *)val);
381 }
382}
383
384#else
385
386static inline char *loader_getenv(const char *name,
Mark Young0153e0b2016-11-03 14:27:13 -0600387 const struct loader_instance *inst) {
Mark Young0ad83132016-06-30 13:02:42 -0600388 // stub func
389 (void)inst;
390 (void)name;
391 return NULL;
392}
Frank Henigmanb1c27cb2016-11-24 20:02:09 -0500393static inline void loader_free_getenv(char *val,
Mark Young0153e0b2016-11-03 14:27:13 -0600394 const struct loader_instance *inst) {
Mark Young0ad83132016-06-30 13:02:42 -0600395 // stub func
396 (void)val;
397 (void)inst;
398}
399
400#endif
401
Jon Ashburn2e37d752016-02-12 08:20:06 -0700402void loader_log(const struct loader_instance *inst, VkFlags msg_type,
Jon Ashburn1530c342016-02-26 13:14:27 -0700403 int32_t msg_code, const char *format, ...) {
Jon Ashburn86723b02015-07-31 15:47:59 -0600404 char msg[512];
Jon Ashburnffad94d2015-06-30 14:46:22 -0700405 va_list ap;
406 int ret;
407
Jon Ashburnffad94d2015-06-30 14:46:22 -0700408 va_start(ap, format);
409 ret = vsnprintf(msg, sizeof(msg), format, ap);
Jon Ashburn23d36b12016-02-02 17:47:28 -0700410 if ((ret >= (int)sizeof(msg)) || ret < 0) {
411 msg[sizeof(msg) - 1] = '\0';
Jon Ashburnffad94d2015-06-30 14:46:22 -0700412 }
413 va_end(ap);
414
Courtney Goeltzenleuchter73477392015-12-03 13:48:01 -0700415 if (inst) {
Karl Schultz94971292016-11-19 09:02:27 -0700416 util_DebugReportMessage(
417 inst, msg_type, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT,
418 (uint64_t)(uintptr_t)inst, 0, msg_code, "loader", msg);
Courtney Goeltzenleuchter73477392015-12-03 13:48:01 -0700419 }
420
421 if (!(msg_type & g_loader_log_msgs)) {
422 return;
423 }
424
Ian Elliott4470a302015-02-17 10:33:47 -0700425#if defined(WIN32)
Jon Ashburnffad94d2015-06-30 14:46:22 -0700426 OutputDebugString(msg);
mschottb9cdb782015-07-22 14:11:29 +0200427 OutputDebugString("\n");
Jon Ashburnffad94d2015-06-30 14:46:22 -0700428#endif
429 fputs(msg, stderr);
430 fputc('\n', stderr);
431}
432
Mark Young0153e0b2016-11-03 14:27:13 -0600433VKAPI_ATTR VkResult VKAPI_CALL vkSetInstanceDispatch(VkInstance instance,
434 void *object) {
Jon Ashburnc3c58772016-03-29 11:16:01 -0600435
436 struct loader_instance *inst = loader_get_instance(instance);
437 if (!inst) {
Mark Youngb6399312017-01-10 14:22:15 -0700438 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
439 "vkSetInstanceDispatch: Can not retrieve Instance "
440 "dispatch table.");
Jon Ashburnc3c58772016-03-29 11:16:01 -0600441 return VK_ERROR_INITIALIZATION_FAILED;
442 }
443 loader_set_dispatch(object, inst->disp);
444 return VK_SUCCESS;
445}
446
Mark Young0153e0b2016-11-03 14:27:13 -0600447VKAPI_ATTR VkResult VKAPI_CALL vkSetDeviceDispatch(VkDevice device,
448 void *object) {
Jon Ashburned8f2312016-03-31 10:52:22 -0600449 struct loader_device *dev;
Mark Young0153e0b2016-11-03 14:27:13 -0600450 struct loader_icd_term *icd_term =
451 loader_get_icd_and_device(device, &dev, NULL);
Jon Ashburned8f2312016-03-31 10:52:22 -0600452
Mark Young0153e0b2016-11-03 14:27:13 -0600453 if (NULL == icd_term) {
Jon Ashburned8f2312016-03-31 10:52:22 -0600454 return VK_ERROR_INITIALIZATION_FAILED;
455 }
456 loader_set_dispatch(object, &dev->loader_dispatch);
457 return VK_SUCCESS;
458}
459
Jon Ashburnffad94d2015-06-30 14:46:22 -0700460#if defined(WIN32)
Tony Barbourea968902015-07-29 14:26:21 -0600461static char *loader_get_next_path(char *path);
Jon Ashburnffad94d2015-06-30 14:46:22 -0700462/**
463* Find the list of registry files (names within a key) in key "location".
464*
Jon Ashburn23d36b12016-02-02 17:47:28 -0700465* This function looks in the registry (hive = DEFAULT_VK_REGISTRY_HIVE) key as
466*given in "location"
467* for a list or name/values which are added to a returned list (function return
468*value).
Jon Ashburnffad94d2015-06-30 14:46:22 -0700469* The DWORD values within the key must be 0 or they are skipped.
Jon Ashburne39a4f82015-08-28 13:38:21 -0600470* Function return is a string with a ';' separated list of filenames.
Jon Ashburnffad94d2015-06-30 14:46:22 -0700471* Function return is NULL if no valid name/value pairs are found in the key,
472* or the key is not found.
473*
474* \returns
475* A string list of filenames as pointer.
476* When done using the returned string list, pointer should be freed.
477*/
Jon Ashburn23d36b12016-02-02 17:47:28 -0700478static char *loader_get_registry_files(const struct loader_instance *inst,
479 char *location) {
Jon Ashburnffad94d2015-06-30 14:46:22 -0700480 LONG rtn_value;
481 HKEY hive, key;
Piers Daniell524ec732015-11-05 16:58:26 -0700482 DWORD access_flags;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700483 char name[2048];
484 char *out = NULL;
Tony Barbourea968902015-07-29 14:26:21 -0600485 char *loc = location;
486 char *next;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700487 DWORD idx = 0;
488 DWORD name_size = sizeof(name);
489 DWORD value;
490 DWORD total_size = 4096;
491 DWORD value_size = sizeof(value);
Tony Barbourea968902015-07-29 14:26:21 -0600492
Jon Ashburn23d36b12016-02-02 17:47:28 -0700493 while (*loc) {
Tony Barbourea968902015-07-29 14:26:21 -0600494 next = loader_get_next_path(loc);
495 hive = DEFAULT_VK_REGISTRY_HIVE;
Piers Daniell524ec732015-11-05 16:58:26 -0700496 access_flags = KEY_QUERY_VALUE;
Tony Barbourea968902015-07-29 14:26:21 -0600497 rtn_value = RegOpenKeyEx(hive, loc, 0, access_flags, &key);
498 if (rtn_value != ERROR_SUCCESS) {
Mark Young93ecb1d2016-01-13 13:47:16 -0700499 // We still couldn't find the key, so give up:
500 loc = next;
501 continue;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700502 }
Tony Barbourea968902015-07-29 14:26:21 -0600503
Jon Ashburn23d36b12016-02-02 17:47:28 -0700504 while ((rtn_value = RegEnumValue(key, idx++, name, &name_size, NULL,
505 NULL, (LPBYTE)&value, &value_size)) ==
506 ERROR_SUCCESS) {
Tony Barbourea968902015-07-29 14:26:21 -0600507 if (value_size == sizeof(value) && value == 0) {
508 if (out == NULL) {
Mark Young0ad83132016-06-30 13:02:42 -0600509 out = loader_instance_heap_alloc(
Jon Ashburn23d36b12016-02-02 17:47:28 -0700510 inst, total_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0ad83132016-06-30 13:02:42 -0600511 if (NULL == out) {
512 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young0153e0b2016-11-03 14:27:13 -0600513 "Out of memory can't alloc space for "
514 "registry data");
Mark Young0ad83132016-06-30 13:02:42 -0600515 return NULL;
516 }
Tony Barbourea968902015-07-29 14:26:21 -0600517 out[0] = '\0';
Jon Ashburn23d36b12016-02-02 17:47:28 -0700518 } else if (strlen(out) + name_size + 1 > total_size) {
Mark Young0ad83132016-06-30 13:02:42 -0600519 out = loader_instance_heap_realloc(
Jon Ashburn23d36b12016-02-02 17:47:28 -0700520 inst, out, total_size, total_size * 2,
521 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0ad83132016-06-30 13:02:42 -0600522 if (NULL == out) {
523 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young0153e0b2016-11-03 14:27:13 -0600524 "Out of memory can't realloc space for "
525 "registry data");
Mark Young0ad83132016-06-30 13:02:42 -0600526 return NULL;
527 }
Tony Barbourea968902015-07-29 14:26:21 -0600528 total_size *= 2;
529 }
Tony Barbourea968902015-07-29 14:26:21 -0600530 if (strlen(out) == 0)
Jon Ashburn23d36b12016-02-02 17:47:28 -0700531 snprintf(out, name_size + 1, "%s", name);
Tony Barbourea968902015-07-29 14:26:21 -0600532 else
Jon Ashburn23d36b12016-02-02 17:47:28 -0700533 snprintf(out + strlen(out), name_size + 2, "%c%s",
Frank Henigman57173102016-11-24 22:15:20 -0500534 PATH_SEPARATOR, name);
Tony Barbourea968902015-07-29 14:26:21 -0600535 }
536 name_size = 2048;
537 }
538 loc = next;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700539 }
Tony Barbourea968902015-07-29 14:26:21 -0600540
Jon Ashburnffad94d2015-06-30 14:46:22 -0700541 return out;
542}
543
Ian Elliott4470a302015-02-17 10:33:47 -0700544#endif // WIN32
545
Jon Ashburnc7237a72015-08-03 09:08:46 -0600546/**
Daniel Dadap00b4aba2015-09-30 11:50:51 -0500547 * Combine path elements, separating each element with the platform-specific
548 * directory separator, and save the combined string to a destination buffer,
549 * not exceeding the given length. Path elements are given as variadic args,
550 * with a NULL element terminating the list.
551 *
552 * \returns the total length of the combined string, not including an ASCII
553 * NUL termination character. This length may exceed the available storage:
554 * in this case, the written string will be truncated to avoid a buffer
555 * overrun, and the return value will greater than or equal to the storage
556 * size. A NULL argument may be provided as the destination buffer in order
557 * to determine the required string length without actually writing a string.
558 */
559
Jon Ashburn23d36b12016-02-02 17:47:28 -0700560static size_t loader_platform_combine_path(char *dest, size_t len, ...) {
Courtney Goeltzenleuchter0ef13a02015-12-16 16:19:46 -0700561 size_t required_len = 0;
Daniel Dadap00b4aba2015-09-30 11:50:51 -0500562 va_list ap;
563 const char *component;
564
565 va_start(ap, len);
566
Jon Ashburn23d36b12016-02-02 17:47:28 -0700567 while ((component = va_arg(ap, const char *))) {
Daniel Dadap00b4aba2015-09-30 11:50:51 -0500568 if (required_len > 0) {
569 // This path element is not the first non-empty element; prepend
570 // a directory separator if space allows
571 if (dest && required_len + 1 < len) {
572 snprintf(dest + required_len, len - required_len, "%c",
573 DIRECTORY_SYMBOL);
574 }
575 required_len++;
576 }
577
578 if (dest && required_len < len) {
579 strncpy(dest + required_len, component, len - required_len);
580 }
581 required_len += strlen(component);
582 }
583
584 va_end(ap);
585
586 // strncpy(3) won't add a NUL terminating byte in the event of truncation.
587 if (dest && required_len >= len) {
588 dest[len - 1] = '\0';
589 }
590
591 return required_len;
592}
593
Daniel Dadap00b4aba2015-09-30 11:50:51 -0500594/**
Jon Ashburnc7237a72015-08-03 09:08:46 -0600595 * Given string of three part form "maj.min.pat" convert to a vulkan version
596 * number.
597 */
Mark Young60861ac2016-09-02 11:39:26 -0600598static uint32_t loader_make_version(char *vers_str) {
Jon Ashburn23d36b12016-02-02 17:47:28 -0700599 uint32_t vers = 0, major = 0, minor = 0, patch = 0;
Mark Young60861ac2016-09-02 11:39:26 -0600600 char *vers_tok;
Jon Ashburnc7237a72015-08-03 09:08:46 -0600601
Mark Young60861ac2016-09-02 11:39:26 -0600602 if (!vers_str) {
Jon Ashburnc7237a72015-08-03 09:08:46 -0600603 return vers;
Jon Ashburnc7237a72015-08-03 09:08:46 -0600604 }
Mark Young60861ac2016-09-02 11:39:26 -0600605
606 vers_tok = strtok(vers_str, ".\"\n\r");
607 if (NULL != vers_tok) {
608 major = (uint16_t)atoi(vers_tok);
609 vers_tok = strtok(NULL, ".\"\n\r");
610 if (NULL != vers_tok) {
611 minor = (uint16_t)atoi(vers_tok);
612 vers_tok = strtok(NULL, ".\"\n\r");
613 if (NULL != vers_tok) {
614 patch = (uint16_t)atoi(vers_tok);
615 }
616 }
617 }
Jon Ashburnc7237a72015-08-03 09:08:46 -0600618
619 return VK_MAKE_VERSION(major, minor, patch);
Jon Ashburnc7237a72015-08-03 09:08:46 -0600620}
621
Jon Ashburn23d36b12016-02-02 17:47:28 -0700622bool compare_vk_extension_properties(const VkExtensionProperties *op1,
623 const VkExtensionProperties *op2) {
Chia-I Wu3432a0c2015-10-27 18:04:07 +0800624 return strcmp(op1->extensionName, op2->extensionName) == 0 ? true : false;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600625}
626
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -0600627/**
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600628 * Search the given ext_array for an extension
629 * matching the given vk_ext_prop
630 */
Jon Ashburn23d36b12016-02-02 17:47:28 -0700631bool has_vk_extension_property_array(const VkExtensionProperties *vk_ext_prop,
632 const uint32_t count,
633 const VkExtensionProperties *ext_array) {
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600634 for (uint32_t i = 0; i < count; i++) {
635 if (compare_vk_extension_properties(vk_ext_prop, &ext_array[i]))
636 return true;
637 }
638 return false;
639}
640
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -0600641/**
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600642 * Search the given ext_list for an extension
643 * matching the given vk_ext_prop
644 */
Jon Ashburn23d36b12016-02-02 17:47:28 -0700645bool has_vk_extension_property(const VkExtensionProperties *vk_ext_prop,
646 const struct loader_extension_list *ext_list) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600647 for (uint32_t i = 0; i < ext_list->count; i++) {
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600648 if (compare_vk_extension_properties(&ext_list->list[i], vk_ext_prop))
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600649 return true;
650 }
651 return false;
652}
653
Jon Ashburnb8726962016-04-08 15:03:35 -0600654/**
655 * Search the given ext_list for a device extension matching the given ext_prop
656 */
Jon Ashburncc407a22016-04-15 09:25:03 -0600657bool has_vk_dev_ext_property(
658 const VkExtensionProperties *ext_prop,
659 const struct loader_device_extension_list *ext_list) {
Jon Ashburnb8726962016-04-08 15:03:35 -0600660 for (uint32_t i = 0; i < ext_list->count; i++) {
661 if (compare_vk_extension_properties(&ext_list->list[i].props, ext_prop))
662 return true;
663 }
664 return false;
665}
666
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600667/*
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -0600668 * Search the given layer list for a layer matching the given layer name
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600669 */
Jon Ashburn23d36b12016-02-02 17:47:28 -0700670static struct loader_layer_properties *
671loader_get_layer_property(const char *name,
672 const struct loader_layer_list *layer_list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600673 for (uint32_t i = 0; i < layer_list->count; i++) {
674 const VkLayerProperties *item = &layer_list->list[i].info;
675 if (strcmp(name, item->layerName) == 0)
676 return &layer_list->list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600677 }
678 return NULL;
679}
680
Jon Ashburne13ecc92015-08-03 17:19:30 -0600681/**
682 * Get the next unused layer property in the list. Init the property to zero.
683 */
Jon Ashburn23d36b12016-02-02 17:47:28 -0700684static struct loader_layer_properties *
685loader_get_next_layer_property(const struct loader_instance *inst,
686 struct loader_layer_list *layer_list) {
Jon Ashburne13ecc92015-08-03 17:19:30 -0600687 if (layer_list->capacity == 0) {
Mark Young0153e0b2016-11-03 14:27:13 -0600688 layer_list->list = loader_instance_heap_alloc(
689 inst, sizeof(struct loader_layer_properties) * 64,
690 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburne13ecc92015-08-03 17:19:30 -0600691 if (layer_list->list == NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -0700692 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -0700693 "loader_get_next_layer_property: Out of memory can "
694 "not add any layer properties to list");
Jon Ashburne13ecc92015-08-03 17:19:30 -0600695 return NULL;
696 }
Jon Ashburn23d36b12016-02-02 17:47:28 -0700697 memset(layer_list->list, 0,
698 sizeof(struct loader_layer_properties) * 64);
Jon Ashburne13ecc92015-08-03 17:19:30 -0600699 layer_list->capacity = sizeof(struct loader_layer_properties) * 64;
700 }
701
702 // ensure enough room to add an entry
Jon Ashburn23d36b12016-02-02 17:47:28 -0700703 if ((layer_list->count + 1) * sizeof(struct loader_layer_properties) >
704 layer_list->capacity) {
Mark Young0ad83132016-06-30 13:02:42 -0600705 layer_list->list = loader_instance_heap_realloc(
Jon Ashburn23d36b12016-02-02 17:47:28 -0700706 inst, layer_list->list, layer_list->capacity,
707 layer_list->capacity * 2, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburne13ecc92015-08-03 17:19:30 -0600708 if (layer_list->list == NULL) {
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -0700709 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -0700710 "loader_get_next_layer_property: realloc failed for "
711 "layer list");
Mark Young0ad83132016-06-30 13:02:42 -0600712 return NULL;
Jon Ashburne13ecc92015-08-03 17:19:30 -0600713 }
714 layer_list->capacity *= 2;
715 }
716
717 layer_list->count++;
718 return &(layer_list->list[layer_list->count - 1]);
719}
720
721/**
722 * Remove all layer properties entrys from the list
723 */
Jon Ashburn23d36b12016-02-02 17:47:28 -0700724void loader_delete_layer_properties(const struct loader_instance *inst,
725 struct loader_layer_list *layer_list) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700726 uint32_t i, j;
727 struct loader_device_extension_list *dev_ext_list;
Jon Ashburnb82c1852015-08-11 14:49:54 -0600728 if (!layer_list)
729 return;
730
Jon Ashburne13ecc92015-08-03 17:19:30 -0600731 for (i = 0; i < layer_list->count; i++) {
Jon Ashburn23d36b12016-02-02 17:47:28 -0700732 loader_destroy_generic_list(
733 inst, (struct loader_generic_list *)&layer_list->list[i]
734 .instance_extension_list);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700735 dev_ext_list = &layer_list->list[i].device_extension_list;
Mark Young0153e0b2016-11-03 14:27:13 -0600736 if (dev_ext_list->capacity > 0 && NULL != dev_ext_list->list &&
Jon Ashburn23d36b12016-02-02 17:47:28 -0700737 dev_ext_list->list->entrypoint_count > 0) {
738 for (j = 0; j < dev_ext_list->list->entrypoint_count; j++) {
Mark Young0153e0b2016-11-03 14:27:13 -0600739 loader_instance_heap_free(inst,
740 dev_ext_list->list->entrypoints[j]);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700741 }
Mark Young0ad83132016-06-30 13:02:42 -0600742 loader_instance_heap_free(inst, dev_ext_list->list->entrypoints);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700743 }
Jon Ashburn23d36b12016-02-02 17:47:28 -0700744 loader_destroy_generic_list(inst,
745 (struct loader_generic_list *)dev_ext_list);
Jon Ashburne13ecc92015-08-03 17:19:30 -0600746 }
747 layer_list->count = 0;
748
Jon Ashburnb82c1852015-08-11 14:49:54 -0600749 if (layer_list->capacity > 0) {
750 layer_list->capacity = 0;
Mark Young0ad83132016-06-30 13:02:42 -0600751 loader_instance_heap_free(inst, layer_list->list);
Jon Ashburnb82c1852015-08-11 14:49:54 -0600752 }
Jon Ashburne13ecc92015-08-03 17:19:30 -0600753}
754
Mark Young3a587792016-08-19 15:25:08 -0600755static VkResult loader_add_instance_extensions(
Jon Ashburn23d36b12016-02-02 17:47:28 -0700756 const struct loader_instance *inst,
757 const PFN_vkEnumerateInstanceExtensionProperties fp_get_props,
758 const char *lib_name, struct loader_extension_list *ext_list) {
Courtney Goeltzenleuchter36eeb742015-12-21 16:41:47 -0700759 uint32_t i, count = 0;
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600760 VkExtensionProperties *ext_props;
Mark Young3a587792016-08-19 15:25:08 -0600761 VkResult res = VK_SUCCESS;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600762
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -0600763 if (!fp_get_props) {
Courtney Goeltzenleuchter35985f62015-09-14 17:22:16 -0600764 /* No EnumerateInstanceExtensionProperties defined */
Mark Young3a587792016-08-19 15:25:08 -0600765 goto out;
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -0600766 }
767
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600768 res = fp_get_props(NULL, &count, NULL);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600769 if (res != VK_SUCCESS) {
Mark Youngb6399312017-01-10 14:22:15 -0700770 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
771 "loader_add_instance_extensions: Error getting Instance "
772 "extension count from %s",
773 lib_name);
Mark Young3a587792016-08-19 15:25:08 -0600774 goto out;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600775 }
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600776
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -0600777 if (count == 0) {
778 /* No ExtensionProperties to report */
Mark Young3a587792016-08-19 15:25:08 -0600779 goto out;
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -0600780 }
781
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600782 ext_props = loader_stack_alloc(count * sizeof(VkExtensionProperties));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600783
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600784 res = fp_get_props(NULL, &count, ext_props);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600785 if (res != VK_SUCCESS) {
Mark Youngb6399312017-01-10 14:22:15 -0700786 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
787 "loader_add_instance_extensions: Error getting Instance "
788 "extensions from %s",
789 lib_name);
Mark Young3a587792016-08-19 15:25:08 -0600790 goto out;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600791 }
Tony Barbour59a47322015-06-24 16:06:58 -0600792
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600793 for (i = 0; i < count; i++) {
Courtney Goeltzenleuchter53043732015-07-12 13:20:05 -0600794 char spec_version[64];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600795
Jon Ashburncc407a22016-04-15 09:25:03 -0600796 bool ext_unsupported =
797 wsi_unsupported_instance_extension(&ext_props[i]);
Jon Ashburn6fa520f2016-03-25 12:49:35 -0600798 if (!ext_unsupported) {
799 snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
800 VK_MAJOR(ext_props[i].specVersion),
801 VK_MINOR(ext_props[i].specVersion),
802 VK_PATCH(ext_props[i].specVersion));
803 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
804 "Instance Extension: %s (%s) version %s",
805 ext_props[i].extensionName, lib_name, spec_version);
Mark Young6267ae62017-01-12 12:27:19 -0700806
Mark Young3a587792016-08-19 15:25:08 -0600807 res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
808 if (res != VK_SUCCESS) {
Mark Youngb6399312017-01-10 14:22:15 -0700809 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
810 "loader_add_instance_extensions: Failed to add %s "
811 "to Instance extension list",
Mark Young3a587792016-08-19 15:25:08 -0600812 lib_name);
813 goto out;
814 }
Jon Ashburn6fa520f2016-03-25 12:49:35 -0600815 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600816 }
Mark Young6267ae62017-01-12 12:27:19 -0700817
Mark Young3a587792016-08-19 15:25:08 -0600818out:
819 return res;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600820}
821
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700822/*
823 * Initialize ext_list with the physical device extensions.
824 * The extension properties are passed as inputs in count and ext_props.
825 */
Jon Ashburn23d36b12016-02-02 17:47:28 -0700826static VkResult
827loader_init_device_extensions(const struct loader_instance *inst,
Mark Young0153e0b2016-11-03 14:27:13 -0600828 struct loader_physical_device_term *phys_dev_term,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700829 uint32_t count, VkExtensionProperties *ext_props,
830 struct loader_extension_list *ext_list) {
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700831 VkResult res;
832 uint32_t i;
833
Mark Young3a587792016-08-19 15:25:08 -0600834 res = loader_init_generic_list(inst, (struct loader_generic_list *)ext_list,
835 sizeof(VkExtensionProperties));
836 if (VK_SUCCESS != res) {
837 return res;
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700838 }
839
840 for (i = 0; i < count; i++) {
841 char spec_version[64];
842
Jon Ashburn23d36b12016-02-02 17:47:28 -0700843 snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
844 VK_MAJOR(ext_props[i].specVersion),
845 VK_MINOR(ext_props[i].specVersion),
846 VK_PATCH(ext_props[i].specVersion));
Mark Young0153e0b2016-11-03 14:27:13 -0600847 loader_log(
848 inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
849 "Device Extension: %s (%s) version %s", ext_props[i].extensionName,
850 phys_dev_term->this_icd_term->scanned_icd->lib_name, spec_version);
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700851 res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
852 if (res != VK_SUCCESS)
853 return res;
854 }
855
856 return VK_SUCCESS;
857}
858
Jon Ashburn1530c342016-02-26 13:14:27 -0700859VkResult loader_add_device_extensions(const struct loader_instance *inst,
Jon Ashburncc407a22016-04-15 09:25:03 -0600860 PFN_vkEnumerateDeviceExtensionProperties
861 fpEnumerateDeviceExtensionProperties,
Jon Ashburn1530c342016-02-26 13:14:27 -0700862 VkPhysicalDevice physical_device,
863 const char *lib_name,
864 struct loader_extension_list *ext_list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600865 uint32_t i, count;
866 VkResult res;
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600867 VkExtensionProperties *ext_props;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600868
Piers Daniell295fe402016-03-29 11:51:11 -0600869 res = fpEnumerateDeviceExtensionProperties(physical_device, NULL, &count,
870 NULL);
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700871 if (res == VK_SUCCESS && count > 0) {
Jon Ashburn23d36b12016-02-02 17:47:28 -0700872 ext_props = loader_stack_alloc(count * sizeof(VkExtensionProperties));
Mark Young9a3ddd42016-10-21 16:25:47 -0600873 if (!ext_props) {
Mark Youngb6399312017-01-10 14:22:15 -0700874 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
875 "loader_add_device_extensions: Failed to allocate space"
876 " for device extension properties.");
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700877 return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young9a3ddd42016-10-21 16:25:47 -0600878 }
Piers Daniell295fe402016-03-29 11:51:11 -0600879 res = fpEnumerateDeviceExtensionProperties(physical_device, NULL,
880 &count, ext_props);
Mark Young9a3ddd42016-10-21 16:25:47 -0600881 if (res != VK_SUCCESS) {
Jon Ashburn24cd4be2015-11-01 14:04:06 -0700882 return res;
Mark Young9a3ddd42016-10-21 16:25:47 -0600883 }
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700884 for (i = 0; i < count; i++) {
885 char spec_version[64];
886
Jon Ashburn23d36b12016-02-02 17:47:28 -0700887 snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
888 VK_MAJOR(ext_props[i].specVersion),
889 VK_MINOR(ext_props[i].specVersion),
890 VK_PATCH(ext_props[i].specVersion));
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -0700891 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700892 "Device Extension: %s (%s) version %s",
893 ext_props[i].extensionName, lib_name, spec_version);
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700894 res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
Mark Youngb6399312017-01-10 14:22:15 -0700895 if (res != VK_SUCCESS) {
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700896 return res;
Mark Youngb6399312017-01-10 14:22:15 -0700897 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600898 }
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700899 } else {
Jon Ashburn23d36b12016-02-02 17:47:28 -0700900 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -0700901 "loader_add_device_extensions: Error getting physical "
902 "device extension info count from library %s",
Jon Ashburn23d36b12016-02-02 17:47:28 -0700903 lib_name);
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700904 return res;
905 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600906
Jon Ashburn24cd4be2015-11-01 14:04:06 -0700907 return VK_SUCCESS;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600908}
909
Mark Young3a587792016-08-19 15:25:08 -0600910VkResult loader_init_generic_list(const struct loader_instance *inst,
Mark Young0153e0b2016-11-03 14:27:13 -0600911 struct loader_generic_list *list_info,
912 size_t element_size) {
Mark Young84ba0482016-09-02 11:45:00 -0600913 size_t capacity = 32 * element_size;
914 list_info->count = 0;
915 list_info->capacity = 0;
Mark Young0ad83132016-06-30 13:02:42 -0600916 list_info->list = loader_instance_heap_alloc(
Mark Young84ba0482016-09-02 11:45:00 -0600917 inst, capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburn6e6a2162015-12-10 08:51:10 -0700918 if (list_info->list == NULL) {
Mark Youngb6399312017-01-10 14:22:15 -0700919 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
920 "loader_init_generic_list: Failed to allocate space "
921 "for generic list");
Mark Young3a587792016-08-19 15:25:08 -0600922 return VK_ERROR_OUT_OF_HOST_MEMORY;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600923 }
Mark Young84ba0482016-09-02 11:45:00 -0600924 memset(list_info->list, 0, capacity);
925 list_info->capacity = capacity;
Mark Young3a587792016-08-19 15:25:08 -0600926 return VK_SUCCESS;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600927}
928
Jon Ashburn6e6a2162015-12-10 08:51:10 -0700929void loader_destroy_generic_list(const struct loader_instance *inst,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700930 struct loader_generic_list *list) {
Mark Young0ad83132016-06-30 13:02:42 -0600931 loader_instance_heap_free(inst, list->list);
Jon Ashburn6e6a2162015-12-10 08:51:10 -0700932 list->count = 0;
933 list->capacity = 0;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600934}
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600935
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600936/*
937 * Append non-duplicate extension properties defined in props
938 * to the given ext_list.
Jon Ashburn24cd4be2015-11-01 14:04:06 -0700939 * Return
940 * Vk_SUCCESS on success
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600941 */
Jon Ashburn23d36b12016-02-02 17:47:28 -0700942VkResult loader_add_to_ext_list(const struct loader_instance *inst,
943 struct loader_extension_list *ext_list,
944 uint32_t prop_list_count,
945 const VkExtensionProperties *props) {
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600946 uint32_t i;
947 const VkExtensionProperties *cur_ext;
948
949 if (ext_list->list == NULL || ext_list->capacity == 0) {
Mark Young0153e0b2016-11-03 14:27:13 -0600950 VkResult res = loader_init_generic_list(
951 inst, (struct loader_generic_list *)ext_list,
952 sizeof(VkExtensionProperties));
Mark Young3a587792016-08-19 15:25:08 -0600953 if (VK_SUCCESS != res) {
954 return res;
955 }
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600956 }
957
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600958 for (i = 0; i < prop_list_count; i++) {
959 cur_ext = &props[i];
960
961 // look for duplicates
962 if (has_vk_extension_property(cur_ext, ext_list)) {
963 continue;
964 }
965
966 // add to list at end
967 // check for enough capacity
Jon Ashburn23d36b12016-02-02 17:47:28 -0700968 if (ext_list->count * sizeof(VkExtensionProperties) >=
969 ext_list->capacity) {
Jon Ashburne39a4f82015-08-28 13:38:21 -0600970
Mark Young0ad83132016-06-30 13:02:42 -0600971 ext_list->list = loader_instance_heap_realloc(
Jon Ashburn23d36b12016-02-02 17:47:28 -0700972 inst, ext_list->list, ext_list->capacity,
973 ext_list->capacity * 2, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburn24cd4be2015-11-01 14:04:06 -0700974
Mark Youngb6399312017-01-10 14:22:15 -0700975 if (ext_list->list == NULL) {
976 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
977 "loader_add_to_ext_list: Failed to reallocate "
978 "space for extension list");
Jon Ashburn24cd4be2015-11-01 14:04:06 -0700979 return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Youngb6399312017-01-10 14:22:15 -0700980 }
Jon Ashburn24cd4be2015-11-01 14:04:06 -0700981
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600982 // double capacity
983 ext_list->capacity *= 2;
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600984 }
985
Jon Ashburn23d36b12016-02-02 17:47:28 -0700986 memcpy(&ext_list->list[ext_list->count], cur_ext,
987 sizeof(VkExtensionProperties));
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600988 ext_list->count++;
989 }
Jon Ashburn24cd4be2015-11-01 14:04:06 -0700990 return VK_SUCCESS;
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600991}
992
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700993/*
994 * Append one extension property defined in props with entrypoints
Jon Ashburnb8726962016-04-08 15:03:35 -0600995 * defined in entrys to the given ext_list. Do not append if a duplicate
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700996 * Return
997 * Vk_SUCCESS on success
998 */
Jon Ashburn23d36b12016-02-02 17:47:28 -0700999VkResult
1000loader_add_to_dev_ext_list(const struct loader_instance *inst,
1001 struct loader_device_extension_list *ext_list,
1002 const VkExtensionProperties *props,
1003 uint32_t entry_count, char **entrys) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001004 uint32_t idx;
1005 if (ext_list->list == NULL || ext_list->capacity == 0) {
Mark Young3a587792016-08-19 15:25:08 -06001006 VkResult res = loader_init_generic_list(
1007 inst, (struct loader_generic_list *)ext_list,
1008 sizeof(struct loader_dev_ext_props));
1009 if (VK_SUCCESS != res) {
1010 return res;
1011 }
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001012 }
1013
Jon Ashburnb8726962016-04-08 15:03:35 -06001014 // look for duplicates
1015 if (has_vk_dev_ext_property(props, ext_list)) {
1016 return VK_SUCCESS;
1017 }
1018
Jon Ashburn23d36b12016-02-02 17:47:28 -07001019 idx = ext_list->count;
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001020 // add to list at end
1021 // check for enough capacity
Jon Ashburn23d36b12016-02-02 17:47:28 -07001022 if (idx * sizeof(struct loader_dev_ext_props) >= ext_list->capacity) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001023
Mark Young0ad83132016-06-30 13:02:42 -06001024 ext_list->list = loader_instance_heap_realloc(
Jon Ashburn23d36b12016-02-02 17:47:28 -07001025 inst, ext_list->list, ext_list->capacity, ext_list->capacity * 2,
1026 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001027
Mark Youngb6399312017-01-10 14:22:15 -07001028 if (ext_list->list == NULL) {
1029 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1030 "loader_add_to_dev_ext_list: Failed to reallocate "
1031 "space for device extension list");
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001032 return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Youngb6399312017-01-10 14:22:15 -07001033 }
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001034
1035 // double capacity
1036 ext_list->capacity *= 2;
1037 }
1038
Jon Ashburn23d36b12016-02-02 17:47:28 -07001039 memcpy(&ext_list->list[idx].props, props,
1040 sizeof(struct loader_dev_ext_props));
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001041 ext_list->list[idx].entrypoint_count = entry_count;
Jon Ashburn23d36b12016-02-02 17:47:28 -07001042 ext_list->list[idx].entrypoints =
Mark Young0ad83132016-06-30 13:02:42 -06001043 loader_instance_heap_alloc(inst, sizeof(char *) * entry_count,
1044 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1045 if (ext_list->list[idx].entrypoints == NULL) {
Mark Youngb6399312017-01-10 14:22:15 -07001046 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1047 "loader_add_to_dev_ext_list: Failed to allocate space "
1048 "for device extension entrypoint list in list %d",
1049 idx);
Mark Young0ad83132016-06-30 13:02:42 -06001050 ext_list->list[idx].entrypoint_count = 0;
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001051 return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young0ad83132016-06-30 13:02:42 -06001052 }
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001053 for (uint32_t i = 0; i < entry_count; i++) {
Mark Young0ad83132016-06-30 13:02:42 -06001054 ext_list->list[idx].entrypoints[i] = loader_instance_heap_alloc(
Jon Ashburn23d36b12016-02-02 17:47:28 -07001055 inst, strlen(entrys[i]) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0ad83132016-06-30 13:02:42 -06001056 if (ext_list->list[idx].entrypoints[i] == NULL) {
1057 for (uint32_t j = 0; j < i; j++) {
1058 loader_instance_heap_free(inst,
1059 ext_list->list[idx].entrypoints[j]);
1060 }
1061 loader_instance_heap_free(inst, ext_list->list[idx].entrypoints);
1062 ext_list->list[idx].entrypoint_count = 0;
1063 ext_list->list[idx].entrypoints = NULL;
Mark Youngb6399312017-01-10 14:22:15 -07001064 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1065 "loader_add_to_dev_ext_list: Failed to allocate space "
1066 "for device extension entrypoint %d name",
1067 i);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001068 return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young0ad83132016-06-30 13:02:42 -06001069 }
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001070 strcpy(ext_list->list[idx].entrypoints[i], entrys[i]);
1071 }
1072 ext_list->count++;
1073
1074 return VK_SUCCESS;
1075}
1076
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001077/**
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001078 * Search the given search_list for any layers in the props list.
Jon Ashburn23d36b12016-02-02 17:47:28 -07001079 * Add these to the output layer_list. Don't add duplicates to the output
1080 * layer_list.
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001081 */
Jon Ashburn23d36b12016-02-02 17:47:28 -07001082static VkResult
1083loader_add_layer_names_to_list(const struct loader_instance *inst,
1084 struct loader_layer_list *output_list,
1085 uint32_t name_count, const char *const *names,
1086 const struct loader_layer_list *search_list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001087 struct loader_layer_properties *layer_prop;
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06001088 VkResult err = VK_SUCCESS;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001089
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001090 for (uint32_t i = 0; i < name_count; i++) {
1091 const char *search_target = names[i];
Jon Ashburne13ecc92015-08-03 17:19:30 -06001092 layer_prop = loader_get_layer_property(search_target, search_list);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001093 if (!layer_prop) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001094 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001095 "loader_add_layer_names_to_list: Unable to find layer"
1096 " %s",
1097 search_target);
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06001098 err = VK_ERROR_LAYER_NOT_PRESENT;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001099 continue;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001100 }
1101
Mark Young0ad83132016-06-30 13:02:42 -06001102 err = loader_add_to_layer_list(inst, output_list, 1, layer_prop);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001103 }
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06001104
1105 return err;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001106}
1107
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -06001108/*
1109 * Manage lists of VkLayerProperties
1110 */
Jon Ashburne39a4f82015-08-28 13:38:21 -06001111static bool loader_init_layer_list(const struct loader_instance *inst,
Jon Ashburn23d36b12016-02-02 17:47:28 -07001112 struct loader_layer_list *list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001113 list->capacity = 32 * sizeof(struct loader_layer_properties);
Mark Young0ad83132016-06-30 13:02:42 -06001114 list->list = loader_instance_heap_alloc(
1115 inst, list->capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001116 if (list->list == NULL) {
1117 return false;
1118 }
1119 memset(list->list, 0, list->capacity);
1120 list->count = 0;
1121 return true;
1122}
1123
Jon Ashburne39a4f82015-08-28 13:38:21 -06001124void loader_destroy_layer_list(const struct loader_instance *inst,
Mark Young0ad83132016-06-30 13:02:42 -06001125 struct loader_device *device,
Jon Ashburn23d36b12016-02-02 17:47:28 -07001126 struct loader_layer_list *layer_list) {
Mark Young0ad83132016-06-30 13:02:42 -06001127 if (device) {
1128 loader_device_heap_free(device, layer_list->list);
1129 } else {
1130 loader_instance_heap_free(inst, layer_list->list);
1131 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001132 layer_list->count = 0;
1133 layer_list->capacity = 0;
1134}
1135
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001136/*
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001137 * Search the given layer list for a list
1138 * matching the given VkLayerProperties
1139 */
Jon Ashburn23d36b12016-02-02 17:47:28 -07001140bool has_vk_layer_property(const VkLayerProperties *vk_layer_prop,
1141 const struct loader_layer_list *list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001142 for (uint32_t i = 0; i < list->count; i++) {
1143 if (strcmp(vk_layer_prop->layerName, list->list[i].info.layerName) == 0)
1144 return true;
1145 }
1146 return false;
1147}
1148
1149/*
1150 * Search the given layer list for a layer
1151 * matching the given name
1152 */
Jon Ashburn23d36b12016-02-02 17:47:28 -07001153bool has_layer_name(const char *name, const struct loader_layer_list *list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001154 for (uint32_t i = 0; i < list->count; i++) {
1155 if (strcmp(name, list->list[i].info.layerName) == 0)
1156 return true;
1157 }
1158 return false;
1159}
1160
1161/*
1162 * Append non-duplicate layer properties defined in prop_list
1163 * to the given layer_info list
1164 */
Mark Young0ad83132016-06-30 13:02:42 -06001165VkResult loader_add_to_layer_list(const struct loader_instance *inst,
1166 struct loader_layer_list *list,
1167 uint32_t prop_list_count,
1168 const struct loader_layer_properties *props) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001169 uint32_t i;
1170 struct loader_layer_properties *layer;
1171
1172 if (list->list == NULL || list->capacity == 0) {
Jon Ashburne39a4f82015-08-28 13:38:21 -06001173 loader_init_layer_list(inst, list);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001174 }
1175
1176 if (list->list == NULL)
Mark Young0ad83132016-06-30 13:02:42 -06001177 return VK_SUCCESS;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001178
1179 for (i = 0; i < prop_list_count; i++) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001180 layer = (struct loader_layer_properties *)&props[i];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001181
1182 // look for duplicates
1183 if (has_vk_layer_property(&layer->info, list)) {
1184 continue;
1185 }
1186
1187 // add to list at end
1188 // check for enough capacity
Jon Ashburn23d36b12016-02-02 17:47:28 -07001189 if (list->count * sizeof(struct loader_layer_properties) >=
1190 list->capacity) {
Jon Ashburne39a4f82015-08-28 13:38:21 -06001191
Mark Young0ad83132016-06-30 13:02:42 -06001192 list->list = loader_instance_heap_realloc(
Jon Ashburn23d36b12016-02-02 17:47:28 -07001193 inst, list->list, list->capacity, list->capacity * 2,
1194 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0ad83132016-06-30 13:02:42 -06001195 if (NULL == list->list) {
1196 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001197 "loader_add_to_layer_list: Realloc failed for "
1198 "when attempting to add new layer");
Mark Young0ad83132016-06-30 13:02:42 -06001199 return VK_ERROR_OUT_OF_HOST_MEMORY;
1200 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001201 // double capacity
1202 list->capacity *= 2;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001203 }
1204
Jon Ashburn23d36b12016-02-02 17:47:28 -07001205 memcpy(&list->list[list->count], layer,
1206 sizeof(struct loader_layer_properties));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001207 list->count++;
1208 }
Mark Young0ad83132016-06-30 13:02:42 -06001209
1210 return VK_SUCCESS;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001211}
1212
Jon Ashburnbd332cc2015-07-07 10:27:45 -06001213/**
1214 * Search the search_list for any layer with a name
1215 * that matches the given name and a type that matches the given type
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001216 * Add all matching layers to the found_list
Jon Ashburnbd332cc2015-07-07 10:27:45 -06001217 * Do not add if found loader_layer_properties is already
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001218 * on the found_list.
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001219 */
Jon Ashburncc407a22016-04-15 09:25:03 -06001220void loader_find_layer_name_add_list(
1221 const struct loader_instance *inst, const char *name,
1222 const enum layer_type type, const struct loader_layer_list *search_list,
1223 struct loader_layer_list *found_list) {
Jon Ashburn56151d62015-10-05 09:03:21 -06001224 bool found = false;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001225 for (uint32_t i = 0; i < search_list->count; i++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001226 struct loader_layer_properties *layer_prop = &search_list->list[i];
Jon Ashburnbd332cc2015-07-07 10:27:45 -06001227 if (0 == strcmp(layer_prop->info.layerName, name) &&
Jon Ashburn23d36b12016-02-02 17:47:28 -07001228 (layer_prop->type & type)) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001229 /* Found a layer with the same name, add to found_list */
Mark Young0153e0b2016-11-03 14:27:13 -06001230 if (VK_SUCCESS ==
1231 loader_add_to_layer_list(inst, found_list, 1, layer_prop)) {
Mark Young0ad83132016-06-30 13:02:42 -06001232 found = true;
1233 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001234 }
1235 }
Jon Ashburn56151d62015-10-05 09:03:21 -06001236 if (!found) {
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07001237 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001238 "loader_find_layer_name_add_list: Failed to find layer name "
1239 "%s to activate",
1240 name);
Jon Ashburn56151d62015-10-05 09:03:21 -06001241 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001242}
1243
Jon Ashburn23d36b12016-02-02 17:47:28 -07001244static VkExtensionProperties *
1245get_extension_property(const char *name,
1246 const struct loader_extension_list *list) {
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06001247 for (uint32_t i = 0; i < list->count; i++) {
Chia-I Wu3432a0c2015-10-27 18:04:07 +08001248 if (strcmp(name, list->list[i].extensionName) == 0)
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06001249 return &list->list[i];
Jon Ashburnfc2e38c2015-04-14 09:15:32 -06001250 }
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06001251 return NULL;
Jon Ashburnfc2e38c2015-04-14 09:15:32 -06001252}
1253
Jon Ashburn23d36b12016-02-02 17:47:28 -07001254static VkExtensionProperties *
1255get_dev_extension_property(const char *name,
1256 const struct loader_device_extension_list *list) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001257 for (uint32_t i = 0; i < list->count; i++) {
1258 if (strcmp(name, list->list[i].props.extensionName) == 0)
1259 return &list->list[i].props;
1260 }
1261 return NULL;
1262}
1263
Courtney Goeltzenleuchterb39ccd52016-01-15 14:15:00 -07001264/*
Courtney Goeltzenleuchterf538ef72015-12-02 14:00:19 -07001265 * For Instance extensions implemented within the loader (i.e. DEBUG_REPORT
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001266 * the extension must provide two entry points for the loader to use:
1267 * - "trampoline" entry point - this is the address returned by GetProcAddr
1268 * and will always do what's necessary to support a global call.
1269 * - "terminator" function - this function will be put at the end of the
Jon Ashburn232e3af2015-11-30 17:21:25 -07001270 * instance chain and will contain the necessary logic to call / process
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001271 * the extension for the appropriate ICDs that are available.
1272 * There is no generic mechanism for including these functions, the references
1273 * must be placed into the appropriate loader entry points.
Jon Ashburn23d36b12016-02-02 17:47:28 -07001274 * GetInstanceProcAddr: call extension GetInstanceProcAddr to check for
1275 * GetProcAddr requests
1276 * loader_coalesce_extensions(void) - add extension records to the list of
1277 * global
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001278 * extension available to the app.
1279 * instance_disp - add function pointer for terminator function to this array.
1280 * The extension itself should be in a separate file that will be
1281 * linked directly with the loader.
1282 */
Jon Ashburn9a4c6aa2015-08-14 11:57:54 -06001283
Mark Young3a587792016-08-19 15:25:08 -06001284VkResult loader_get_icd_loader_instance_extensions(
Mark Young0153e0b2016-11-03 14:27:13 -06001285 const struct loader_instance *inst,
1286 struct loader_icd_tramp_list *icd_tramp_list,
Jon Ashburn23d36b12016-02-02 17:47:28 -07001287 struct loader_extension_list *inst_exts) {
Jon Ashburn5c6a46f2015-08-14 14:49:22 -06001288 struct loader_extension_list icd_exts;
Mark Young3a587792016-08-19 15:25:08 -06001289 VkResult res = VK_SUCCESS;
1290
Jon Ashburn23d36b12016-02-02 17:47:28 -07001291 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
1292 "Build ICD instance extension list");
Mark Young3a587792016-08-19 15:25:08 -06001293
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001294 // traverse scanned icd list adding non-duplicate extensions to the list
Mark Young0153e0b2016-11-03 14:27:13 -06001295 for (uint32_t i = 0; i < icd_tramp_list->count; i++) {
Mark Young3a587792016-08-19 15:25:08 -06001296 res = loader_init_generic_list(inst,
1297 (struct loader_generic_list *)&icd_exts,
1298 sizeof(VkExtensionProperties));
1299 if (VK_SUCCESS != res) {
1300 goto out;
1301 }
1302 res = loader_add_instance_extensions(
Mark Young0153e0b2016-11-03 14:27:13 -06001303 inst, icd_tramp_list->scanned_list[i]
1304 .EnumerateInstanceExtensionProperties,
1305 icd_tramp_list->scanned_list[i].lib_name, &icd_exts);
Mark Young3a587792016-08-19 15:25:08 -06001306 if (VK_SUCCESS == res) {
Lenny Komow4053b812016-12-29 16:27:28 -07001307 // Remove any extensions not recognized by the loader
1308 for (int32_t j = 0; j < (int32_t)icd_exts.count; j++) {
1309
1310 // See if the extension is in the list of supported extensions
1311 bool found = false;
1312 for (uint32_t k = 0; LOADER_INSTANCE_EXTENSIONS[k] != NULL;
1313 k++) {
1314 if (strcmp(icd_exts.list[j].extensionName,
1315 LOADER_INSTANCE_EXTENSIONS[k]) == 0) {
1316 found = true;
1317 break;
1318 }
1319 }
1320
1321 // If it isn't in the list, remove it
1322 if (!found) {
1323 for (uint32_t k = j + 1; k < icd_exts.count; k++) {
1324 icd_exts.list[k - 1] = icd_exts.list[k];
1325 }
1326 --icd_exts.count;
1327 --j;
1328 }
1329 }
1330
Mark Young3a587792016-08-19 15:25:08 -06001331 res = loader_add_to_ext_list(inst, inst_exts, icd_exts.count,
1332 icd_exts.list);
1333 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07001334 loader_destroy_generic_list(inst,
1335 (struct loader_generic_list *)&icd_exts);
Mark Young3a587792016-08-19 15:25:08 -06001336 if (VK_SUCCESS != res) {
1337 goto out;
1338 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001339 };
1340
Mark Young6267ae62017-01-12 12:27:19 -07001341
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001342 // Traverse loader's extensions, adding non-duplicate extensions to the list
Jon Ashburne39a4f82015-08-28 13:38:21 -06001343 debug_report_add_instance_extensions(inst, inst_exts);
Mark Young3a587792016-08-19 15:25:08 -06001344
1345out:
1346 return res;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001347}
1348
Mark Young0153e0b2016-11-03 14:27:13 -06001349struct loader_icd_term *
1350loader_get_icd_and_device(const VkDevice device,
1351 struct loader_device **found_dev,
1352 uint32_t *icd_index) {
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001353 *found_dev = NULL;
Mark Young16573c72016-06-28 10:52:43 -06001354 uint32_t index = 0;
Jon Ashburn23d36b12016-02-02 17:47:28 -07001355 for (struct loader_instance *inst = loader.instances; inst;
1356 inst = inst->next) {
Mark Young0153e0b2016-11-03 14:27:13 -06001357 for (struct loader_icd_term *icd_term = inst->icd_terms; icd_term;
1358 icd_term = icd_term->next) {
1359 for (struct loader_device *dev = icd_term->logical_device_list; dev;
Jon Ashburn23d36b12016-02-02 17:47:28 -07001360 dev = dev->next)
Mark Young65cb3662016-11-07 13:27:02 -07001361 // Value comparison of device prevents object wrapping by layers
1362 if (loader_get_dispatch(dev->icd_device) ==
1363 loader_get_dispatch(device) ||
1364 loader_get_dispatch(dev->chain_device) ==
Jon Ashburn23d36b12016-02-02 17:47:28 -07001365 loader_get_dispatch(device)) {
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001366 *found_dev = dev;
Mark Young16573c72016-06-28 10:52:43 -06001367 if (NULL != icd_index) {
1368 *icd_index = index;
1369 }
Mark Young0153e0b2016-11-03 14:27:13 -06001370 return icd_term;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001371 }
Mark Young16573c72016-06-28 10:52:43 -06001372 index++;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001373 }
1374 }
1375 return NULL;
1376}
1377
Mark Young0ad83132016-06-30 13:02:42 -06001378void loader_destroy_logical_device(const struct loader_instance *inst,
1379 struct loader_device *dev,
1380 const VkAllocationCallbacks *pAllocator) {
1381 if (pAllocator) {
1382 dev->alloc_callbacks = *pAllocator;
1383 }
Mark Young0ad83132016-06-30 13:02:42 -06001384 if (NULL != dev->activated_layer_list.list) {
1385 loader_deactivate_layers(inst, dev, &dev->activated_layer_list);
1386 }
1387 loader_device_heap_free(dev, dev);
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001388}
1389
Jon Ashburn1530c342016-02-26 13:14:27 -07001390struct loader_device *
Mark Young0ad83132016-06-30 13:02:42 -06001391loader_create_logical_device(const struct loader_instance *inst,
1392 const VkAllocationCallbacks *pAllocator) {
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001393 struct loader_device *new_dev;
Mark Young0ad83132016-06-30 13:02:42 -06001394#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
1395 {
1396#else
1397 if (pAllocator) {
1398 new_dev = (struct loader_device *)pAllocator->pfnAllocation(
1399 pAllocator->pUserData, sizeof(struct loader_device), sizeof(int *),
1400 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
1401 } else {
1402#endif
1403 new_dev = (struct loader_device *)malloc(sizeof(struct loader_device));
1404 }
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001405
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001406 if (!new_dev) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001407 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001408 "loader_create_logical_device: Failed to alloc struct "
1409 "loader_device");
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001410 return NULL;
1411 }
1412
1413 memset(new_dev, 0, sizeof(struct loader_device));
Mark Young0ad83132016-06-30 13:02:42 -06001414 if (pAllocator) {
1415 new_dev->alloc_callbacks = *pAllocator;
1416 }
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001417
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001418 return new_dev;
1419}
1420
Piers Daniell295fe402016-03-29 11:51:11 -06001421void loader_add_logical_device(const struct loader_instance *inst,
Mark Young0153e0b2016-11-03 14:27:13 -06001422 struct loader_icd_term *icd_term,
Piers Daniell295fe402016-03-29 11:51:11 -06001423 struct loader_device *dev) {
Mark Young0153e0b2016-11-03 14:27:13 -06001424 dev->next = icd_term->logical_device_list;
1425 icd_term->logical_device_list = dev;
Piers Daniell295fe402016-03-29 11:51:11 -06001426}
1427
Jon Ashburn23d36b12016-02-02 17:47:28 -07001428void loader_remove_logical_device(const struct loader_instance *inst,
Mark Young0153e0b2016-11-03 14:27:13 -06001429 struct loader_icd_term *icd_term,
Mark Young0ad83132016-06-30 13:02:42 -06001430 struct loader_device *found_dev,
1431 const VkAllocationCallbacks *pAllocator) {
Jon Ashburn781a7ae2015-11-19 15:43:26 -07001432 struct loader_device *dev, *prev_dev;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001433
Mark Young0153e0b2016-11-03 14:27:13 -06001434 if (!icd_term || !found_dev)
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001435 return;
1436
1437 prev_dev = NULL;
Mark Young0153e0b2016-11-03 14:27:13 -06001438 dev = icd_term->logical_device_list;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001439 while (dev && dev != found_dev) {
1440 prev_dev = dev;
1441 dev = dev->next;
1442 }
1443
1444 if (prev_dev)
1445 prev_dev->next = found_dev->next;
1446 else
Mark Young0153e0b2016-11-03 14:27:13 -06001447 icd_term->logical_device_list = found_dev->next;
Mark Young0ad83132016-06-30 13:02:42 -06001448 loader_destroy_logical_device(inst, found_dev, pAllocator);
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001449}
1450
Jon Ashburn23d36b12016-02-02 17:47:28 -07001451static void loader_icd_destroy(struct loader_instance *ptr_inst,
Mark Young0153e0b2016-11-03 14:27:13 -06001452 struct loader_icd_term *icd_term,
Mark Young0ad83132016-06-30 13:02:42 -06001453 const VkAllocationCallbacks *pAllocator) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001454 ptr_inst->total_icd_count--;
Mark Young0153e0b2016-11-03 14:27:13 -06001455 for (struct loader_device *dev = icd_term->logical_device_list; dev;) {
Courtney Goeltzenleuchter1f157ac2015-06-14 19:57:15 -06001456 struct loader_device *next_dev = dev->next;
Mark Young0ad83132016-06-30 13:02:42 -06001457 loader_destroy_logical_device(ptr_inst, dev, pAllocator);
Courtney Goeltzenleuchter1f157ac2015-06-14 19:57:15 -06001458 dev = next_dev;
1459 }
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001460
Mark Young0153e0b2016-11-03 14:27:13 -06001461 loader_instance_heap_free(ptr_inst, icd_term);
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001462}
1463
Mark Young0153e0b2016-11-03 14:27:13 -06001464static struct loader_icd_term *
Jon Ashburn23d36b12016-02-02 17:47:28 -07001465loader_icd_create(const struct loader_instance *inst) {
Mark Young0153e0b2016-11-03 14:27:13 -06001466 struct loader_icd_term *icd_term;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001467
Mark Young0153e0b2016-11-03 14:27:13 -06001468 icd_term = loader_instance_heap_alloc(inst, sizeof(struct loader_icd_term),
1469 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1470 if (!icd_term) {
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001471 return NULL;
Mark Youngdb13a2a2016-09-06 13:53:03 -06001472 }
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001473
Mark Young0153e0b2016-11-03 14:27:13 -06001474 memset(icd_term, 0, sizeof(struct loader_icd_term));
Courtney Goeltzenleuchter55001bb2014-10-28 10:29:27 -06001475
Mark Young0153e0b2016-11-03 14:27:13 -06001476 return icd_term;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001477}
1478
Mark Young0153e0b2016-11-03 14:27:13 -06001479static struct loader_icd_term *
Jon Ashburn23d36b12016-02-02 17:47:28 -07001480loader_icd_add(struct loader_instance *ptr_inst,
Mark Young0153e0b2016-11-03 14:27:13 -06001481 const struct loader_scanned_icd *scanned_icd) {
1482 struct loader_icd_term *icd_term;
Chia-I Wu13a61a52014-08-04 11:18:20 +08001483
Mark Young0153e0b2016-11-03 14:27:13 -06001484 icd_term = loader_icd_create(ptr_inst);
1485 if (!icd_term) {
Chia-I Wu13a61a52014-08-04 11:18:20 +08001486 return NULL;
Mark Youngdb13a2a2016-09-06 13:53:03 -06001487 }
Chia-I Wu13a61a52014-08-04 11:18:20 +08001488
Mark Young0153e0b2016-11-03 14:27:13 -06001489 icd_term->scanned_icd = scanned_icd;
1490 icd_term->this_instance = ptr_inst;
Jon Ashburn3d002332015-08-20 16:35:30 -06001491
Chia-I Wu13a61a52014-08-04 11:18:20 +08001492 /* prepend to the list */
Mark Young0153e0b2016-11-03 14:27:13 -06001493 icd_term->next = ptr_inst->icd_terms;
1494 ptr_inst->icd_terms = icd_term;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001495 ptr_inst->total_icd_count++;
Chia-I Wu13a61a52014-08-04 11:18:20 +08001496
Mark Young0153e0b2016-11-03 14:27:13 -06001497 return icd_term;
Chia-I Wu13a61a52014-08-04 11:18:20 +08001498}
Mark Young0153e0b2016-11-03 14:27:13 -06001499
Jon Ashburn17b4c862016-04-25 11:09:37 -06001500/**
1501 * Determine the ICD interface version to use.
1502 * @param icd
1503 * @param pVersion Output parameter indicating which version to use or 0 if
1504 * the negotiation API is not supported by the ICD
1505 * @return bool indicating true if the selected interface version is supported
1506 * by the loader, false indicates the version is not supported
1507 * version 0 doesn't support vk_icdGetInstanceProcAddr nor
1508 * vk_icdNegotiateLoaderICDInterfaceVersion
1509 * version 1 supports vk_icdGetInstanceProcAddr
1510 * version 2 supports vk_icdNegotiateLoaderICDInterfaceVersion
1511 */
1512bool loader_get_icd_interface_version(
Mark Young0153e0b2016-11-03 14:27:13 -06001513 PFN_vkNegotiateLoaderICDInterfaceVersion fp_negotiate_icd_version,
1514 uint32_t *pVersion) {
Jon Ashburn17b4c862016-04-25 11:09:37 -06001515
1516 if (fp_negotiate_icd_version == NULL) {
1517 // ICD does not support the negotiation API, it supports version 0 or 1
1518 // calling code must determine if it is version 0 or 1
1519 *pVersion = 0;
1520 } else {
1521 // ICD supports the negotiation API, so call it with the loader's
1522 // latest version supported
1523 *pVersion = CURRENT_LOADER_ICD_INTERFACE_VERSION;
1524 VkResult result = fp_negotiate_icd_version(pVersion);
1525
1526 if (result == VK_ERROR_INCOMPATIBLE_DRIVER) {
1527 // ICD no longer supports the loader's latest interface version so
1528 // fail loading the ICD
1529 return false;
1530 }
1531 }
1532
1533#if MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION > 0
1534 if (*pVersion < MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION) {
1535 // Loader no longer supports the ICD's latest interface version so fail
1536 // loading the ICD
1537 return false;
1538 }
1539#endif
1540 return true;
1541}
Chia-I Wu13a61a52014-08-04 11:18:20 +08001542
Jon Ashburn23d36b12016-02-02 17:47:28 -07001543void loader_scanned_icd_clear(const struct loader_instance *inst,
Mark Young0153e0b2016-11-03 14:27:13 -06001544 struct loader_icd_tramp_list *icd_tramp_list) {
1545 if (icd_tramp_list->capacity == 0)
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001546 return;
Mark Young0153e0b2016-11-03 14:27:13 -06001547 for (uint32_t i = 0; i < icd_tramp_list->count; i++) {
1548 loader_platform_close_library(icd_tramp_list->scanned_list[i].handle);
1549 loader_instance_heap_free(inst,
1550 icd_tramp_list->scanned_list[i].lib_name);
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001551 }
Mark Young0153e0b2016-11-03 14:27:13 -06001552 loader_instance_heap_free(inst, icd_tramp_list->scanned_list);
1553 icd_tramp_list->capacity = 0;
1554 icd_tramp_list->count = 0;
1555 icd_tramp_list->scanned_list = NULL;
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001556}
1557
Mark Young0153e0b2016-11-03 14:27:13 -06001558static VkResult
1559loader_scanned_icd_init(const struct loader_instance *inst,
1560 struct loader_icd_tramp_list *icd_tramp_list) {
Mark Young0ad83132016-06-30 13:02:42 -06001561 VkResult err = VK_SUCCESS;
Mark Young0153e0b2016-11-03 14:27:13 -06001562 loader_scanned_icd_clear(inst, icd_tramp_list);
1563 icd_tramp_list->capacity = 8 * sizeof(struct loader_scanned_icd);
1564 icd_tramp_list->scanned_list = loader_instance_heap_alloc(
1565 inst, icd_tramp_list->capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1566 if (NULL == icd_tramp_list->scanned_list) {
1567 loader_log(
1568 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001569 "loader_scanned_icd_init: Realloc failed for layer list when "
1570 "attempting to add new layer");
Mark Young0ad83132016-06-30 13:02:42 -06001571 err = VK_ERROR_OUT_OF_HOST_MEMORY;
1572 }
1573 return err;
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001574}
1575
Mark Young0153e0b2016-11-03 14:27:13 -06001576static VkResult
1577loader_scanned_icd_add(const struct loader_instance *inst,
1578 struct loader_icd_tramp_list *icd_tramp_list,
1579 const char *filename, uint32_t api_version) {
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001580 loader_platform_dl_handle handle;
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06001581 PFN_vkCreateInstance fp_create_inst;
Jon Ashburnfd4d09d2016-01-07 09:44:27 -07001582 PFN_vkEnumerateInstanceExtensionProperties fp_get_inst_ext_props;
Jon Ashburnc624c882015-07-16 10:17:29 -06001583 PFN_vkGetInstanceProcAddr fp_get_proc_addr;
Jon Ashburn17b4c862016-04-25 11:09:37 -06001584 PFN_vkNegotiateLoaderICDInterfaceVersion fp_negotiate_icd_version;
Mark Young0153e0b2016-11-03 14:27:13 -06001585 struct loader_scanned_icd *new_scanned_icd;
Jon Ashburn17b4c862016-04-25 11:09:37 -06001586 uint32_t interface_vers;
Mark Young3a587792016-08-19 15:25:08 -06001587 VkResult res = VK_SUCCESS;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001588
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06001589 /* TODO implement smarter opening/closing of libraries. For now this
1590 * function leaves libraries open and the scanned_icd_clear closes them */
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001591 handle = loader_platform_open_library(filename);
Mark Youngb6399312017-01-10 14:22:15 -07001592 if (NULL == handle) {
1593 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -07001594 loader_platform_open_library_error(filename));
Mark Young3a587792016-08-19 15:25:08 -06001595 goto out;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001596 }
1597
Jon Ashburn17b4c862016-04-25 11:09:37 -06001598 // Get and settle on an ICD interface version
Mark Young0ad83132016-06-30 13:02:42 -06001599 fp_negotiate_icd_version = loader_platform_get_proc_address(
1600 handle, "vk_icdNegotiateLoaderICDInterfaceVersion");
Jon Ashburn17b4c862016-04-25 11:09:37 -06001601
1602 if (!loader_get_icd_interface_version(fp_negotiate_icd_version,
Mark Young0ad83132016-06-30 13:02:42 -06001603 &interface_vers)) {
1604 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001605 "loader_scanned_icd_add: ICD %s doesn't support interface"
1606 " version compatible with loader, skip this ICD.",
Mark Young0ad83132016-06-30 13:02:42 -06001607 filename);
Mark Young3a587792016-08-19 15:25:08 -06001608 goto out;
Jon Ashburn17b4c862016-04-25 11:09:37 -06001609 }
1610
Jon Ashburn23d36b12016-02-02 17:47:28 -07001611 fp_get_proc_addr =
1612 loader_platform_get_proc_address(handle, "vk_icdGetInstanceProcAddr");
Mark Youngb6399312017-01-10 14:22:15 -07001613 if (NULL == fp_get_proc_addr) {
Jon Ashburn17b4c862016-04-25 11:09:37 -06001614 assert(interface_vers == 0);
1615 // Use deprecated interface from version 0
Jon Ashburn23d36b12016-02-02 17:47:28 -07001616 fp_get_proc_addr =
1617 loader_platform_get_proc_address(handle, "vkGetInstanceProcAddr");
Mark Youngb6399312017-01-10 14:22:15 -07001618 if (NULL == fp_get_proc_addr) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001619 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001620 "loader_scanned_icd_add: Attempt to retreive either "
1621 " \'vkGetInstanceProcAddr\' or "
1622 "\'vk_icdGetInstanceProcAddr\' from ICD %s failed.",
1623 filename);
Mark Young3a587792016-08-19 15:25:08 -06001624 goto out;
Jon Ashburnfd4d09d2016-01-07 09:44:27 -07001625 } else {
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07001626 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001627 "loader_scanned_icd_add: Using deprecated ICD "
1628 "interface of \'vkGetInstanceProcAddr\' instead of "
1629 "\'vk_icdGetInstanceProcAddr\' for ICD %s",
Mark Young0ad83132016-06-30 13:02:42 -06001630 filename);
Jon Ashburnfd4d09d2016-01-07 09:44:27 -07001631 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07001632 fp_create_inst =
1633 loader_platform_get_proc_address(handle, "vkCreateInstance");
Mark Youngb6399312017-01-10 14:22:15 -07001634 if (NULL == fp_create_inst) {
Mark Young0ad83132016-06-30 13:02:42 -06001635 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001636 "loader_scanned_icd_add: Failed querying "
1637 "\'vkCreateInstance\' via dlsym/loadlibrary for "
1638 "ICD %s",
Mark Young0ad83132016-06-30 13:02:42 -06001639 filename);
Mark Young3a587792016-08-19 15:25:08 -06001640 goto out;
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001641 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07001642 fp_get_inst_ext_props = loader_platform_get_proc_address(
1643 handle, "vkEnumerateInstanceExtensionProperties");
Mark Youngb6399312017-01-10 14:22:15 -07001644 if (NULL == fp_get_inst_ext_props) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001645 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001646 "loader_scanned_icd_add: Could not get \'vkEnumerate"
1647 "InstanceExtensionProperties\' via dlsym/loadlibrary "
1648 "for ICD %s",
Mark Young0ad83132016-06-30 13:02:42 -06001649 filename);
Mark Young3a587792016-08-19 15:25:08 -06001650 goto out;
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001651 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07001652 } else {
Jon Ashburn17b4c862016-04-25 11:09:37 -06001653 // Use newer interface version 1 or later
1654 if (interface_vers == 0)
1655 interface_vers = 1;
1656
Jon Ashburn23d36b12016-02-02 17:47:28 -07001657 fp_create_inst =
1658 (PFN_vkCreateInstance)fp_get_proc_addr(NULL, "vkCreateInstance");
Mark Youngb6399312017-01-10 14:22:15 -07001659 if (NULL == fp_create_inst) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001660 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001661 "loader_scanned_icd_add: Could not get "
1662 "\'vkCreateInstance\' via \'vk_icdGetInstanceProcAddr\'"
1663 " for ICD %s",
Mark Young0ad83132016-06-30 13:02:42 -06001664 filename);
Mark Young3a587792016-08-19 15:25:08 -06001665 goto out;
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001666 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07001667 fp_get_inst_ext_props =
1668 (PFN_vkEnumerateInstanceExtensionProperties)fp_get_proc_addr(
1669 NULL, "vkEnumerateInstanceExtensionProperties");
Mark Youngb6399312017-01-10 14:22:15 -07001670 if (NULL == fp_get_inst_ext_props) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001671 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001672 "loader_scanned_icd_add: Could not get \'vkEnumerate"
1673 "InstanceExtensionProperties\' via "
1674 "\'vk_icdGetInstanceProcAddr\' for ICD %s",
Mark Young0ad83132016-06-30 13:02:42 -06001675 filename);
Mark Young3a587792016-08-19 15:25:08 -06001676 goto out;
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001677 }
Jon Ashburnfd4d09d2016-01-07 09:44:27 -07001678 }
Jon Ashburn46d1f582015-01-28 11:01:35 -07001679
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001680 // check for enough capacity
Mark Young0153e0b2016-11-03 14:27:13 -06001681 if ((icd_tramp_list->count * sizeof(struct loader_scanned_icd)) >=
1682 icd_tramp_list->capacity) {
Jon Ashburne39a4f82015-08-28 13:38:21 -06001683
Mark Young0153e0b2016-11-03 14:27:13 -06001684 icd_tramp_list->scanned_list = loader_instance_heap_realloc(
1685 inst, icd_tramp_list->scanned_list, icd_tramp_list->capacity,
1686 icd_tramp_list->capacity * 2, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1687 if (NULL == icd_tramp_list->scanned_list) {
Mark Young3a587792016-08-19 15:25:08 -06001688 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young0ad83132016-06-30 13:02:42 -06001689 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001690 "loader_scanned_icd_add: Realloc failed on icd library"
1691 " list for ICD %s",
1692 filename);
Mark Young3a587792016-08-19 15:25:08 -06001693 goto out;
Mark Young0ad83132016-06-30 13:02:42 -06001694 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07001695 // double capacity
Mark Young0153e0b2016-11-03 14:27:13 -06001696 icd_tramp_list->capacity *= 2;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001697 }
Mark Young0153e0b2016-11-03 14:27:13 -06001698 new_scanned_icd = &(icd_tramp_list->scanned_list[icd_tramp_list->count]);
Jon Ashburn46d1f582015-01-28 11:01:35 -07001699
Mark Young0153e0b2016-11-03 14:27:13 -06001700 new_scanned_icd->handle = handle;
1701 new_scanned_icd->api_version = api_version;
1702 new_scanned_icd->GetInstanceProcAddr = fp_get_proc_addr;
1703 new_scanned_icd->EnumerateInstanceExtensionProperties =
1704 fp_get_inst_ext_props;
1705 new_scanned_icd->CreateInstance = fp_create_inst;
1706 new_scanned_icd->interface_version = interface_vers;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001707
Mark Young0153e0b2016-11-03 14:27:13 -06001708 new_scanned_icd->lib_name = (char *)loader_instance_heap_alloc(
Jon Ashburn23d36b12016-02-02 17:47:28 -07001709 inst, strlen(filename) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0153e0b2016-11-03 14:27:13 -06001710 if (NULL == new_scanned_icd->lib_name) {
Mark Youngb6399312017-01-10 14:22:15 -07001711 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1712 "loader_scanned_icd_add: Out of memory can't add ICD %s",
1713 filename);
Mark Young3a587792016-08-19 15:25:08 -06001714 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young3a587792016-08-19 15:25:08 -06001715 goto out;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001716 }
Mark Young0153e0b2016-11-03 14:27:13 -06001717 strcpy(new_scanned_icd->lib_name, filename);
1718 icd_tramp_list->count++;
Mark Young3a587792016-08-19 15:25:08 -06001719
1720out:
1721
1722 return res;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001723}
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001724
Mark Young0153e0b2016-11-03 14:27:13 -06001725static bool loader_icd_init_entrys(struct loader_icd_term *icd_term,
1726 VkInstance inst,
Jon Ashburn23d36b12016-02-02 17:47:28 -07001727 const PFN_vkGetInstanceProcAddr fp_gipa) {
1728/* initialize entrypoint function pointers */
Jon Ashburn3da71f22015-05-14 12:43:38 -06001729
Jon Ashburn23d36b12016-02-02 17:47:28 -07001730#define LOOKUP_GIPA(func, required) \
1731 do { \
Mark Young0153e0b2016-11-03 14:27:13 -06001732 icd_term->func = (PFN_vk##func)fp_gipa(inst, "vk" #func); \
1733 if (!icd_term->func && required) { \
Jon Ashburn23d36b12016-02-02 17:47:28 -07001734 loader_log((struct loader_instance *)inst, \
Jon Ashburn1530c342016-02-26 13:14:27 -07001735 VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, \
Jon Ashburn23d36b12016-02-02 17:47:28 -07001736 loader_platform_get_proc_address_error("vk" #func)); \
1737 return false; \
1738 } \
Jon Ashburn3da71f22015-05-14 12:43:38 -06001739 } while (0)
1740
Jon Ashburnc624c882015-07-16 10:17:29 -06001741 LOOKUP_GIPA(GetDeviceProcAddr, true);
1742 LOOKUP_GIPA(DestroyInstance, true);
1743 LOOKUP_GIPA(EnumeratePhysicalDevices, true);
1744 LOOKUP_GIPA(GetPhysicalDeviceFeatures, true);
1745 LOOKUP_GIPA(GetPhysicalDeviceFormatProperties, true);
Jon Ashburn754864f2015-07-23 18:49:07 -06001746 LOOKUP_GIPA(GetPhysicalDeviceImageFormatProperties, true);
Jon Ashburnc624c882015-07-16 10:17:29 -06001747 LOOKUP_GIPA(CreateDevice, true);
1748 LOOKUP_GIPA(GetPhysicalDeviceProperties, true);
1749 LOOKUP_GIPA(GetPhysicalDeviceMemoryProperties, true);
Cody Northropd0802882015-08-03 17:04:53 -06001750 LOOKUP_GIPA(GetPhysicalDeviceQueueFamilyProperties, true);
Courtney Goeltzenleuchter35985f62015-09-14 17:22:16 -06001751 LOOKUP_GIPA(EnumerateDeviceExtensionProperties, true);
Jon Ashburnc624c882015-07-16 10:17:29 -06001752 LOOKUP_GIPA(GetPhysicalDeviceSparseImageFormatProperties, true);
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07001753 LOOKUP_GIPA(CreateDebugReportCallbackEXT, false);
1754 LOOKUP_GIPA(DestroyDebugReportCallbackEXT, false);
Mark Young65cb3662016-11-07 13:27:02 -07001755 LOOKUP_GIPA(DebugMarkerSetObjectTagEXT, false);
1756 LOOKUP_GIPA(DebugMarkerSetObjectNameEXT, false);
Ian Elliott7e40db92015-08-21 15:09:33 -06001757 LOOKUP_GIPA(GetPhysicalDeviceSurfaceSupportKHR, false);
Ian Elliott486c5502015-11-19 16:05:09 -07001758 LOOKUP_GIPA(GetPhysicalDeviceSurfaceCapabilitiesKHR, false);
1759 LOOKUP_GIPA(GetPhysicalDeviceSurfaceFormatsKHR, false);
1760 LOOKUP_GIPA(GetPhysicalDeviceSurfacePresentModesKHR, false);
Petros Bantolas25d27fe2016-04-14 12:50:42 +01001761 LOOKUP_GIPA(GetPhysicalDeviceDisplayPropertiesKHR, false);
1762 LOOKUP_GIPA(GetDisplayModePropertiesKHR, false);
1763 LOOKUP_GIPA(CreateDisplayPlaneSurfaceKHR, false);
1764 LOOKUP_GIPA(GetPhysicalDeviceDisplayPlanePropertiesKHR, false);
1765 LOOKUP_GIPA(GetDisplayPlaneSupportedDisplaysKHR, false);
1766 LOOKUP_GIPA(CreateDisplayModeKHR, false);
1767 LOOKUP_GIPA(GetDisplayPlaneCapabilitiesKHR, false);
1768 LOOKUP_GIPA(DestroySurfaceKHR, false);
Mark Young16573c72016-06-28 10:52:43 -06001769 LOOKUP_GIPA(CreateSwapchainKHR, false);
Ian Elliott919fa302015-11-24 15:39:10 -07001770#ifdef VK_USE_PLATFORM_WIN32_KHR
Mark Young16573c72016-06-28 10:52:43 -06001771 LOOKUP_GIPA(CreateWin32SurfaceKHR, false);
Ian Elliott919fa302015-11-24 15:39:10 -07001772 LOOKUP_GIPA(GetPhysicalDeviceWin32PresentationSupportKHR, false);
1773#endif
1774#ifdef VK_USE_PLATFORM_XCB_KHR
Mark Young16573c72016-06-28 10:52:43 -06001775 LOOKUP_GIPA(CreateXcbSurfaceKHR, false);
Ian Elliott919fa302015-11-24 15:39:10 -07001776 LOOKUP_GIPA(GetPhysicalDeviceXcbPresentationSupportKHR, false);
1777#endif
Karl Schultz65d20182016-03-08 07:55:27 -07001778#ifdef VK_USE_PLATFORM_XLIB_KHR
Mark Young16573c72016-06-28 10:52:43 -06001779 LOOKUP_GIPA(CreateXlibSurfaceKHR, false);
Karl Schultz65d20182016-03-08 07:55:27 -07001780 LOOKUP_GIPA(GetPhysicalDeviceXlibPresentationSupportKHR, false);
1781#endif
Mark Younga7c51fd2016-09-16 10:18:42 -06001782#ifdef VK_USE_PLATFORM_MIR_KHR
1783 LOOKUP_GIPA(CreateMirSurfaceKHR, false);
1784 LOOKUP_GIPA(GetPhysicalDeviceMirPresentationSupportKHR, false);
1785#endif
Jason Ekstranda5ebe8a2016-02-12 17:25:03 -08001786#ifdef VK_USE_PLATFORM_WAYLAND_KHR
Mark Young16573c72016-06-28 10:52:43 -06001787 LOOKUP_GIPA(CreateWaylandSurfaceKHR, false);
Jason Ekstranda5ebe8a2016-02-12 17:25:03 -08001788 LOOKUP_GIPA(GetPhysicalDeviceWaylandPresentationSupportKHR, false);
1789#endif
Mark Youngfa552782016-12-12 16:14:55 -07001790 // NV_external_memory_capabilities
James Jones389dc0c2016-08-18 23:41:19 +01001791 LOOKUP_GIPA(GetPhysicalDeviceExternalImageFormatPropertiesNV, false);
Mark Youngfa552782016-12-12 16:14:55 -07001792 // NVX_device_generated_commands
1793 LOOKUP_GIPA(GetPhysicalDeviceGeneratedCommandsPropertiesNVX, false);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001794
Jon Ashburnc624c882015-07-16 10:17:29 -06001795#undef LOOKUP_GIPA
Ian Elliottd3ef02f2015-07-06 14:36:13 -06001796
Jon Ashburnc624c882015-07-16 10:17:29 -06001797 return true;
Jon Ashburn3da71f22015-05-14 12:43:38 -06001798}
1799
Jon Ashburn23d36b12016-02-02 17:47:28 -07001800static void loader_debug_init(void) {
Mark Young0ad83132016-06-30 13:02:42 -06001801 char *env, *orig;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001802
1803 if (g_loader_debug > 0)
1804 return;
1805
1806 g_loader_debug = 0;
1807
1808 /* parse comma-separated debug options */
Mark Young0ad83132016-06-30 13:02:42 -06001809 orig = env = loader_getenv("VK_LOADER_DEBUG", NULL);
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001810 while (env) {
Mark Young0ad83132016-06-30 13:02:42 -06001811 char *p = strchr(env, ',');
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001812 size_t len;
1813
1814 if (p)
1815 len = p - env;
1816 else
1817 len = strlen(env);
1818
1819 if (len > 0) {
Michael Worcester25c73e72015-12-10 18:06:24 +00001820 if (strncmp(env, "all", len) == 0) {
1821 g_loader_debug = ~0u;
1822 g_loader_log_msgs = ~0u;
1823 } else if (strncmp(env, "warn", len) == 0) {
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001824 g_loader_debug |= LOADER_WARN_BIT;
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07001825 g_loader_log_msgs |= VK_DEBUG_REPORT_WARNING_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001826 } else if (strncmp(env, "info", len) == 0) {
1827 g_loader_debug |= LOADER_INFO_BIT;
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07001828 g_loader_log_msgs |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001829 } else if (strncmp(env, "perf", len) == 0) {
1830 g_loader_debug |= LOADER_PERF_BIT;
Jon Ashburn1530c342016-02-26 13:14:27 -07001831 g_loader_log_msgs |=
1832 VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001833 } else if (strncmp(env, "error", len) == 0) {
1834 g_loader_debug |= LOADER_ERROR_BIT;
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07001835 g_loader_log_msgs |= VK_DEBUG_REPORT_ERROR_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001836 } else if (strncmp(env, "debug", len) == 0) {
1837 g_loader_debug |= LOADER_DEBUG_BIT;
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07001838 g_loader_log_msgs |= VK_DEBUG_REPORT_DEBUG_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001839 }
1840 }
1841
1842 if (!p)
1843 break;
1844
1845 env = p + 1;
1846 }
Jon Ashburn38a497f2016-01-04 14:01:38 -07001847
Mark Young0ad83132016-06-30 13:02:42 -06001848 loader_free_getenv(orig, NULL);
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001849}
1850
Jon Ashburn23d36b12016-02-02 17:47:28 -07001851void loader_initialize(void) {
Jon Ashburn6461ef22015-09-22 13:11:00 -06001852 // initialize mutexs
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001853 loader_platform_thread_create_mutex(&loader_lock);
Jon Ashburn6461ef22015-09-22 13:11:00 -06001854 loader_platform_thread_create_mutex(&loader_json_lock);
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001855
1856 // initialize logging
1857 loader_debug_init();
Jon Ashburn87d6aa92015-08-28 15:19:27 -06001858
1859 // initial cJSON to use alloc callbacks
1860 cJSON_Hooks alloc_fns = {
Mark Young0ad83132016-06-30 13:02:42 -06001861 .malloc_fn = loader_instance_tls_heap_alloc,
1862 .free_fn = loader_instance_tls_heap_free,
Jon Ashburn87d6aa92015-08-28 15:19:27 -06001863 };
1864 cJSON_InitHooks(&alloc_fns);
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001865}
1866
Jon Ashburn2077e382015-06-29 11:25:34 -06001867struct loader_manifest_files {
1868 uint32_t count;
1869 char **filename_list;
1870};
1871
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001872/**
Jon Ashburn2077e382015-06-29 11:25:34 -06001873 * Get next file or dirname given a string list or registry key path
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001874 *
1875 * \returns
Jon Ashburn2077e382015-06-29 11:25:34 -06001876 * A pointer to first char in the next path.
1877 * The next path (or NULL) in the list is returned in next_path.
1878 * Note: input string is modified in some cases. PASS IN A COPY!
1879 */
Jon Ashburn23d36b12016-02-02 17:47:28 -07001880static char *loader_get_next_path(char *path) {
Jon Ashburn2077e382015-06-29 11:25:34 -06001881 uint32_t len;
1882 char *next;
1883
1884 if (path == NULL)
1885 return NULL;
Frank Henigman57173102016-11-24 22:15:20 -05001886 next = strchr(path, PATH_SEPARATOR);
Jon Ashburn2077e382015-06-29 11:25:34 -06001887 if (next == NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001888 len = (uint32_t)strlen(path);
Jon Ashburn2077e382015-06-29 11:25:34 -06001889 next = path + len;
Jon Ashburn23d36b12016-02-02 17:47:28 -07001890 } else {
Jon Ashburn2077e382015-06-29 11:25:34 -06001891 *next = '\0';
1892 next++;
1893 }
1894
1895 return next;
1896}
1897
1898/**
Daniel Dadap00b4aba2015-09-30 11:50:51 -05001899 * Given a path which is absolute or relative, expand the path if relative or
1900 * leave the path unmodified if absolute. The base path to prepend to relative
1901 * paths is given in rel_base.
Jon Ashburn15315172015-07-07 15:06:25 -06001902 *
1903 * \returns
1904 * A string in out_fullpath of the full absolute path
Jon Ashburn15315172015-07-07 15:06:25 -06001905 */
Jon Ashburn23d36b12016-02-02 17:47:28 -07001906static void loader_expand_path(const char *path, const char *rel_base,
1907 size_t out_size, char *out_fullpath) {
Jon Ashburn15315172015-07-07 15:06:25 -06001908 if (loader_platform_is_path_absolute(path)) {
Daniel Dadap00b4aba2015-09-30 11:50:51 -05001909 // do not prepend a base to an absolute path
1910 rel_base = "";
Jon Ashburn15315172015-07-07 15:06:25 -06001911 }
Daniel Dadap00b4aba2015-09-30 11:50:51 -05001912
1913 loader_platform_combine_path(out_fullpath, out_size, rel_base, path, NULL);
Jon Ashburn15315172015-07-07 15:06:25 -06001914}
1915
1916/**
Jon Ashburn2077e382015-06-29 11:25:34 -06001917 * Given a filename (file) and a list of paths (dir), try to find an existing
1918 * file in the paths. If filename already is a path then no
1919 * searching in the given paths.
1920 *
1921 * \returns
1922 * A string in out_fullpath of either the full path or file.
Jon Ashburn2077e382015-06-29 11:25:34 -06001923 */
Jon Ashburn23d36b12016-02-02 17:47:28 -07001924static void loader_get_fullpath(const char *file, const char *dirs,
1925 size_t out_size, char *out_fullpath) {
Daniel Dadap00b4aba2015-09-30 11:50:51 -05001926 if (!loader_platform_is_path(file) && *dirs) {
1927 char *dirs_copy, *dir, *next_dir;
1928
1929 dirs_copy = loader_stack_alloc(strlen(dirs) + 1);
1930 strcpy(dirs_copy, dirs);
1931
Jon Ashburn23d36b12016-02-02 17:47:28 -07001932 // find if file exists after prepending paths in given list
1933 for (dir = dirs_copy; *dir && (next_dir = loader_get_next_path(dir));
Daniel Dadap00b4aba2015-09-30 11:50:51 -05001934 dir = next_dir) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001935 loader_platform_combine_path(out_fullpath, out_size, dir, file,
1936 NULL);
Jon Ashburn2077e382015-06-29 11:25:34 -06001937 if (loader_platform_file_exists(out_fullpath)) {
1938 return;
1939 }
Jon Ashburn2077e382015-06-29 11:25:34 -06001940 }
1941 }
Daniel Dadap00b4aba2015-09-30 11:50:51 -05001942
Jon Ashburn2077e382015-06-29 11:25:34 -06001943 snprintf(out_fullpath, out_size, "%s", file);
1944}
1945
1946/**
1947 * Read a JSON file into a buffer.
1948 *
1949 * \returns
1950 * A pointer to a cJSON object representing the JSON parse tree.
1951 * This returned buffer should be freed by caller.
1952 */
Mark Young3a587792016-08-19 15:25:08 -06001953static VkResult loader_get_json(const struct loader_instance *inst,
1954 const char *filename, cJSON **json) {
1955 FILE *file = NULL;
Jon Ashburn2077e382015-06-29 11:25:34 -06001956 char *json_buf;
Mark Young93ecb1d2016-01-13 13:47:16 -07001957 size_t len;
Mark Young3a587792016-08-19 15:25:08 -06001958 VkResult res = VK_SUCCESS;
1959
1960 if (NULL == json) {
Mark Youngb6399312017-01-10 14:22:15 -07001961 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1962 "loader_get_json: Received invalid JSON file");
Mark Young3a587792016-08-19 15:25:08 -06001963 res = VK_ERROR_INITIALIZATION_FAILED;
1964 goto out;
1965 }
1966
1967 *json = NULL;
1968
Jon Ashburn23d36b12016-02-02 17:47:28 -07001969 file = fopen(filename, "rb");
Jon Ashburnaa4ea472015-08-27 08:30:50 -06001970 if (!file) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001971 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001972 "loader_get_json: Failed to open JSON file %s", filename);
1973 res = VK_ERROR_INITIALIZATION_FAILED;
Mark Young3a587792016-08-19 15:25:08 -06001974 goto out;
Jon Ashburnaa4ea472015-08-27 08:30:50 -06001975 }
Jon Ashburn2077e382015-06-29 11:25:34 -06001976 fseek(file, 0, SEEK_END);
1977 len = ftell(file);
1978 fseek(file, 0, SEEK_SET);
Jon Ashburn23d36b12016-02-02 17:47:28 -07001979 json_buf = (char *)loader_stack_alloc(len + 1);
Jon Ashburn2077e382015-06-29 11:25:34 -06001980 if (json_buf == NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001981 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001982 "loader_get_json: Failed to allocate space for "
1983 " JSON file %s buffer of length %d",
1984 filename, len);
1985 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young3a587792016-08-19 15:25:08 -06001986 goto out;
Jon Ashburn2077e382015-06-29 11:25:34 -06001987 }
1988 if (fread(json_buf, sizeof(char), len, file) != len) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001989 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001990 "loader_get_json: Failed to read JSON file %s.", filename);
1991 res = VK_ERROR_INITIALIZATION_FAILED;
Mark Young3a587792016-08-19 15:25:08 -06001992 goto out;
Jon Ashburn2077e382015-06-29 11:25:34 -06001993 }
Jon Ashburn2077e382015-06-29 11:25:34 -06001994 json_buf[len] = '\0';
1995
Jon Ashburn23d36b12016-02-02 17:47:28 -07001996 // parse text from file
Mark Young3a587792016-08-19 15:25:08 -06001997 *json = cJSON_Parse(json_buf);
1998 if (*json == NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001999 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002000 "loader_get_json: Failed to parse JSON file %s, "
2001 " this is usually because something ran out of "
2002 " memory.",
2003 filename);
2004 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young3a587792016-08-19 15:25:08 -06002005 goto out;
2006 }
2007
2008out:
2009 if (NULL != file) {
2010 fclose(file);
2011 }
2012
2013 return res;
Jon Ashburn2077e382015-06-29 11:25:34 -06002014}
2015
2016/**
Jon Ashburn3d002332015-08-20 16:35:30 -06002017 * Do a deep copy of the loader_layer_properties structure.
2018 */
Mark Young0ad83132016-06-30 13:02:42 -06002019VkResult loader_copy_layer_properties(const struct loader_instance *inst,
2020 struct loader_layer_properties *dst,
2021 struct loader_layer_properties *src) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07002022 uint32_t cnt, i;
Jon Ashburn23d36b12016-02-02 17:47:28 -07002023 memcpy(dst, src, sizeof(*src));
Mark Youngb6399312017-01-10 14:22:15 -07002024 dst->instance_extension_list.list = loader_instance_heap_alloc(
2025 inst,
2026 sizeof(VkExtensionProperties) * src->instance_extension_list.count,
2027 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0ad83132016-06-30 13:02:42 -06002028 if (NULL == dst->instance_extension_list.list) {
2029 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002030 "loader_copy_layer_properties: Failed to allocate space "
2031 " for instance extension list of size %d.",
2032 src->instance_extension_list.count);
Mark Young0ad83132016-06-30 13:02:42 -06002033 return VK_ERROR_OUT_OF_HOST_MEMORY;
2034 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07002035 dst->instance_extension_list.capacity =
2036 sizeof(VkExtensionProperties) * src->instance_extension_list.count;
Jon Ashburne39a4f82015-08-28 13:38:21 -06002037 memcpy(dst->instance_extension_list.list, src->instance_extension_list.list,
Jon Ashburn23d36b12016-02-02 17:47:28 -07002038 dst->instance_extension_list.capacity);
Mark Youngb6399312017-01-10 14:22:15 -07002039 dst->device_extension_list.list = loader_instance_heap_alloc(
2040 inst,
2041 sizeof(struct loader_dev_ext_props) * src->device_extension_list.count,
2042 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0ad83132016-06-30 13:02:42 -06002043 if (NULL == dst->device_extension_list.list) {
2044 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002045 "loader_copy_layer_properties: Failed to allocate space "
2046 " for device extension list of size %d.",
2047 src->device_extension_list.count);
Mark Young0ad83132016-06-30 13:02:42 -06002048 return VK_ERROR_OUT_OF_HOST_MEMORY;
2049 }
Mark Young0153e0b2016-11-03 14:27:13 -06002050 memset(dst->device_extension_list.list, 0,
2051 sizeof(struct loader_dev_ext_props) *
2052 src->device_extension_list.count);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07002053
Jon Ashburn23d36b12016-02-02 17:47:28 -07002054 dst->device_extension_list.capacity =
2055 sizeof(struct loader_dev_ext_props) * src->device_extension_list.count;
Jon Ashburne39a4f82015-08-28 13:38:21 -06002056 memcpy(dst->device_extension_list.list, src->device_extension_list.list,
Jon Ashburn23d36b12016-02-02 17:47:28 -07002057 dst->device_extension_list.capacity);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07002058 if (src->device_extension_list.count > 0 &&
Jon Ashburn23d36b12016-02-02 17:47:28 -07002059 src->device_extension_list.list->entrypoint_count > 0) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07002060 cnt = src->device_extension_list.list->entrypoint_count;
Mark Young0ad83132016-06-30 13:02:42 -06002061 dst->device_extension_list.list->entrypoints =
2062 loader_instance_heap_alloc(inst, sizeof(char *) * cnt,
2063 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2064 if (NULL == dst->device_extension_list.list->entrypoints) {
Mark Youngb6399312017-01-10 14:22:15 -07002065 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2066 "loader_copy_layer_properties: Failed to allocate space "
2067 " for device extension entrypoint list of size %d.",
2068 cnt);
Mark Young0ad83132016-06-30 13:02:42 -06002069 return VK_ERROR_OUT_OF_HOST_MEMORY;
2070 }
Mark Young0153e0b2016-11-03 14:27:13 -06002071 memset(dst->device_extension_list.list->entrypoints, 0,
2072 sizeof(char *) * cnt);
Mark Young0ad83132016-06-30 13:02:42 -06002073
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07002074 for (i = 0; i < cnt; i++) {
Mark Young0ad83132016-06-30 13:02:42 -06002075 dst->device_extension_list.list->entrypoints[i] =
2076 loader_instance_heap_alloc(
2077 inst,
2078 strlen(src->device_extension_list.list->entrypoints[i]) + 1,
2079 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2080 if (NULL == dst->device_extension_list.list->entrypoints[i]) {
Mark Youngb6399312017-01-10 14:22:15 -07002081 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2082 "loader_copy_layer_properties: Failed to "
2083 "allocate space for device extension entrypoint "
2084 "%d name of length",
2085 i);
Mark Young0ad83132016-06-30 13:02:42 -06002086 return VK_ERROR_OUT_OF_HOST_MEMORY;
2087 }
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07002088 strcpy(dst->device_extension_list.list->entrypoints[i],
2089 src->device_extension_list.list->entrypoints[i]);
2090 }
2091 }
Mark Young0ad83132016-06-30 13:02:42 -06002092
2093 return VK_SUCCESS;
Jon Ashburn3d002332015-08-20 16:35:30 -06002094}
2095
Jon Ashburn86a527a2016-02-10 20:59:26 -07002096static bool
2097loader_find_layer_name_list(const char *name,
2098 const struct loader_layer_list *layer_list) {
2099 if (!layer_list)
2100 return false;
2101 for (uint32_t j = 0; j < layer_list->count; j++)
2102 if (!strcmp(name, layer_list->list[j].info.layerName))
2103 return true;
2104 return false;
2105}
2106
2107static bool loader_find_layer_name(const char *name, uint32_t layer_count,
2108 const char **layer_list) {
2109 if (!layer_list)
2110 return false;
2111 for (uint32_t j = 0; j < layer_count; j++)
2112 if (!strcmp(name, layer_list[j]))
2113 return true;
2114 return false;
2115}
2116
Jon Ashburn491cd042016-05-16 14:01:18 -06002117bool loader_find_layer_name_array(
Jon Ashburn86a527a2016-02-10 20:59:26 -07002118 const char *name, uint32_t layer_count,
2119 const char layer_list[][VK_MAX_EXTENSION_NAME_SIZE]) {
2120 if (!layer_list)
2121 return false;
2122 for (uint32_t j = 0; j < layer_count; j++)
2123 if (!strcmp(name, layer_list[j]))
2124 return true;
2125 return false;
2126}
2127
2128/**
2129 * Searches through an array of layer names (ppp_layer_names) looking for a
2130 * layer key_name.
2131 * If not found then simply returns updating nothing.
2132 * Otherwise, it uses expand_count, expand_names adding them to layer names.
Chris Forbes69366472016-04-07 09:04:49 +12002133 * Any duplicate (pre-existing) expand_names in layer names are removed.
2134 * Order is otherwise preserved, with the layer key_name being replaced by the
2135 * expand_names.
Jon Ashburn86a527a2016-02-10 20:59:26 -07002136 * @param inst
2137 * @param layer_count
2138 * @param ppp_layer_names
2139 */
Mark Young0ad83132016-06-30 13:02:42 -06002140VkResult loader_expand_layer_names(
2141 struct loader_instance *inst, const char *key_name, uint32_t expand_count,
Jon Ashburn86a527a2016-02-10 20:59:26 -07002142 const char expand_names[][VK_MAX_EXTENSION_NAME_SIZE],
Jon Ashburncc407a22016-04-15 09:25:03 -06002143 uint32_t *layer_count, char const *const **ppp_layer_names) {
Jon Ashburn71483442016-02-11 18:59:43 -07002144
Jon Ashburncc407a22016-04-15 09:25:03 -06002145 char const *const *pp_src_layers = *ppp_layer_names;
Jon Ashburn86a527a2016-02-10 20:59:26 -07002146
Jon Ashburncc407a22016-04-15 09:25:03 -06002147 if (!loader_find_layer_name(key_name, *layer_count,
Jon Ashburn491cd042016-05-16 14:01:18 -06002148 (char const **)pp_src_layers)) {
2149 inst->activated_layers_are_std_val = false;
Mark Young0ad83132016-06-30 13:02:42 -06002150 return VK_SUCCESS; // didn't find the key_name in the list.
Jon Ashburn491cd042016-05-16 14:01:18 -06002151 }
Jon Ashburn71483442016-02-11 18:59:43 -07002152
Jon Ashburn86a527a2016-02-10 20:59:26 -07002153 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
2154 "Found meta layer %s, replacing with actual layer group",
2155 key_name);
Chris Forbesbd9de052016-04-06 20:49:02 +12002156
Jon Ashburn491cd042016-05-16 14:01:18 -06002157 inst->activated_layers_are_std_val = true;
Mark Young0ad83132016-06-30 13:02:42 -06002158 char const **pp_dst_layers = loader_instance_heap_alloc(
Jon Ashburncc407a22016-04-15 09:25:03 -06002159 inst, (expand_count + *layer_count - 1) * sizeof(char const *),
2160 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Mark Young0ad83132016-06-30 13:02:42 -06002161 if (NULL == pp_dst_layers) {
2162 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002163 "loader_expand_layer_names:: Failed to allocate space for "
2164 "std_validation layer names in pp_dst_layers.");
Mark Young0ad83132016-06-30 13:02:42 -06002165 return VK_ERROR_OUT_OF_HOST_MEMORY;
2166 }
Chris Forbesbd9de052016-04-06 20:49:02 +12002167
2168 // copy layers from src to dst, stripping key_name and anything in
2169 // expand_names.
2170 uint32_t src_index, dst_index = 0;
2171 for (src_index = 0; src_index < *layer_count; src_index++) {
Jon Ashburncc407a22016-04-15 09:25:03 -06002172 if (loader_find_layer_name_array(pp_src_layers[src_index], expand_count,
2173 expand_names)) {
Chris Forbes69366472016-04-07 09:04:49 +12002174 continue;
2175 }
2176
2177 if (!strcmp(pp_src_layers[src_index], key_name)) {
2178 // insert all expand_names in place of key_name
2179 uint32_t expand_index;
Jon Ashburncc407a22016-04-15 09:25:03 -06002180 for (expand_index = 0; expand_index < expand_count;
2181 expand_index++) {
Chris Forbes69366472016-04-07 09:04:49 +12002182 pp_dst_layers[dst_index++] = expand_names[expand_index];
2183 }
Chris Forbesbd9de052016-04-06 20:49:02 +12002184 continue;
Jon Ashburn86a527a2016-02-10 20:59:26 -07002185 }
Chris Forbesbd9de052016-04-06 20:49:02 +12002186
2187 pp_dst_layers[dst_index++] = pp_src_layers[src_index];
Jon Ashburn86a527a2016-02-10 20:59:26 -07002188 }
2189
Chris Forbesbd9de052016-04-06 20:49:02 +12002190 *ppp_layer_names = pp_dst_layers;
2191 *layer_count = dst_index;
Mark Young0ad83132016-06-30 13:02:42 -06002192
2193 return VK_SUCCESS;
Jon Ashburn86a527a2016-02-10 20:59:26 -07002194}
2195
Chris Forbesbd9de052016-04-06 20:49:02 +12002196void loader_delete_shadow_inst_layer_names(const struct loader_instance *inst,
2197 const VkInstanceCreateInfo *orig,
2198 VkInstanceCreateInfo *ours) {
2199 /* Free the layer names array iff we had to reallocate it */
2200 if (orig->ppEnabledLayerNames != ours->ppEnabledLayerNames) {
Mark Young0ad83132016-06-30 13:02:42 -06002201 loader_instance_heap_free(inst, (void *)ours->ppEnabledLayerNames);
Jon Ashburn86a527a2016-02-10 20:59:26 -07002202 }
2203}
2204
Jon Ashburn491cd042016-05-16 14:01:18 -06002205void loader_init_std_validation_props(struct loader_layer_properties *props) {
2206 memset(props, 0, sizeof(struct loader_layer_properties));
2207 props->type = VK_LAYER_TYPE_META_EXPLICT;
2208 strncpy(props->info.description, "LunarG Standard Validation Layer",
Mark Young0153e0b2016-11-03 14:27:13 -06002209 sizeof(props->info.description));
Jon Ashburn491cd042016-05-16 14:01:18 -06002210 props->info.implementationVersion = 1;
2211 strncpy(props->info.layerName, std_validation_str,
Mark Young0153e0b2016-11-03 14:27:13 -06002212 sizeof(props->info.layerName));
Jon Ashburn491cd042016-05-16 14:01:18 -06002213 // TODO what about specVersion? for now insert loader's built version
2214 props->info.specVersion = VK_MAKE_VERSION(1, 0, VK_HEADER_VERSION);
2215}
2216
Jon Ashburn86a527a2016-02-10 20:59:26 -07002217/**
Jon Ashburn491cd042016-05-16 14:01:18 -06002218 * Searches through the existing instance layer lists looking for
Jon Ashburn86a527a2016-02-10 20:59:26 -07002219 * the set of required layer names. If found then it adds a meta property to the
2220 * layer list.
2221 * Assumes the required layers are the same for both instance and device lists.
2222 * @param inst
2223 * @param layer_count number of layers in layer_names
2224 * @param layer_names array of required layer names
2225 * @param layer_instance_list
Jon Ashburn86a527a2016-02-10 20:59:26 -07002226 */
2227static void loader_add_layer_property_meta(
2228 const struct loader_instance *inst, uint32_t layer_count,
2229 const char layer_names[][VK_MAX_EXTENSION_NAME_SIZE],
Jon Ashburn491cd042016-05-16 14:01:18 -06002230 struct loader_layer_list *layer_instance_list) {
2231 uint32_t i;
Jon Ashburn86a527a2016-02-10 20:59:26 -07002232 bool found;
2233 struct loader_layer_list *layer_list;
2234
Jon Ashburn491cd042016-05-16 14:01:18 -06002235 if (0 == layer_count || (!layer_instance_list))
Jon Ashburn888c0502016-02-19 15:22:10 -07002236 return;
Jon Ashburn491cd042016-05-16 14:01:18 -06002237 if (layer_instance_list && (layer_count > layer_instance_list->count))
Jon Ashburn86a527a2016-02-10 20:59:26 -07002238 return;
2239
Jon Ashburn491cd042016-05-16 14:01:18 -06002240 layer_list = layer_instance_list;
2241
2242 found = true;
2243 if (layer_list == NULL)
2244 return;
2245 for (i = 0; i < layer_count; i++) {
2246 if (loader_find_layer_name_list(layer_names[i], layer_list))
Jon Ashburn888c0502016-02-19 15:22:10 -07002247 continue;
Jon Ashburn491cd042016-05-16 14:01:18 -06002248 found = false;
2249 break;
Jon Ashburn86a527a2016-02-10 20:59:26 -07002250 }
Jon Ashburn491cd042016-05-16 14:01:18 -06002251
2252 struct loader_layer_properties *props;
2253 if (found) {
2254 props = loader_get_next_layer_property(inst, layer_list);
Mark Young0ad83132016-06-30 13:02:42 -06002255 if (NULL == props) {
2256 // Error already triggered in loader_get_next_layer_property.
2257 return;
2258 }
Jon Ashburn491cd042016-05-16 14:01:18 -06002259 loader_init_std_validation_props(props);
Jon Ashburn491cd042016-05-16 14:01:18 -06002260 }
Jon Ashburn86a527a2016-02-10 20:59:26 -07002261}
2262
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002263static void loader_read_json_layer(
2264 const struct loader_instance *inst,
2265 struct loader_layer_list *layer_instance_list, cJSON *layer_node,
2266 cJSON *item, cJSON *disable_environment, bool is_implicit, char *filename) {
2267 char *temp;
2268 char *name, *type, *library_path, *api_version;
2269 char *implementation_version, *description;
2270 cJSON *ext_item;
2271 VkExtensionProperties ext_prop;
2272
Mark Young0ad83132016-06-30 13:02:42 -06002273/*
2274 * The following are required in the "layer" object:
2275 * (required) "name"
2276 * (required) "type"
2277 * (required) “library_path”
2278 * (required) “api_version”
2279 * (required) “implementation_version”
2280 * (required) “description”
2281 * (required for implicit layers) “disable_environment”
2282 */
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002283
Jon Ashburn23d36b12016-02-02 17:47:28 -07002284#define GET_JSON_OBJECT(node, var) \
2285 { \
2286 var = cJSON_GetObjectItem(node, #var); \
2287 if (var == NULL) { \
2288 layer_node = layer_node->next; \
Jon Ashburn1530c342016-02-26 13:14:27 -07002289 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002290 "Didn't find required layer object %s in manifest " \
2291 "JSON file, skipping this layer", \
2292 #var); \
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002293 return; \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002294 } \
2295 }
2296#define GET_JSON_ITEM(node, var) \
2297 { \
2298 item = cJSON_GetObjectItem(node, #var); \
2299 if (item == NULL) { \
2300 layer_node = layer_node->next; \
Jon Ashburn1530c342016-02-26 13:14:27 -07002301 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002302 "Didn't find required layer value %s in manifest JSON " \
2303 "file, skipping this layer", \
2304 #var); \
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002305 return; \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002306 } \
2307 temp = cJSON_Print(item); \
Mark Young0ad83132016-06-30 13:02:42 -06002308 if (temp == NULL) { \
2309 layer_node = layer_node->next; \
2310 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, \
2311 "Problem accessing layer value %s in manifest JSON " \
2312 "file, skipping this layer", \
2313 #var); \
2314 return; \
2315 } \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002316 temp[strlen(temp) - 1] = '\0'; \
2317 var = loader_stack_alloc(strlen(temp) + 1); \
2318 strcpy(var, &temp[1]); \
Mark Young0ad83132016-06-30 13:02:42 -06002319 cJSON_Free(temp); \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002320 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002321 GET_JSON_ITEM(layer_node, name)
2322 GET_JSON_ITEM(layer_node, type)
2323 GET_JSON_ITEM(layer_node, library_path)
2324 GET_JSON_ITEM(layer_node, api_version)
2325 GET_JSON_ITEM(layer_node, implementation_version)
2326 GET_JSON_ITEM(layer_node, description)
2327 if (is_implicit) {
2328 GET_JSON_OBJECT(layer_node, disable_environment)
2329 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002330#undef GET_JSON_ITEM
2331#undef GET_JSON_OBJECT
2332
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002333 // add list entry
2334 struct loader_layer_properties *props = NULL;
2335 if (!strcmp(type, "DEVICE")) {
2336 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2337 "Device layers are deprecated skipping this layer");
2338 layer_node = layer_node->next;
2339 return;
2340 }
2341 // Allow either GLOBAL or INSTANCE type interchangeably to handle
2342 // layers that must work with older loaders
2343 if (!strcmp(type, "INSTANCE") || !strcmp(type, "GLOBAL")) {
2344 if (layer_instance_list == NULL) {
Jon Ashburn432d2762015-09-18 12:53:16 -06002345 layer_node = layer_node->next;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002346 return;
Jon Ashburn432d2762015-09-18 12:53:16 -06002347 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002348 props = loader_get_next_layer_property(inst, layer_instance_list);
Mark Young0ad83132016-06-30 13:02:42 -06002349 if (NULL == props) {
2350 // Error already triggered in loader_get_next_layer_property.
2351 return;
2352 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002353 props->type = (is_implicit) ? VK_LAYER_TYPE_INSTANCE_IMPLICIT
2354 : VK_LAYER_TYPE_INSTANCE_EXPLICIT;
2355 }
Jon Ashburn432d2762015-09-18 12:53:16 -06002356
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002357 if (props == NULL) {
2358 layer_node = layer_node->next;
2359 return;
2360 }
Jon Ashburn15315172015-07-07 15:06:25 -06002361
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002362 strncpy(props->info.layerName, name, sizeof(props->info.layerName));
2363 props->info.layerName[sizeof(props->info.layerName) - 1] = '\0';
2364
2365 char *fullpath = props->lib_name;
2366 char *rel_base;
2367 if (loader_platform_is_path(library_path)) {
2368 // a relative or absolute path
2369 char *name_copy = loader_stack_alloc(strlen(filename) + 1);
2370 strcpy(name_copy, filename);
2371 rel_base = loader_platform_dirname(name_copy);
2372 loader_expand_path(library_path, rel_base, MAX_STRING_SIZE, fullpath);
2373 } else {
2374 // a filename which is assumed in a system directory
2375 loader_get_fullpath(library_path, DEFAULT_VK_LAYERS_PATH,
2376 MAX_STRING_SIZE, fullpath);
2377 }
2378 props->info.specVersion = loader_make_version(api_version);
2379 props->info.implementationVersion = atoi(implementation_version);
2380 strncpy((char *)props->info.description, description,
2381 sizeof(props->info.description));
2382 props->info.description[sizeof(props->info.description) - 1] = '\0';
2383 if (is_implicit) {
2384 if (!disable_environment || !disable_environment->child) {
2385 loader_log(
2386 inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2387 "Didn't find required layer child value disable_environment"
2388 "in manifest JSON file, skipping this layer");
2389 layer_node = layer_node->next;
2390 return;
Jon Ashburnfb8ac012015-08-12 16:39:32 -06002391 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002392 strncpy(props->disable_env_var.name, disable_environment->child->string,
2393 sizeof(props->disable_env_var.name));
2394 props->disable_env_var.name[sizeof(props->disable_env_var.name) - 1] =
2395 '\0';
2396 strncpy(props->disable_env_var.value,
2397 disable_environment->child->valuestring,
2398 sizeof(props->disable_env_var.value));
2399 props->disable_env_var.value[sizeof(props->disable_env_var.value) - 1] =
2400 '\0';
2401 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002402
Jon Ashburn23d36b12016-02-02 17:47:28 -07002403/**
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002404* Now get all optional items and objects and put in list:
2405* functions
2406* instance_extensions
2407* device_extensions
2408* enable_environment (implicit layers only)
2409*/
Jon Ashburn23d36b12016-02-02 17:47:28 -07002410#define GET_JSON_OBJECT(node, var) \
2411 { var = cJSON_GetObjectItem(node, #var); }
2412#define GET_JSON_ITEM(node, var) \
2413 { \
2414 item = cJSON_GetObjectItem(node, #var); \
2415 if (item != NULL) { \
2416 temp = cJSON_Print(item); \
Mark Young0ad83132016-06-30 13:02:42 -06002417 if (temp != NULL) { \
2418 temp[strlen(temp) - 1] = '\0'; \
2419 var = loader_stack_alloc(strlen(temp) + 1); \
2420 strcpy(var, &temp[1]); \
2421 cJSON_Free(temp); \
2422 } \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002423 } \
2424 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002425
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002426 cJSON *instance_extensions, *device_extensions, *functions,
2427 *enable_environment;
2428 cJSON *entrypoints;
2429 char *vkGetInstanceProcAddr, *vkGetDeviceProcAddr, *spec_version;
2430 char **entry_array;
2431 vkGetInstanceProcAddr = NULL;
2432 vkGetDeviceProcAddr = NULL;
2433 spec_version = NULL;
2434 entrypoints = NULL;
2435 entry_array = NULL;
2436 int i, j;
Jon Ashburn075ce432015-12-17 17:38:24 -07002437
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002438 /**
2439 * functions
2440 * vkGetInstanceProcAddr
2441 * vkGetDeviceProcAddr
2442 */
2443 GET_JSON_OBJECT(layer_node, functions)
2444 if (functions != NULL) {
2445 GET_JSON_ITEM(functions, vkGetInstanceProcAddr)
2446 GET_JSON_ITEM(functions, vkGetDeviceProcAddr)
2447 if (vkGetInstanceProcAddr != NULL)
2448 strncpy(props->functions.str_gipa, vkGetInstanceProcAddr,
2449 sizeof(props->functions.str_gipa));
2450 props->functions.str_gipa[sizeof(props->functions.str_gipa) - 1] = '\0';
2451 if (vkGetDeviceProcAddr != NULL)
2452 strncpy(props->functions.str_gdpa, vkGetDeviceProcAddr,
2453 sizeof(props->functions.str_gdpa));
2454 props->functions.str_gdpa[sizeof(props->functions.str_gdpa) - 1] = '\0';
2455 }
2456 /**
2457 * instance_extensions
2458 * array of
2459 * name
2460 * spec_version
2461 */
2462 GET_JSON_OBJECT(layer_node, instance_extensions)
2463 if (instance_extensions != NULL) {
2464 int count = cJSON_GetArraySize(instance_extensions);
2465 for (i = 0; i < count; i++) {
2466 ext_item = cJSON_GetArrayItem(instance_extensions, i);
2467 GET_JSON_ITEM(ext_item, name)
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002468 if (name != NULL) {
2469 strncpy(ext_prop.extensionName, name,
2470 sizeof(ext_prop.extensionName));
2471 ext_prop.extensionName[sizeof(ext_prop.extensionName) - 1] =
2472 '\0';
2473 }
Mark Young0ad83132016-06-30 13:02:42 -06002474 GET_JSON_ITEM(ext_item, spec_version)
2475 if (NULL != spec_version) {
2476 ext_prop.specVersion = atoi(spec_version);
2477 } else {
2478 ext_prop.specVersion = 0;
2479 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002480 bool ext_unsupported =
2481 wsi_unsupported_instance_extension(&ext_prop);
2482 if (!ext_unsupported) {
2483 loader_add_to_ext_list(inst, &props->instance_extension_list, 1,
2484 &ext_prop);
Jon Ashburn075ce432015-12-17 17:38:24 -07002485 }
Jon Ashburnfb8ac012015-08-12 16:39:32 -06002486 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002487 }
2488 /**
2489 * device_extensions
2490 * array of
2491 * name
2492 * spec_version
2493 * entrypoints
2494 */
2495 GET_JSON_OBJECT(layer_node, device_extensions)
2496 if (device_extensions != NULL) {
2497 int count = cJSON_GetArraySize(device_extensions);
2498 for (i = 0; i < count; i++) {
2499 ext_item = cJSON_GetArrayItem(device_extensions, i);
2500 GET_JSON_ITEM(ext_item, name)
2501 GET_JSON_ITEM(ext_item, spec_version)
2502 if (name != NULL) {
2503 strncpy(ext_prop.extensionName, name,
2504 sizeof(ext_prop.extensionName));
2505 ext_prop.extensionName[sizeof(ext_prop.extensionName) - 1] =
2506 '\0';
2507 }
Mark Young0ad83132016-06-30 13:02:42 -06002508 if (NULL != spec_version) {
2509 ext_prop.specVersion = atoi(spec_version);
2510 } else {
2511 ext_prop.specVersion = 0;
2512 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002513 // entrypoints = cJSON_GetObjectItem(ext_item, "entrypoints");
2514 GET_JSON_OBJECT(ext_item, entrypoints)
2515 int entry_count;
2516 if (entrypoints == NULL) {
2517 loader_add_to_dev_ext_list(inst, &props->device_extension_list,
2518 &ext_prop, 0, NULL);
2519 continue;
2520 }
2521 entry_count = cJSON_GetArraySize(entrypoints);
Mark Young0ad83132016-06-30 13:02:42 -06002522 if (entry_count) {
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002523 entry_array =
2524 (char **)loader_stack_alloc(sizeof(char *) * entry_count);
Mark Young0ad83132016-06-30 13:02:42 -06002525 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002526 for (j = 0; j < entry_count; j++) {
2527 ext_item = cJSON_GetArrayItem(entrypoints, j);
2528 if (ext_item != NULL) {
2529 temp = cJSON_Print(ext_item);
Mark Young0ad83132016-06-30 13:02:42 -06002530 if (NULL == temp) {
2531 entry_array[j] = NULL;
2532 continue;
2533 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002534 temp[strlen(temp) - 1] = '\0';
2535 entry_array[j] = loader_stack_alloc(strlen(temp) + 1);
2536 strcpy(entry_array[j], &temp[1]);
Mark Young0ad83132016-06-30 13:02:42 -06002537 cJSON_Free(temp);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002538 }
2539 }
2540 loader_add_to_dev_ext_list(inst, &props->device_extension_list,
2541 &ext_prop, entry_count, entry_array);
2542 }
2543 }
2544 if (is_implicit) {
2545 GET_JSON_OBJECT(layer_node, enable_environment)
2546
2547 // enable_environment is optional
2548 if (enable_environment) {
2549 strncpy(props->enable_env_var.name,
2550 enable_environment->child->string,
2551 sizeof(props->enable_env_var.name));
2552 props->enable_env_var.name[sizeof(props->enable_env_var.name) - 1] =
2553 '\0';
2554 strncpy(props->enable_env_var.value,
2555 enable_environment->child->valuestring,
2556 sizeof(props->enable_env_var.value));
2557 props->enable_env_var
2558 .value[sizeof(props->enable_env_var.value) - 1] = '\0';
2559 }
2560 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002561#undef GET_JSON_ITEM
2562#undef GET_JSON_OBJECT
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002563}
2564
2565/**
2566 * Given a cJSON struct (json) of the top level JSON object from layer manifest
2567 * file, add entry to the layer_list. Fill out the layer_properties in this list
2568 * entry from the input cJSON object.
2569 *
2570 * \returns
2571 * void
2572 * layer_list has a new entry and initialized accordingly.
2573 * If the json input object does not have all the required fields no entry
2574 * is added to the list.
2575 */
2576static void
2577loader_add_layer_properties(const struct loader_instance *inst,
2578 struct loader_layer_list *layer_instance_list,
2579 cJSON *json, bool is_implicit, char *filename) {
2580 /* Fields in layer manifest file that are required:
2581 * (required) “file_format_version”
2582 *
Mark Young0ad83132016-06-30 13:02:42 -06002583 * If more than one "layer" object are to be used, use the "layers" array
2584 * instead.
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002585 *
2586 * First get all required items and if any missing abort
2587 */
2588
2589 cJSON *item, *layers_node, *layer_node;
2590 uint16_t file_major_vers = 0;
2591 uint16_t file_minor_vers = 0;
2592 uint16_t file_patch_vers = 0;
2593 char *vers_tok;
2594 cJSON *disable_environment = NULL;
2595 item = cJSON_GetObjectItem(json, "file_format_version");
2596 if (item == NULL) {
2597 return;
2598 }
2599 char *file_vers = cJSON_PrintUnformatted(item);
Mark Young0ad83132016-06-30 13:02:42 -06002600 if (NULL == file_vers) {
2601 return;
2602 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002603 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
2604 "Found manifest file %s, version %s", filename, file_vers);
2605 // Get the major/minor/and patch as integers for easier comparison
2606 vers_tok = strtok(file_vers, ".\"\n\r");
2607 if (NULL != vers_tok) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04002608 file_major_vers = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002609 vers_tok = strtok(NULL, ".\"\n\r");
2610 if (NULL != vers_tok) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04002611 file_minor_vers = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002612 vers_tok = strtok(NULL, ".\"\n\r");
2613 if (NULL != vers_tok) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04002614 file_patch_vers = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002615 }
2616 }
2617 }
2618 if (file_major_vers != 1 || file_minor_vers != 0 || file_patch_vers > 1) {
2619 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002620 "loader_add_layer_properties: Unexpected manifest file "
2621 " version (expected 1.0.0 or 1.0.1) in %s, may cause "
2622 "errors",
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002623 filename);
2624 }
Mark Young0ad83132016-06-30 13:02:42 -06002625 cJSON_Free(file_vers);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002626 // If "layers" is present, read in the array of layer objects
2627 layers_node = cJSON_GetObjectItem(json, "layers");
2628 if (layers_node != NULL) {
2629 int numItems = cJSON_GetArraySize(layers_node);
2630 if (file_major_vers == 1 && file_minor_vers == 0 &&
2631 file_patch_vers == 0) {
2632 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002633 "loader_add_layer_properties: \"layers\" tag not "
2634 "supported until file version 1.0.1, but %s is "
2635 "reporting version %s",
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002636 filename, file_vers);
2637 }
2638 for (int curLayer = 0; curLayer < numItems; curLayer++) {
2639 layer_node = cJSON_GetArrayItem(layers_node, curLayer);
2640 if (layer_node == NULL) {
2641 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002642 "loader_add_layer_properties: Can not find "
2643 "\"layers\" array element %d object in manifest "
2644 "JSON file %s. Skipping this file",
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002645 curLayer, filename);
2646 return;
2647 }
2648 loader_read_json_layer(inst, layer_instance_list, layer_node, item,
2649 disable_environment, is_implicit, filename);
2650 }
2651 } else {
2652 // Otherwise, try to read in individual layers
2653 layer_node = cJSON_GetObjectItem(json, "layer");
2654 if (layer_node == NULL) {
2655 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002656 "loader_add_layer_properties: Can not find \"layer\" "
2657 "object in manifest JSON file %s. Skipping this file.",
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002658 filename);
2659 return;
2660 }
2661 // Loop through all "layer" objects in the file to get a count of them
2662 // first.
2663 uint16_t layer_count = 0;
2664 cJSON *tempNode = layer_node;
2665 do {
2666 tempNode = tempNode->next;
2667 layer_count++;
2668 } while (tempNode != NULL);
2669 /*
2670 * Throw a warning if we encounter multiple "layer" objects in file
2671 * versions newer than 1.0.0. Having multiple objects with the same
2672 * name at the same level is actually a JSON standard violation.
2673 */
2674 if (layer_count > 1 &&
2675 (file_major_vers > 1 ||
2676 !(file_minor_vers == 0 && file_patch_vers == 0))) {
2677 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002678 "loader_add_layer_properties: Multiple \"layer\" nodes"
2679 " are deprecated starting in file version \"1.0.1\". "
2680 "Please use \"layers\" : [] array instead in %s.",
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002681 filename);
2682 } else {
2683 do {
2684 loader_read_json_layer(inst, layer_instance_list, layer_node,
2685 item, disable_environment, is_implicit,
2686 filename);
2687 layer_node = layer_node->next;
2688 } while (layer_node != NULL);
2689 }
2690 }
Jon Ashburnfb8ac012015-08-12 16:39:32 -06002691 return;
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002692}
2693
2694/**
Jon Ashburn2077e382015-06-29 11:25:34 -06002695 * Find the Vulkan library manifest files.
2696 *
Jon Ashburnb6822212016-02-16 15:34:16 -07002697 * This function scans the "location" or "env_override" directories/files
Jon Ashburn2077e382015-06-29 11:25:34 -06002698 * for a list of JSON manifest files. If env_override is non-NULL
2699 * and has a valid value. Then the location is ignored. Otherwise
2700 * location is used to look for manifest files. The location
2701 * is interpreted as Registry path on Windows and a directory path(s)
Jon Ashburnb6822212016-02-16 15:34:16 -07002702 * on Linux. "home_location" is an additional directory in the users home
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01002703 * directory to look at. It is expanded into the dir path
2704 * $XDG_DATA_HOME/home_location or $HOME/.local/share/home_location depending
2705 * on environment variables. This "home_location" is only used on Linux.
Jon Ashburn2077e382015-06-29 11:25:34 -06002706 *
2707 * \returns
Mark Young0ad83132016-06-30 13:02:42 -06002708 * VKResult
Jon Ashburn2077e382015-06-29 11:25:34 -06002709 * A string list of manifest files to be opened in out_files param.
2710 * List has a pointer to string for each manifest filename.
2711 * When done using the list in out_files, pointers should be freed.
Jon Ashburn23d36b12016-02-02 17:47:28 -07002712 * Location or override string lists can be either files or directories as
2713 *follows:
Jon Ashburnffad94d2015-06-30 14:46:22 -07002714 * | location | override
2715 * --------------------------------
2716 * Win ICD | files | files
2717 * Win Layer | files | dirs
2718 * Linux ICD | dirs | files
2719 * Linux Layer| dirs | dirs
Jon Ashburn2077e382015-06-29 11:25:34 -06002720 */
Mark Youngf8c20102016-11-07 16:26:17 -07002721static VkResult
2722loader_get_manifest_files(const struct loader_instance *inst,
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05002723 const char *env_override, const char *source_override,
Mark Youngf8c20102016-11-07 16:26:17 -07002724 bool is_layer, bool warn_if_not_present,
2725 const char *location, const char *home_location,
2726 struct loader_manifest_files *out_files) {
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05002727 const char *override = NULL;
2728 char *override_getenv = NULL;
Mark Young0ad83132016-06-30 13:02:42 -06002729 char *loc, *orig_loc = NULL;
2730 char *reg = NULL;
Jon Ashburn2077e382015-06-29 11:25:34 -06002731 char *file, *next_file, *name;
2732 size_t alloced_count = 64;
2733 char full_path[2048];
2734 DIR *sysdir = NULL;
Jon Ashburnffad94d2015-06-30 14:46:22 -07002735 bool list_is_dirs = false;
Jon Ashburn2077e382015-06-29 11:25:34 -06002736 struct dirent *dent;
Mark Young0ad83132016-06-30 13:02:42 -06002737 VkResult res = VK_SUCCESS;
Jon Ashburn2077e382015-06-29 11:25:34 -06002738
2739 out_files->count = 0;
2740 out_files->filename_list = NULL;
2741
Jamie Madill00c3c912016-04-06 18:26:46 -04002742 if (source_override != NULL) {
2743 override = source_override;
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05002744 } else if (env_override != NULL) {
Johannes van Waveren9bd805012015-10-28 11:45:00 -05002745#if !defined(_WIN32)
Jon Ashburncc407a22016-04-15 09:25:03 -06002746 if (geteuid() != getuid() || getegid() != getgid()) {
Jon Ashburnffad94d2015-06-30 14:46:22 -07002747 /* Don't allow setuid apps to use the env var: */
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05002748 env_override = NULL;
Jon Ashburn2077e382015-06-29 11:25:34 -06002749 }
2750#endif
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05002751 if (env_override != NULL) {
2752 override = override_getenv = loader_getenv(env_override, inst);
2753 }
Jon Ashburn2077e382015-06-29 11:25:34 -06002754 }
2755
Jon Ashburnb6822212016-02-16 15:34:16 -07002756#if !defined(_WIN32)
2757 if (location == NULL && home_location == NULL) {
2758#else
2759 home_location = NULL;
Jon Ashburn2077e382015-06-29 11:25:34 -06002760 if (location == NULL) {
Jon Ashburnb6822212016-02-16 15:34:16 -07002761#endif
Mark Youngb6399312017-01-10 14:22:15 -07002762 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2763 "loader_get_manifest_files: Can not get manifest files with "
2764 "NULL location, env_override=%s",
2765 (env_override != NULL) ? env_override : "");
Mark Young0ad83132016-06-30 13:02:42 -06002766 res = VK_ERROR_INITIALIZATION_FAILED;
2767 goto out;
Jon Ashburn2077e382015-06-29 11:25:34 -06002768 }
2769
Johannes van Waveren9bd805012015-10-28 11:45:00 -05002770#if defined(_WIN32)
Jon Ashburnffad94d2015-06-30 14:46:22 -07002771 list_is_dirs = (is_layer && override != NULL) ? true : false;
Johannes van Waveren9bd805012015-10-28 11:45:00 -05002772#else
2773 list_is_dirs = (override == NULL || is_layer) ? true : false;
Jon Ashburnffad94d2015-06-30 14:46:22 -07002774#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06002775 // Make a copy of the input we are using so it is not modified
Jon Ashburnffad94d2015-06-30 14:46:22 -07002776 // Also handle getting the location(s) from registry on Windows
2777 if (override == NULL) {
Jon Ashburn3b78e462015-07-31 10:11:24 -06002778 loc = loader_stack_alloc(strlen(location) + 1);
Jon Ashburnffad94d2015-06-30 14:46:22 -07002779 if (loc == NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07002780 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002781 "loader_get_manifest_files: Failed to allocate "
2782 " %d bytes for manifest file location.",
2783 strlen(location));
Mark Young0ad83132016-06-30 13:02:42 -06002784 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2785 goto out;
Jon Ashburnffad94d2015-06-30 14:46:22 -07002786 }
2787 strcpy(loc, location);
Johannes van Waveren9bd805012015-10-28 11:45:00 -05002788#if defined(_WIN32)
Mark Young0ad83132016-06-30 13:02:42 -06002789 reg = loader_get_registry_files(inst, loc);
2790 if (reg == NULL) {
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07002791 if (!is_layer) {
Mark Youngb6399312017-01-10 14:22:15 -07002792 loader_log(
2793 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2794 "loader_get_manifest_files: Registry lookup failed "
2795 " to get ICD manifest files. Possibly missing Vulkan"
2796 " driver?");
Mark Young0ad83132016-06-30 13:02:42 -06002797 // This typically only fails when out of memory, which is
2798 // critical
2799 // if this is for the loader.
2800 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07002801 } else {
Mark Youngf8c20102016-11-07 16:26:17 -07002802 if (warn_if_not_present) {
2803 // warning only for layers
2804 loader_log(
2805 inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002806 "loader_get_manifest_files: Registry lookup failed "
2807 " to get layer manifest files.");
Mark Youngf8c20102016-11-07 16:26:17 -07002808 }
Mark Young0ad83132016-06-30 13:02:42 -06002809 // Return success for now since it's not critical for layers
2810 res = VK_SUCCESS;
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07002811 }
Mark Young0ad83132016-06-30 13:02:42 -06002812 goto out;
Jon Ashburn24265ac2015-07-31 09:33:21 -06002813 }
Mark Young0ad83132016-06-30 13:02:42 -06002814 orig_loc = loc;
2815 loc = reg;
Jon Ashburnffad94d2015-06-30 14:46:22 -07002816#endif
Jon Ashburn23d36b12016-02-02 17:47:28 -07002817 } else {
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -06002818 loc = loader_stack_alloc(strlen(override) + 1);
Jon Ashburnffad94d2015-06-30 14:46:22 -07002819 if (loc == NULL) {
Mark Youngb6399312017-01-10 14:22:15 -07002820 loader_log(
2821 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2822 "loader_get_manifest_files: Failed to allocate space for "
2823 " override environment variable of length %d",
2824 strlen(override) + 1);
Mark Young0ad83132016-06-30 13:02:42 -06002825 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2826 goto out;
Jon Ashburnffad94d2015-06-30 14:46:22 -07002827 }
2828 strcpy(loc, override);
2829 }
Jon Ashburn2077e382015-06-29 11:25:34 -06002830
Liam Middlebrook9b14e892015-07-23 18:32:20 -07002831 // Print out the paths being searched if debugging is enabled
Jon Ashburn23d36b12016-02-02 17:47:28 -07002832 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
2833 "Searching the following paths for manifest files: %s\n", loc);
Liam Middlebrook9b14e892015-07-23 18:32:20 -07002834
Jon Ashburn2077e382015-06-29 11:25:34 -06002835 file = loc;
2836 while (*file) {
2837 next_file = loader_get_next_path(file);
Jon Ashburnffad94d2015-06-30 14:46:22 -07002838 if (list_is_dirs) {
Jon Ashburn2077e382015-06-29 11:25:34 -06002839 sysdir = opendir(file);
2840 name = NULL;
2841 if (sysdir) {
2842 dent = readdir(sysdir);
2843 if (dent == NULL)
2844 break;
2845 name = &(dent->d_name[0]);
2846 loader_get_fullpath(name, file, sizeof(full_path), full_path);
2847 name = full_path;
2848 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07002849 } else {
Johannes van Waveren9bd805012015-10-28 11:45:00 -05002850#if defined(_WIN32)
2851 name = file;
2852#else
Jon Ashburnffad94d2015-06-30 14:46:22 -07002853 // only Linux has relative paths
Jon Ashburn2077e382015-06-29 11:25:34 -06002854 char *dir;
2855 // make a copy of location so it isn't modified
Jason Ekstrandcc7550e2015-10-10 08:33:37 -07002856 dir = loader_stack_alloc(strlen(loc) + 1);
Jon Ashburn2077e382015-06-29 11:25:34 -06002857 if (dir == NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07002858 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002859 "loader_get_manifest_files: Failed to allocate "
2860 " space for relative location path length %d",
2861 strlen(loc) + 1);
Mark Young0ad83132016-06-30 13:02:42 -06002862 goto out;
Jon Ashburn2077e382015-06-29 11:25:34 -06002863 }
Jason Ekstrandcc7550e2015-10-10 08:33:37 -07002864 strcpy(dir, loc);
Jon Ashburn2077e382015-06-29 11:25:34 -06002865
2866 loader_get_fullpath(file, dir, sizeof(full_path), full_path);
2867
2868 name = full_path;
Jon Ashburnffad94d2015-06-30 14:46:22 -07002869#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06002870 }
2871 while (name) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07002872 /* Look for files ending with ".json" suffix */
2873 uint32_t nlen = (uint32_t)strlen(name);
2874 const char *suf = name + nlen - 5;
2875 if ((nlen > 5) && !strncmp(suf, ".json", 5)) {
2876 if (out_files->count == 0) {
Mark Young0ad83132016-06-30 13:02:42 -06002877 out_files->filename_list = loader_instance_heap_alloc(
2878 inst, alloced_count * sizeof(char *),
2879 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Jon Ashburn23d36b12016-02-02 17:47:28 -07002880 } else if (out_files->count == alloced_count) {
Mark Young0ad83132016-06-30 13:02:42 -06002881 out_files->filename_list = loader_instance_heap_realloc(
2882 inst, out_files->filename_list,
2883 alloced_count * sizeof(char *),
2884 alloced_count * sizeof(char *) * 2,
2885 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Jon Ashburn23d36b12016-02-02 17:47:28 -07002886 alloced_count *= 2;
Jon Ashburn2077e382015-06-29 11:25:34 -06002887 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07002888 if (out_files->filename_list == NULL) {
2889 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002890 "loader_get_manifest_files: Failed to allocate "
2891 " space for manifest file name list");
Mark Young0ad83132016-06-30 13:02:42 -06002892 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2893 goto out;
Jon Ashburn2077e382015-06-29 11:25:34 -06002894 }
Mark Young0ad83132016-06-30 13:02:42 -06002895 out_files->filename_list[out_files->count] =
2896 loader_instance_heap_alloc(
2897 inst, strlen(name) + 1,
2898 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Jon Ashburn23d36b12016-02-02 17:47:28 -07002899 if (out_files->filename_list[out_files->count] == NULL) {
2900 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002901 "loader_get_manifest_files: Failed to allocate "
2902 " space for manifest file %d list",
2903 out_files->count);
Mark Young0ad83132016-06-30 13:02:42 -06002904 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2905 goto out;
Jon Ashburn23d36b12016-02-02 17:47:28 -07002906 }
2907 strcpy(out_files->filename_list[out_files->count], name);
2908 out_files->count++;
2909 } else if (!list_is_dirs) {
2910 loader_log(
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07002911 inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -07002912 "Skipping manifest file %s, file name must end in .json",
2913 name);
2914 }
2915 if (list_is_dirs) {
2916 dent = readdir(sysdir);
Mark Young0ad83132016-06-30 13:02:42 -06002917 if (dent == NULL) {
Jon Ashburn2077e382015-06-29 11:25:34 -06002918 break;
Mark Young0ad83132016-06-30 13:02:42 -06002919 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07002920 name = &(dent->d_name[0]);
2921 loader_get_fullpath(name, file, sizeof(full_path), full_path);
2922 name = full_path;
2923 } else {
2924 break;
2925 }
Jon Ashburn2077e382015-06-29 11:25:34 -06002926 }
Mark Young0ad83132016-06-30 13:02:42 -06002927 if (sysdir) {
Jon Ashburn2077e382015-06-29 11:25:34 -06002928 closedir(sysdir);
Mark Young0ad83132016-06-30 13:02:42 -06002929 sysdir = NULL;
2930 }
Jon Ashburn2077e382015-06-29 11:25:34 -06002931 file = next_file;
Jon Ashburn67e262e2016-02-18 12:45:39 -07002932#if !defined(_WIN32)
Jon Ashburn1530c342016-02-26 13:14:27 -07002933 if (home_location != NULL &&
2934 (next_file == NULL || *next_file == '\0') && override == NULL) {
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01002935 char *xdgdatahome = secure_getenv("XDG_DATA_HOME");
2936 size_t len;
2937 if (xdgdatahome != NULL) {
2938
2939 char *home_loc = loader_stack_alloc(strlen(xdgdatahome) + 2 +
Jon Ashburn67e262e2016-02-18 12:45:39 -07002940 strlen(home_location));
2941 if (home_loc == NULL) {
2942 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002943 "loader_get_manifest_files: Failed to allocate "
2944 " space for manifest file XDG Home location");
Mark Young0ad83132016-06-30 13:02:42 -06002945 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2946 goto out;
Jon Ashburn67e262e2016-02-18 12:45:39 -07002947 }
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01002948 strcpy(home_loc, xdgdatahome);
Jon Ashburn67e262e2016-02-18 12:45:39 -07002949 // Add directory separator if needed
2950 if (home_location[0] != DIRECTORY_SYMBOL) {
2951 len = strlen(home_loc);
2952 home_loc[len] = DIRECTORY_SYMBOL;
Jon Ashburn1530c342016-02-26 13:14:27 -07002953 home_loc[len + 1] = '\0';
Jon Ashburn67e262e2016-02-18 12:45:39 -07002954 }
2955 strcat(home_loc, home_location);
2956 file = home_loc;
2957 next_file = loader_get_next_path(file);
2958 home_location = NULL;
2959
Jon Ashburn1530c342016-02-26 13:14:27 -07002960 loader_log(
2961 inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01002962 "Searching the following path for manifest files: %s\n",
Jon Ashburn1530c342016-02-26 13:14:27 -07002963 home_loc);
Jon Ashburn67e262e2016-02-18 12:45:39 -07002964 list_is_dirs = true;
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01002965
2966 } else {
2967
2968 char *home = secure_getenv("HOME");
2969 if (home != NULL) {
2970 char *home_loc = loader_stack_alloc(strlen(home) + 16 +
2971 strlen(home_location));
2972 if (home_loc == NULL) {
Mark Youngb6399312017-01-10 14:22:15 -07002973 loader_log(
2974 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2975 "loader_get_manifest_files: Failed to allocate "
2976 " space for manifest file Home location");
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01002977 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2978 goto out;
2979 }
2980 strcpy(home_loc, home);
2981
2982 len = strlen(home);
2983 if (home[len] != DIRECTORY_SYMBOL) {
2984 home_loc[len] = DIRECTORY_SYMBOL;
2985 home_loc[len + 1] = '\0';
2986 }
2987 strcat(home_loc, ".local/share");
2988
2989 if (home_location[0] != DIRECTORY_SYMBOL) {
2990 len = strlen(home_loc);
2991 home_loc[len] = DIRECTORY_SYMBOL;
2992 home_loc[len + 1] = '\0';
2993 }
2994 strcat(home_loc, home_location);
2995 file = home_loc;
2996 next_file = loader_get_next_path(file);
2997 home_location = NULL;
2998
2999 loader_log(
3000 inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
3001 "Searching the following path for manifest files: %s\n",
3002 home_loc);
3003 list_is_dirs = true;
3004 } else {
3005 // without knowing HOME, we just.. give up
3006 }
Jon Ashburn67e262e2016-02-18 12:45:39 -07003007 }
3008 }
3009#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06003010 }
Mark Young0ad83132016-06-30 13:02:42 -06003011
3012out:
3013 if (VK_SUCCESS != res && NULL != out_files->filename_list) {
3014 for (uint32_t remove = 0; remove < out_files->count; remove++) {
3015 loader_instance_heap_free(inst, out_files->filename_list[remove]);
3016 }
3017 loader_instance_heap_free(inst, out_files->filename_list);
3018 out_files->count = 0;
3019 out_files->filename_list = NULL;
3020 }
3021
3022 if (NULL != sysdir) {
3023 closedir(sysdir);
3024 }
3025
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05003026 if (override_getenv != NULL) {
3027 loader_free_getenv(override_getenv, inst);
3028 }
3029
Mark Young0ad83132016-06-30 13:02:42 -06003030 if (NULL != reg && reg != orig_loc) {
3031 loader_instance_heap_free(inst, reg);
3032 }
3033 return res;
Jon Ashburn2077e382015-06-29 11:25:34 -06003034}
3035
Jon Ashburn23d36b12016-02-02 17:47:28 -07003036void loader_init_icd_lib_list() {}
Jon Ashburn8810c5f2015-08-18 18:04:47 -06003037
Jon Ashburn23d36b12016-02-02 17:47:28 -07003038void loader_destroy_icd_lib_list() {}
Jon Ashburn2077e382015-06-29 11:25:34 -06003039/**
3040 * Try to find the Vulkan ICD driver(s).
3041 *
3042 * This function scans the default system loader path(s) or path
3043 * specified by the \c VK_ICD_FILENAMES environment variable in
3044 * order to find loadable VK ICDs manifest files. From these
3045 * manifest files it finds the ICD libraries.
3046 *
3047 * \returns
Mark Young0ad83132016-06-30 13:02:42 -06003048 * Vulkan result
3049 * (on result == VK_SUCCESS) a list of icds that were discovered
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06003050 */
Mark Young0ad83132016-06-30 13:02:42 -06003051VkResult loader_icd_scan(const struct loader_instance *inst,
Mark Young0153e0b2016-11-03 14:27:13 -06003052 struct loader_icd_tramp_list *icd_tramp_list) {
Jon Ashburn2077e382015-06-29 11:25:34 -06003053 char *file_str;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003054 uint16_t file_major_vers = 0;
3055 uint16_t file_minor_vers = 0;
3056 uint16_t file_patch_vers = 0;
3057 char *vers_tok;
Jon Ashburn2077e382015-06-29 11:25:34 -06003058 struct loader_manifest_files manifest_files;
Mark Young0ad83132016-06-30 13:02:42 -06003059 VkResult res = VK_SUCCESS;
3060 bool lockedMutex = false;
3061 cJSON *json = NULL;
Mark Young3a587792016-08-19 15:25:08 -06003062 uint32_t num_good_icds = 0;
Jon Ashburn2077e382015-06-29 11:25:34 -06003063
Mark Young0ad83132016-06-30 13:02:42 -06003064 memset(&manifest_files, 0, sizeof(struct loader_manifest_files));
3065
Mark Young0153e0b2016-11-03 14:27:13 -06003066 res = loader_scanned_icd_init(inst, icd_tramp_list);
Mark Young0ad83132016-06-30 13:02:42 -06003067 if (VK_SUCCESS != res) {
3068 goto out;
3069 }
3070
Jon Ashburn2077e382015-06-29 11:25:34 -06003071 // Get a list of manifest files for ICDs
Mark Young0ad83132016-06-30 13:02:42 -06003072 res = loader_get_manifest_files(inst, "VK_ICD_FILENAMES", NULL, false,
Mark Youngf8c20102016-11-07 16:26:17 -07003073 true, DEFAULT_VK_DRIVERS_INFO,
Mark Young0ad83132016-06-30 13:02:42 -06003074 HOME_VK_DRIVERS_INFO, &manifest_files);
3075 if (VK_SUCCESS != res || manifest_files.count == 0) {
3076 goto out;
3077 }
Jon Ashburn6461ef22015-09-22 13:11:00 -06003078 loader_platform_thread_lock_mutex(&loader_json_lock);
Mark Young0ad83132016-06-30 13:02:42 -06003079 lockedMutex = true;
Jon Ashburn2077e382015-06-29 11:25:34 -06003080 for (uint32_t i = 0; i < manifest_files.count; i++) {
3081 file_str = manifest_files.filename_list[i];
Mark Young0ad83132016-06-30 13:02:42 -06003082 if (file_str == NULL) {
Jon Ashburn2077e382015-06-29 11:25:34 -06003083 continue;
Mark Young0ad83132016-06-30 13:02:42 -06003084 }
Jon Ashburn2077e382015-06-29 11:25:34 -06003085
Mark Young3a587792016-08-19 15:25:08 -06003086 res = loader_get_json(inst, file_str, &json);
3087 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
3088 break;
3089 } else if (VK_SUCCESS != res || NULL == json) {
Jon Ashburnaa4ea472015-08-27 08:30:50 -06003090 continue;
Mark Young0ad83132016-06-30 13:02:42 -06003091 }
Mark Young3a587792016-08-19 15:25:08 -06003092
Jon Ashburn005617f2015-11-17 17:35:40 -07003093 cJSON *item, *itemICD;
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003094 item = cJSON_GetObjectItem(json, "file_format_version");
Jon Ashburn6461ef22015-09-22 13:11:00 -06003095 if (item == NULL) {
Mark Young3a587792016-08-19 15:25:08 -06003096 if (num_good_icds == 0) {
3097 res = VK_ERROR_INITIALIZATION_FAILED;
3098 }
Mark Youngb6399312017-01-10 14:22:15 -07003099 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3100 "loader_icd_scan: ICD JSON %s does not have a"
3101 " \'file_format_version\' field. Skipping ICD JSON.",
3102 file_str);
Derrick Owens62e16ef2016-09-09 15:49:07 -04003103 cJSON_Delete(json);
3104 json = NULL;
Mark Young3a587792016-08-19 15:25:08 -06003105 continue;
Jon Ashburn6461ef22015-09-22 13:11:00 -06003106 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003107 char *file_vers = cJSON_Print(item);
Mark Young0ad83132016-06-30 13:02:42 -06003108 if (NULL == file_vers) {
3109 // Only reason the print can fail is if there was an allocation
3110 // issue
Mark Young3a587792016-08-19 15:25:08 -06003111 if (num_good_icds == 0) {
3112 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3113 }
Mark Youngb6399312017-01-10 14:22:15 -07003114 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3115 "loader_icd_scan: Failed retrieving ICD JSON %s"
3116 " \'file_format_version\' field. Skipping ICD JSON",
3117 file_str);
Derrick Owenscd92b8b2016-09-09 15:45:13 -04003118 cJSON_Delete(json);
3119 json = NULL;
Mark Young3a587792016-08-19 15:25:08 -06003120 continue;
Mark Young0ad83132016-06-30 13:02:42 -06003121 }
Mark Youngcbcbf892016-06-22 15:25:00 -06003122 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07003123 "Found ICD manifest file %s, version %s", file_str,
3124 file_vers);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003125 // Get the major/minor/and patch as integers for easier comparison
3126 vers_tok = strtok(file_vers, ".\"\n\r");
3127 if (NULL != vers_tok) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04003128 file_major_vers = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003129 vers_tok = strtok(NULL, ".\"\n\r");
3130 if (NULL != vers_tok) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04003131 file_minor_vers = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003132 vers_tok = strtok(NULL, ".\"\n\r");
3133 if (NULL != vers_tok) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04003134 file_patch_vers = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003135 }
3136 }
3137 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003138 if (file_major_vers != 1 || file_minor_vers != 0 || file_patch_vers > 1)
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07003139 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07003140 "loader_icd_scan: Unexpected manifest file version "
3141 "(expected 1.0.0 or 1.0.1), may cause errors");
Mark Young0ad83132016-06-30 13:02:42 -06003142 cJSON_Free(file_vers);
Jon Ashburn005617f2015-11-17 17:35:40 -07003143 itemICD = cJSON_GetObjectItem(json, "ICD");
3144 if (itemICD != NULL) {
3145 item = cJSON_GetObjectItem(itemICD, "library_path");
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003146 if (item != NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003147 char *temp = cJSON_Print(item);
Jon Ashburn86251302015-08-25 16:48:24 -06003148 if (!temp || strlen(temp) == 0) {
Mark Young3a587792016-08-19 15:25:08 -06003149 if (num_good_icds == 0) {
3150 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3151 }
Mark Youngb6399312017-01-10 14:22:15 -07003152 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3153 "loader_icd_scan: Failed retrieving ICD JSON %s"
3154 " \'library_path\' field. Skipping ICD JSON.",
3155 file_str);
Mark Young0ad83132016-06-30 13:02:42 -06003156 cJSON_Free(temp);
Jon Ashburn86251302015-08-25 16:48:24 -06003157 cJSON_Delete(json);
Mark Young0ad83132016-06-30 13:02:42 -06003158 json = NULL;
Jon Ashburn86251302015-08-25 16:48:24 -06003159 continue;
Jon Ashburn2077e382015-06-29 11:25:34 -06003160 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07003161 // strip out extra quotes
Jon Ashburn86251302015-08-25 16:48:24 -06003162 temp[strlen(temp) - 1] = '\0';
3163 char *library_path = loader_stack_alloc(strlen(temp) + 1);
Mark Young3a587792016-08-19 15:25:08 -06003164 if (NULL == library_path) {
Mark Youngb6399312017-01-10 14:22:15 -07003165 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3166 "loader_icd_scan: Failed to allocate space for "
3167 "ICD JSON %s \'library_path\' value. Skipping "
3168 " ICD JSON.",
3169 file_str);
Mark Young3a587792016-08-19 15:25:08 -06003170 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3171 cJSON_Free(temp);
3172 cJSON_Delete(json);
3173 json = NULL;
3174 goto out;
3175 }
Jon Ashburn86251302015-08-25 16:48:24 -06003176 strcpy(library_path, &temp[1]);
Mark Young0ad83132016-06-30 13:02:42 -06003177 cJSON_Free(temp);
Mark Young3a587792016-08-19 15:25:08 -06003178 if (strlen(library_path) == 0) {
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07003179 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07003180 "loader_icd_scan: ICD JSON %s \'library_path\'"
3181 " field is empty. Skipping ICD JSON.",
Jon Ashburn23d36b12016-02-02 17:47:28 -07003182 file_str);
Jon Ashburn86251302015-08-25 16:48:24 -06003183 cJSON_Delete(json);
Mark Young0ad83132016-06-30 13:02:42 -06003184 json = NULL;
Jon Ashburn86251302015-08-25 16:48:24 -06003185 continue;
3186 }
Jamie Madill2fcbd152016-04-27 16:33:23 -04003187 char fullpath[MAX_STRING_SIZE];
Jon Ashburn86251302015-08-25 16:48:24 -06003188 // Print out the paths being searched if debugging is enabled
Jon Ashburn23d36b12016-02-02 17:47:28 -07003189 loader_log(
3190 inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07003191 "Searching for ICD drivers named %s, using default dir %s",
Jamie Madill2fcbd152016-04-27 16:33:23 -04003192 library_path, DEFAULT_VK_DRIVERS_PATH);
Daniel Dadap00b4aba2015-09-30 11:50:51 -05003193 if (loader_platform_is_path(library_path)) {
Jon Ashburn86251302015-08-25 16:48:24 -06003194 // a relative or absolute path
Daniel Dadap00b4aba2015-09-30 11:50:51 -05003195 char *name_copy = loader_stack_alloc(strlen(file_str) + 1);
3196 char *rel_base;
Jon Ashburn86251302015-08-25 16:48:24 -06003197 strcpy(name_copy, file_str);
3198 rel_base = loader_platform_dirname(name_copy);
Jon Ashburn23d36b12016-02-02 17:47:28 -07003199 loader_expand_path(library_path, rel_base, sizeof(fullpath),
3200 fullpath);
Daniel Dadap00b4aba2015-09-30 11:50:51 -05003201 } else {
Jamie Madill2fcbd152016-04-27 16:33:23 -04003202 // a filename which is assumed in a system directory
3203 loader_get_fullpath(library_path, DEFAULT_VK_DRIVERS_PATH,
3204 sizeof(fullpath), fullpath);
Jon Ashburn86251302015-08-25 16:48:24 -06003205 }
Jon Ashburn005617f2015-11-17 17:35:40 -07003206
3207 uint32_t vers = 0;
3208 item = cJSON_GetObjectItem(itemICD, "api_version");
3209 if (item != NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003210 temp = cJSON_Print(item);
Mark Young0ad83132016-06-30 13:02:42 -06003211 if (NULL == temp) {
Mark Youngb6399312017-01-10 14:22:15 -07003212 loader_log(
3213 inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3214 "loader_icd_scan: Failed retrieving ICD JSON %s"
3215 " \'api_version\' field. Skipping ICD JSON.",
3216 file_str);
3217
Mark Young0ad83132016-06-30 13:02:42 -06003218 // Only reason the print can fail is if there was an
3219 // allocation issue
Mark Youngb6399312017-01-10 14:22:15 -07003220 if (num_good_icds == 0) {
3221 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3222 }
3223
3224 cJSON_Free(temp);
3225 cJSON_Delete(json);
3226 json = NULL;
3227 continue;
Mark Young0ad83132016-06-30 13:02:42 -06003228 }
Jon Ashburn005617f2015-11-17 17:35:40 -07003229 vers = loader_make_version(temp);
Mark Young0ad83132016-06-30 13:02:42 -06003230 cJSON_Free(temp);
Mark Youngb6399312017-01-10 14:22:15 -07003231 } else {
3232 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3233 "loader_icd_scan: ICD JSON %s does not have an"
3234 " \'api_version\' field.",
3235 file_str);
Jon Ashburn005617f2015-11-17 17:35:40 -07003236 }
Mark Youngb6399312017-01-10 14:22:15 -07003237
Mark Young0153e0b2016-11-03 14:27:13 -06003238 res = loader_scanned_icd_add(inst, icd_tramp_list, fullpath,
3239 vers);
Mark Young3a587792016-08-19 15:25:08 -06003240 if (VK_SUCCESS != res) {
Mark Youngb6399312017-01-10 14:22:15 -07003241 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3242 "loader_icd_scan: Failed to add ICD JSON %s. "
3243 " Skipping ICD JSON.",
3244 fullpath);
3245 cJSON_Free(temp);
3246 cJSON_Delete(json);
3247 json = NULL;
3248 continue;
Mark Young3a587792016-08-19 15:25:08 -06003249 }
3250 num_good_icds++;
Mark Young0ad83132016-06-30 13:02:42 -06003251 } else {
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07003252 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07003253 "loader_icd_scan: Failed to find \'library_path\' "
3254 "object in ICD JSON file %s. Skipping ICD JSON.",
Jon Ashburn23d36b12016-02-02 17:47:28 -07003255 file_str);
Mark Young0ad83132016-06-30 13:02:42 -06003256 }
3257 } else {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003258 loader_log(
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07003259 inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07003260 "loader_icd_scan: Can not find \'ICD\' object in ICD JSON "
3261 "file %s. Skipping ICD JSON",
Jon Ashburn23d36b12016-02-02 17:47:28 -07003262 file_str);
Mark Young0ad83132016-06-30 13:02:42 -06003263 }
Jon Ashburn2077e382015-06-29 11:25:34 -06003264
Mark Young0ad83132016-06-30 13:02:42 -06003265 cJSON_Delete(json);
3266 json = NULL;
3267 }
3268
3269out:
Mark Youngb6399312017-01-10 14:22:15 -07003270
Mark Young0ad83132016-06-30 13:02:42 -06003271 if (NULL != json) {
Jon Ashburn2077e382015-06-29 11:25:34 -06003272 cJSON_Delete(json);
3273 }
Mark Young0ad83132016-06-30 13:02:42 -06003274 if (NULL != manifest_files.filename_list) {
3275 for (uint32_t i = 0; i < manifest_files.count; i++) {
3276 if (NULL != manifest_files.filename_list[i]) {
3277 loader_instance_heap_free(inst,
3278 manifest_files.filename_list[i]);
3279 }
3280 }
3281 loader_instance_heap_free(inst, manifest_files.filename_list);
3282 }
3283 if (lockedMutex) {
3284 loader_platform_thread_unlock_mutex(&loader_json_lock);
3285 }
3286 return res;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08003287}
3288
Jon Ashburn23d36b12016-02-02 17:47:28 -07003289void loader_layer_scan(const struct loader_instance *inst,
Jon Ashburn491cd042016-05-16 14:01:18 -06003290 struct loader_layer_list *instance_layers) {
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003291 char *file_str;
Jon Ashburn23d36b12016-02-02 17:47:28 -07003292 struct loader_manifest_files
3293 manifest_files[2]; // [0] = explicit, [1] = implicit
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003294 cJSON *json;
Jon Ashburn075ce432015-12-17 17:38:24 -07003295 uint32_t implicit;
Mark Young0ad83132016-06-30 13:02:42 -06003296 bool lockedMutex = false;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003297
Mark Young0ad83132016-06-30 13:02:42 -06003298 memset(manifest_files, 0, sizeof(struct loader_manifest_files) * 2);
3299
3300 // Get a list of manifest files for explicit layers
3301 if (VK_SUCCESS !=
3302 loader_get_manifest_files(inst, LAYERS_PATH_ENV, LAYERS_SOURCE_PATH,
Mark Youngf8c20102016-11-07 16:26:17 -07003303 true, true, DEFAULT_VK_ELAYERS_INFO,
Mark Young0ad83132016-06-30 13:02:42 -06003304 HOME_VK_ELAYERS_INFO, &manifest_files[0])) {
3305 goto out;
3306 }
3307
3308 // Get a list of manifest files for any implicit layers
Jon Ashburn23d36b12016-02-02 17:47:28 -07003309 // Pass NULL for environment variable override - implicit layers are not
3310 // overridden by LAYERS_PATH_ENV
Mark Youngf8c20102016-11-07 16:26:17 -07003311 if (VK_SUCCESS != loader_get_manifest_files(inst, NULL, NULL, true, false,
3312 DEFAULT_VK_ILAYERS_INFO,
3313 HOME_VK_ILAYERS_INFO,
3314 &manifest_files[1])) {
Mark Young0ad83132016-06-30 13:02:42 -06003315 goto out;
3316 }
Jon Ashburn90c6a0e2015-06-04 15:30:58 -06003317
Mark Young0ad83132016-06-30 13:02:42 -06003318 // Make sure we have at least one layer, if not, go ahead and return
3319 if (manifest_files[0].count == 0 && manifest_files[1].count == 0) {
3320 goto out;
3321 }
3322
3323 // cleanup any previously scanned libraries
Jon Ashburne39a4f82015-08-28 13:38:21 -06003324 loader_delete_layer_properties(inst, instance_layers);
Jon Ashburnb2ef1372015-07-16 17:19:31 -06003325
Jon Ashburn6461ef22015-09-22 13:11:00 -06003326 loader_platform_thread_lock_mutex(&loader_json_lock);
Mark Young0ad83132016-06-30 13:02:42 -06003327 lockedMutex = true;
Jon Ashburn075ce432015-12-17 17:38:24 -07003328 for (implicit = 0; implicit < 2; implicit++) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04003329 for (uint32_t i = 0; i < manifest_files[implicit].count; i++) {
Jon Ashburn075ce432015-12-17 17:38:24 -07003330 file_str = manifest_files[implicit].filename_list[i];
3331 if (file_str == NULL)
3332 continue;
Courtney Goeltzenleuchtera9e4af42015-06-01 14:49:17 -06003333
Jon Ashburn075ce432015-12-17 17:38:24 -07003334 // parse file into JSON struct
Mark Young3a587792016-08-19 15:25:08 -06003335 VkResult res = loader_get_json(inst, file_str, &json);
3336 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
3337 break;
3338 } else if (VK_SUCCESS != res || NULL == json) {
Jon Ashburn075ce432015-12-17 17:38:24 -07003339 continue;
3340 }
3341
Jon Ashburn491cd042016-05-16 14:01:18 -06003342 loader_add_layer_properties(inst, instance_layers, json,
3343 (implicit == 1), file_str);
Jon Ashburn075ce432015-12-17 17:38:24 -07003344 cJSON_Delete(json);
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003345 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003346 }
Jon Ashburn86a527a2016-02-10 20:59:26 -07003347
3348 // add a meta layer for validation if the validation layers are all present
Mark Young0ad83132016-06-30 13:02:42 -06003349 loader_add_layer_property_meta(inst, sizeof(std_validation_names) /
3350 sizeof(std_validation_names[0]),
3351 std_validation_names, instance_layers);
Jon Ashburn86a527a2016-02-10 20:59:26 -07003352
Mark Young0ad83132016-06-30 13:02:42 -06003353out:
3354
3355 for (uint32_t manFile = 0; manFile < 2; manFile++) {
3356 if (NULL != manifest_files[manFile].filename_list) {
3357 for (uint32_t i = 0; i < manifest_files[manFile].count; i++) {
3358 if (NULL != manifest_files[manFile].filename_list[i]) {
3359 loader_instance_heap_free(
3360 inst, manifest_files[manFile].filename_list[i]);
3361 }
3362 }
3363 loader_instance_heap_free(inst,
3364 manifest_files[manFile].filename_list);
3365 }
3366 }
3367 if (lockedMutex) {
3368 loader_platform_thread_unlock_mutex(&loader_json_lock);
3369 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003370}
3371
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003372void loader_implicit_layer_scan(const struct loader_instance *inst,
Jon Ashburn491cd042016-05-16 14:01:18 -06003373 struct loader_layer_list *instance_layers) {
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003374 char *file_str;
3375 struct loader_manifest_files manifest_files;
3376 cJSON *json;
3377 uint32_t i;
3378
3379 // Pass NULL for environment variable override - implicit layers are not
3380 // overridden by LAYERS_PATH_ENV
Mark Young0ad83132016-06-30 13:02:42 -06003381 VkResult res = loader_get_manifest_files(
Mark Youngf8c20102016-11-07 16:26:17 -07003382 inst, NULL, NULL, true, false, DEFAULT_VK_ILAYERS_INFO,
3383 HOME_VK_ILAYERS_INFO, &manifest_files);
Mark Young0ad83132016-06-30 13:02:42 -06003384 if (VK_SUCCESS != res || manifest_files.count == 0) {
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003385 return;
3386 }
3387
3388 /* cleanup any previously scanned libraries */
3389 loader_delete_layer_properties(inst, instance_layers);
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003390
3391 loader_platform_thread_lock_mutex(&loader_json_lock);
3392
3393 for (i = 0; i < manifest_files.count; i++) {
3394 file_str = manifest_files.filename_list[i];
3395 if (file_str == NULL) {
3396 continue;
3397 }
3398
3399 // parse file into JSON struct
Mark Young3a587792016-08-19 15:25:08 -06003400 res = loader_get_json(inst, file_str, &json);
3401 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
3402 break;
3403 } else if (VK_SUCCESS != res || NULL == json) {
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003404 continue;
3405 }
3406
Mark Young0ad83132016-06-30 13:02:42 -06003407 loader_add_layer_properties(inst, instance_layers, json, true,
3408 file_str);
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003409
Mark Young0ad83132016-06-30 13:02:42 -06003410 loader_instance_heap_free(inst, file_str);
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003411 cJSON_Delete(json);
3412 }
Mark Young0ad83132016-06-30 13:02:42 -06003413 loader_instance_heap_free(inst, manifest_files.filename_list);
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003414
3415 // add a meta layer for validation if the validation layers are all present
Mark Young0ad83132016-06-30 13:02:42 -06003416 loader_add_layer_property_meta(inst, sizeof(std_validation_names) /
3417 sizeof(std_validation_names[0]),
3418 std_validation_names, instance_layers);
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003419
3420 loader_platform_thread_unlock_mutex(&loader_json_lock);
3421}
3422
Jon Ashburn23d36b12016-02-02 17:47:28 -07003423static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
3424loader_gpa_instance_internal(VkInstance inst, const char *pName) {
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003425 if (!strcmp(pName, "vkGetInstanceProcAddr"))
Jon Ashburn23d36b12016-02-02 17:47:28 -07003426 return (void *)loader_gpa_instance_internal;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003427 if (!strcmp(pName, "vkCreateInstance"))
Jon Ashburn1530c342016-02-26 13:14:27 -07003428 return (void *)terminator_CreateInstance;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003429 if (!strcmp(pName, "vkCreateDevice"))
Jon Ashburn1530c342016-02-26 13:14:27 -07003430 return (void *)terminator_CreateDevice;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003431
Jon Ashburn27cd5842015-05-12 17:26:48 -06003432 // inst is not wrapped
3433 if (inst == VK_NULL_HANDLE) {
3434 return NULL;
3435 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07003436 VkLayerInstanceDispatchTable *disp_table =
3437 *(VkLayerInstanceDispatchTable **)inst;
Jon Ashburn27cd5842015-05-12 17:26:48 -06003438 void *addr;
3439
3440 if (disp_table == NULL)
3441 return NULL;
3442
Jon Ashburnc7d3e732016-03-08 09:30:30 -07003443 bool found_name;
Jon Ashburncc407a22016-04-15 09:25:03 -06003444 addr =
3445 loader_lookup_instance_dispatch_table(disp_table, pName, &found_name);
Jon Ashburnc7d3e732016-03-08 09:30:30 -07003446 if (found_name) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06003447 return addr;
Jon Ashburn3d526cb2015-04-13 18:10:06 -06003448 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003449
Jon Ashburnc7d3e732016-03-08 09:30:30 -07003450 // Don't call down the chain, this would be an infinite loop
3451 loader_log(NULL, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Jon Ashburncc407a22016-04-15 09:25:03 -06003452 "loader_gpa_instance_internal() unrecognized name %s", pName);
Jon Ashburnc7d3e732016-03-08 09:30:30 -07003453 return NULL;
Jon Ashburn3d526cb2015-04-13 18:10:06 -06003454}
3455
Piers Daniellf9262be2016-09-14 11:24:36 -06003456VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
Jon Ashburncc407a22016-04-15 09:25:03 -06003457loader_gpa_device_internal(VkDevice device, const char *pName) {
3458 struct loader_device *dev;
Mark Young0153e0b2016-11-03 14:27:13 -06003459 struct loader_icd_term *icd_term =
3460 loader_get_icd_and_device(device, &dev, NULL);
Mark Young16573c72016-06-28 10:52:43 -06003461
Mark Young65cb3662016-11-07 13:27:02 -07003462 // NOTE: Device Funcs needing Trampoline/Terminator.
3463 // Overrides for device functions needing a trampoline and
3464 // a terminator because certain device entry-points still need to go
3465 // through a terminator before hitting the ICD. This could be for
3466 // several reasons, but the main one is currently unwrapping an
3467 // object before passing the appropriate info along to the ICD.
3468 // This is why we also have to override the direct ICD call to
3469 // vkGetDeviceProcAddr to intercept those calls.
3470 if (!strcmp(pName, "vkGetDeviceProcAddr")) {
3471 return (PFN_vkVoidFunction)loader_gpa_device_internal;
3472 } else if (!strcmp(pName, "vkCreateSwapchainKHR")) {
Mark Young16573c72016-06-28 10:52:43 -06003473 return (PFN_vkVoidFunction)terminator_vkCreateSwapchainKHR;
Mark Young65cb3662016-11-07 13:27:02 -07003474 } else if (!strcmp(pName, "vkDebugMarkerSetObjectTagEXT")) {
3475 return (PFN_vkVoidFunction)terminator_DebugMarkerSetObjectTagEXT;
3476 } else if (!strcmp(pName, "vkDebugMarkerSetObjectNameEXT")) {
3477 return (PFN_vkVoidFunction)terminator_DebugMarkerSetObjectNameEXT;
Mark Young16573c72016-06-28 10:52:43 -06003478 }
3479
Mark Young0153e0b2016-11-03 14:27:13 -06003480 return icd_term->GetDeviceProcAddr(device, pName);
Piers Daniell295fe402016-03-29 11:51:11 -06003481}
3482
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003483/**
3484 * Initialize device_ext dispatch table entry as follows:
3485 * If dev == NULL find all logical devices created within this instance and
3486 * init the entry (given by idx) in the ext dispatch table.
3487 * If dev != NULL only initialize the entry in the given dev's dispatch table.
Jon Ashburn23d36b12016-02-02 17:47:28 -07003488 * The initialization value is gotten by calling down the device chain with
3489 * GDPA.
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003490 * If GDPA returns NULL then don't initialize the dispatch table entry.
3491 */
3492static void loader_init_dispatch_dev_ext_entry(struct loader_instance *inst,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003493 struct loader_device *dev,
3494 uint32_t idx,
3495 const char *funcName)
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003496
Jon Ashburn23d36b12016-02-02 17:47:28 -07003497{
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003498 void *gdpa_value;
3499 if (dev != NULL) {
3500 gdpa_value = dev->loader_dispatch.core_dispatch.GetDeviceProcAddr(
Mark Young65cb3662016-11-07 13:27:02 -07003501 dev->chain_device, funcName);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003502 if (gdpa_value != NULL)
Mark Young8191d9f2016-09-02 11:41:28 -06003503 dev->loader_dispatch.ext_dispatch.dev_ext[idx] =
Jon Ashburn23d36b12016-02-02 17:47:28 -07003504 (PFN_vkDevExt)gdpa_value;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003505 } else {
Mark Young0153e0b2016-11-03 14:27:13 -06003506 for (struct loader_icd_term *icd_term = inst->icd_terms;
3507 icd_term != NULL; icd_term = icd_term->next) {
3508 struct loader_device *ldev = icd_term->logical_device_list;
Karl Schultz2558bd32016-02-24 14:39:39 -07003509 while (ldev) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003510 gdpa_value =
Karl Schultz2558bd32016-02-24 14:39:39 -07003511 ldev->loader_dispatch.core_dispatch.GetDeviceProcAddr(
Mark Young65cb3662016-11-07 13:27:02 -07003512 ldev->chain_device, funcName);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003513 if (gdpa_value != NULL)
Mark Young8191d9f2016-09-02 11:41:28 -06003514 ldev->loader_dispatch.ext_dispatch.dev_ext[idx] =
Jon Ashburn23d36b12016-02-02 17:47:28 -07003515 (PFN_vkDevExt)gdpa_value;
Karl Schultz2558bd32016-02-24 14:39:39 -07003516 ldev = ldev->next;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003517 }
3518 }
3519 }
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003520}
3521
3522/**
3523 * Find all dev extension in the hash table and initialize the dispatch table
3524 * for dev for each of those extension entrypoints found in hash table.
3525
3526 */
Jon Ashburn1530c342016-02-26 13:14:27 -07003527void loader_init_dispatch_dev_ext(struct loader_instance *inst,
3528 struct loader_device *dev) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003529 for (uint32_t i = 0; i < MAX_NUM_DEV_EXTS; i++) {
3530 if (inst->disp_hash[i].func_name != NULL)
3531 loader_init_dispatch_dev_ext_entry(inst, dev, i,
3532 inst->disp_hash[i].func_name);
3533 }
3534}
3535
3536static bool loader_check_icds_for_address(struct loader_instance *inst,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003537 const char *funcName) {
Mark Young0153e0b2016-11-03 14:27:13 -06003538 struct loader_icd_term *icd_term;
3539 icd_term = inst->icd_terms;
3540 while (NULL != icd_term) {
3541 if (icd_term->scanned_icd->GetInstanceProcAddr(icd_term->instance,
3542 funcName))
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003543 // this icd supports funcName
3544 return true;
Mark Young0153e0b2016-11-03 14:27:13 -06003545 icd_term = icd_term->next;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003546 }
3547
3548 return false;
3549}
3550
Jon Ashburncc407a22016-04-15 09:25:03 -06003551static bool loader_check_layer_list_for_address(
3552 const struct loader_layer_list *const layers, const char *funcName) {
Jeremy Hayes1eb1f622016-03-03 16:03:03 -07003553 // Iterate over the layers.
Jon Ashburncc407a22016-04-15 09:25:03 -06003554 for (uint32_t layer = 0; layer < layers->count; ++layer) {
Jeremy Hayes1eb1f622016-03-03 16:03:03 -07003555 // Iterate over the extensions.
Jon Ashburncc407a22016-04-15 09:25:03 -06003556 const struct loader_device_extension_list *const extensions =
3557 &(layers->list[layer].device_extension_list);
3558 for (uint32_t extension = 0; extension < extensions->count;
3559 ++extension) {
Jeremy Hayes1eb1f622016-03-03 16:03:03 -07003560 // Iterate over the entry points.
Jon Ashburncc407a22016-04-15 09:25:03 -06003561 const struct loader_dev_ext_props *const property =
3562 &(extensions->list[extension]);
3563 for (uint32_t entry = 0; entry < property->entrypoint_count;
3564 ++entry) {
3565 if (strcmp(property->entrypoints[entry], funcName) == 0) {
Jeremy Hayes1eb1f622016-03-03 16:03:03 -07003566 return true;
3567 }
3568 }
3569 }
3570 }
3571
3572 return false;
3573}
3574
Jon Ashburn23d36b12016-02-02 17:47:28 -07003575static void loader_free_dev_ext_table(struct loader_instance *inst) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003576 for (uint32_t i = 0; i < MAX_NUM_DEV_EXTS; i++) {
Mark Young0ad83132016-06-30 13:02:42 -06003577 loader_instance_heap_free(inst, inst->disp_hash[i].func_name);
3578 loader_instance_heap_free(inst, inst->disp_hash[i].list.index);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003579 }
3580 memset(inst->disp_hash, 0, sizeof(inst->disp_hash));
3581}
3582
3583static bool loader_add_dev_ext_table(struct loader_instance *inst,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003584 uint32_t *ptr_idx, const char *funcName) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003585 uint32_t i;
3586 uint32_t idx = *ptr_idx;
3587 struct loader_dispatch_hash_list *list = &inst->disp_hash[idx].list;
3588
3589 if (!inst->disp_hash[idx].func_name) {
3590 // no entry here at this idx, so use it
3591 assert(list->capacity == 0);
Mark Young0ad83132016-06-30 13:02:42 -06003592 inst->disp_hash[idx].func_name = (char *)loader_instance_heap_alloc(
Jon Ashburn23d36b12016-02-02 17:47:28 -07003593 inst, strlen(funcName) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003594 if (inst->disp_hash[idx].func_name == NULL) {
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07003595 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07003596 "loader_add_dev_ext_table: Failed to allocate memory "
3597 "for func_name %s",
3598 funcName);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003599 return false;
3600 }
3601 strncpy(inst->disp_hash[idx].func_name, funcName, strlen(funcName) + 1);
3602 return true;
3603 }
3604
3605 // check for enough capacity
3606 if (list->capacity == 0) {
Mark Young0153e0b2016-11-03 14:27:13 -06003607 list->index =
3608 loader_instance_heap_alloc(inst, 8 * sizeof(*(list->index)),
3609 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003610 if (list->index == NULL) {
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07003611 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07003612 "loader_add_dev_ext_table: Failed to allocate memory "
3613 "for list index",
3614 funcName);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003615 return false;
3616 }
3617 list->capacity = 8 * sizeof(*(list->index));
3618 } else if (list->capacity < (list->count + 1) * sizeof(*(list->index))) {
Mark Young0153e0b2016-11-03 14:27:13 -06003619 list->index = loader_instance_heap_realloc(
3620 inst, list->index, list->capacity, list->capacity * 2,
3621 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003622 if (list->index == NULL) {
Mark Youngb6399312017-01-10 14:22:15 -07003623 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3624 "loader_add_dev_ext_table: Failed to reallocate memory "
3625 "for list index",
3626 funcName);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003627 return false;
3628 }
3629 list->capacity *= 2;
3630 }
3631
Jon Ashburn23d36b12016-02-02 17:47:28 -07003632 // find an unused index in the hash table and use it
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003633 i = (idx + 1) % MAX_NUM_DEV_EXTS;
3634 do {
3635 if (!inst->disp_hash[i].func_name) {
3636 assert(inst->disp_hash[i].list.capacity == 0);
Mark Young0153e0b2016-11-03 14:27:13 -06003637 inst->disp_hash[i].func_name = (char *)loader_instance_heap_alloc(
3638 inst, strlen(funcName) + 1,
3639 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003640 if (inst->disp_hash[i].func_name == NULL) {
Mark Youngb6399312017-01-10 14:22:15 -07003641 loader_log(
3642 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3643 "loader_add_dev_ext_table: Failed to allocate memory "
3644 "for func_name %s",
3645 funcName);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003646 return false;
3647 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07003648 strncpy(inst->disp_hash[i].func_name, funcName,
3649 strlen(funcName) + 1);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003650 list->index[list->count] = i;
3651 list->count++;
3652 *ptr_idx = i;
3653 return true;
3654 }
3655 i = (i + 1) % MAX_NUM_DEV_EXTS;
3656 } while (i != idx);
3657
Mark Youngb6399312017-01-10 14:22:15 -07003658 loader_log(
3659 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3660 "loader_add_dev_ext_table: Could not insert into hash table; is "
3661 "it full?");
3662
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003663 return false;
3664}
3665
3666static bool loader_name_in_dev_ext_table(struct loader_instance *inst,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003667 uint32_t *idx, const char *funcName) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003668 uint32_t alt_idx;
Jon Ashburn23d36b12016-02-02 17:47:28 -07003669 if (inst->disp_hash[*idx].func_name &&
3670 !strcmp(inst->disp_hash[*idx].func_name, funcName))
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003671 return true;
3672
3673 // funcName wasn't at the primary spot in the hash table
3674 // search the list of secondary locations (shallow search, not deep search)
3675 for (uint32_t i = 0; i < inst->disp_hash[*idx].list.count; i++) {
3676 alt_idx = inst->disp_hash[*idx].list.index[i];
3677 if (!strcmp(inst->disp_hash[*idx].func_name, funcName)) {
3678 *idx = alt_idx;
3679 return true;
3680 }
3681 }
3682
3683 return false;
3684}
3685
3686/**
Jon Ashburn23d36b12016-02-02 17:47:28 -07003687 * This function returns generic trampoline code address for unknown entry
3688 * points.
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003689 * Presumably, these unknown entry points (as given by funcName) are device
3690 * extension entrypoints. A hash table is used to keep a list of unknown entry
3691 * points and their mapping to the device extension dispatch table
3692 * (struct loader_dev_ext_dispatch_table).
3693 * \returns
Jon Ashburn23d36b12016-02-02 17:47:28 -07003694 * For a given entry point string (funcName), if an existing mapping is found
3695 * the
3696 * trampoline address for that mapping is returned. Otherwise, this unknown
3697 * entry point
3698 * has not been seen yet. Next check if a layer or ICD supports it. If so then
3699 * a
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003700 * new entry in the hash table is initialized and that trampoline address for
3701 * the new entry is returned. Null is returned if the hash table is full or
3702 * if no discovered layer or ICD returns a non-NULL GetProcAddr for it.
3703 */
Jon Ashburn23d36b12016-02-02 17:47:28 -07003704void *loader_dev_ext_gpa(struct loader_instance *inst, const char *funcName) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003705 uint32_t idx;
3706 uint32_t seed = 0;
3707
3708 idx = murmurhash(funcName, strlen(funcName), seed) % MAX_NUM_DEV_EXTS;
3709
3710 if (loader_name_in_dev_ext_table(inst, &idx, funcName))
3711 // found funcName already in hash
3712 return loader_get_dev_ext_trampoline(idx);
3713
3714 // Check if funcName is supported in either ICDs or a layer library
Jeremy Hayes1eb1f622016-03-03 16:03:03 -07003715 if (!loader_check_icds_for_address(inst, funcName) &&
Mark Young0153e0b2016-11-03 14:27:13 -06003716 !loader_check_layer_list_for_address(&inst->instance_layer_list,
3717 funcName)) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003718 // if support found in layers continue on
3719 return NULL;
3720 }
3721
3722 if (loader_add_dev_ext_table(inst, &idx, funcName)) {
3723 // successfully added new table entry
3724 // init any dev dispatch table entrys as needed
3725 loader_init_dispatch_dev_ext_entry(inst, NULL, idx, funcName);
3726 return loader_get_dev_ext_trampoline(idx);
3727 }
3728
3729 return NULL;
3730}
3731
Jon Ashburn23d36b12016-02-02 17:47:28 -07003732struct loader_instance *loader_get_instance(const VkInstance instance) {
Jon Ashburne0e64572015-09-30 12:56:42 -06003733 /* look up the loader_instance in our list by comparing dispatch tables, as
3734 * there is no guarantee the instance is still a loader_instance* after any
3735 * layers which wrap the instance object.
3736 */
3737 const VkLayerInstanceDispatchTable *disp;
3738 struct loader_instance *ptr_instance = NULL;
3739 disp = loader_get_instance_dispatch(instance);
Jon Ashburn23d36b12016-02-02 17:47:28 -07003740 for (struct loader_instance *inst = loader.instances; inst;
3741 inst = inst->next) {
Jon Ashburne0e64572015-09-30 12:56:42 -06003742 if (inst->disp == disp) {
3743 ptr_instance = inst;
3744 break;
3745 }
3746 }
3747 return ptr_instance;
3748}
3749
Jon Ashburn23d36b12016-02-02 17:47:28 -07003750static loader_platform_dl_handle
Mark Young0153e0b2016-11-03 14:27:13 -06003751loader_open_layer_lib(const struct loader_instance *inst,
3752 const char *chain_type,
3753 struct loader_layer_properties *prop) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003754
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06003755 if ((prop->lib_handle = loader_platform_open_library(prop->lib_name)) ==
Jon Ashburn23d36b12016-02-02 17:47:28 -07003756 NULL) {
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07003757 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07003758 "loader_open_layer_lib: Failed to open library %s",
3759 prop->lib_name);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003760 } else {
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07003761 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07003762 "Loading layer library %s", prop->lib_name);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003763 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003764
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06003765 return prop->lib_handle;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003766}
3767
Mark Young0153e0b2016-11-03 14:27:13 -06003768static void loader_close_layer_lib(const struct loader_instance *inst,
3769 struct loader_layer_properties *prop) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003770
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06003771 if (prop->lib_handle) {
3772 loader_platform_close_library(prop->lib_handle);
3773 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
3774 "Unloading layer library %s", prop->lib_name);
3775 prop->lib_handle = NULL;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003776 }
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06003777}
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003778
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06003779void loader_deactivate_layers(const struct loader_instance *instance,
Mark Young0ad83132016-06-30 13:02:42 -06003780 struct loader_device *device,
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06003781 struct loader_layer_list *list) {
3782 /* delete instance list of enabled layers and close any layer libraries */
3783 for (uint32_t i = 0; i < list->count; i++) {
3784 struct loader_layer_properties *layer_prop = &list->list[i];
Courtney Goeltzenleuchter80bfd0e2015-12-17 09:51:22 -07003785
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06003786 loader_close_layer_lib(instance, layer_prop);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07003787 }
Mark Young0ad83132016-06-30 13:02:42 -06003788 loader_destroy_layer_list(instance, device, list);
Jon Ashburnb8358052014-11-18 09:06:04 -07003789}
3790
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003791/**
3792 * Go through the search_list and find any layers which match type. If layer
3793 * type match is found in then add it to ext_list.
3794 */
Jon Ashburn23d36b12016-02-02 17:47:28 -07003795static void
3796loader_add_layer_implicit(const struct loader_instance *inst,
3797 const enum layer_type type,
3798 struct loader_layer_list *list,
3799 const struct loader_layer_list *search_list) {
Jon Ashburn075ce432015-12-17 17:38:24 -07003800 bool enable;
3801 char *env_value;
Jon Ashburn0c26e712015-07-02 16:10:32 -06003802 uint32_t i;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06003803 for (i = 0; i < search_list->count; i++) {
3804 const struct loader_layer_properties *prop = &search_list->list[i];
Jon Ashburn0c26e712015-07-02 16:10:32 -06003805 if (prop->type & type) {
Jon Ashburn075ce432015-12-17 17:38:24 -07003806 /* Found an implicit layer, see if it should be enabled */
3807 enable = false;
3808
Jon Ashburn23d36b12016-02-02 17:47:28 -07003809 // if no enable_environment variable is specified, this implicit
3810 // layer
Jon Ashburn075ce432015-12-17 17:38:24 -07003811 // should always be enabled. Otherwise check if the variable is set
3812 if (prop->enable_env_var.name[0] == 0) {
3813 enable = true;
3814 } else {
Mark Young0ad83132016-06-30 13:02:42 -06003815 env_value = loader_getenv(prop->enable_env_var.name, inst);
Jon Ashburn075ce432015-12-17 17:38:24 -07003816 if (env_value && !strcmp(prop->enable_env_var.value, env_value))
3817 enable = true;
Mark Young0ad83132016-06-30 13:02:42 -06003818 loader_free_getenv(env_value, inst);
Jon Ashburn075ce432015-12-17 17:38:24 -07003819 }
3820
3821 // disable_environment has priority, i.e. if both enable and disable
Jon Ashburn23d36b12016-02-02 17:47:28 -07003822 // environment variables are set, the layer is disabled. Implicit
3823 // layers
Jon Ashburn075ce432015-12-17 17:38:24 -07003824 // are required to have a disable_environment variables
Mark Young0ad83132016-06-30 13:02:42 -06003825 env_value = loader_getenv(prop->disable_env_var.name, inst);
3826 if (env_value) {
Jon Ashburn075ce432015-12-17 17:38:24 -07003827 enable = false;
Mark Young0ad83132016-06-30 13:02:42 -06003828 }
3829 loader_free_getenv(env_value, inst);
Jon Ashburn075ce432015-12-17 17:38:24 -07003830
Mark Young0ad83132016-06-30 13:02:42 -06003831 if (enable) {
Jon Ashburn075ce432015-12-17 17:38:24 -07003832 loader_add_to_layer_list(inst, list, 1, prop);
Mark Young0ad83132016-06-30 13:02:42 -06003833 }
Jon Ashburn0c26e712015-07-02 16:10:32 -06003834 }
3835 }
Jon Ashburn0c26e712015-07-02 16:10:32 -06003836}
3837
3838/**
3839 * Get the layer name(s) from the env_name environment variable. If layer
Jon Ashburnbd332cc2015-07-07 10:27:45 -06003840 * is found in search_list then add it to layer_list. But only add it to
3841 * layer_list if type matches.
Jon Ashburn0c26e712015-07-02 16:10:32 -06003842 */
Jon Ashburn491cd042016-05-16 14:01:18 -06003843static void loader_add_layer_env(struct loader_instance *inst,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003844 const enum layer_type type,
3845 const char *env_name,
3846 struct loader_layer_list *layer_list,
3847 const struct loader_layer_list *search_list) {
Ian Elliott4470a302015-02-17 10:33:47 -07003848 char *layerEnv;
Jon Ashburneb6d5682015-07-02 14:10:53 -06003849 char *next, *name;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003850
Mark Young0ad83132016-06-30 13:02:42 -06003851 layerEnv = loader_getenv(env_name, inst);
Ian Elliott4470a302015-02-17 10:33:47 -07003852 if (layerEnv == NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003853 return;
Ian Elliott4470a302015-02-17 10:33:47 -07003854 }
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -06003855 name = loader_stack_alloc(strlen(layerEnv) + 1);
Jon Ashburneb6d5682015-07-02 14:10:53 -06003856 if (name == NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003857 return;
Ian Elliott4470a302015-02-17 10:33:47 -07003858 }
Jon Ashburneb6d5682015-07-02 14:10:53 -06003859 strcpy(name, layerEnv);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003860
Mark Young0ad83132016-06-30 13:02:42 -06003861 loader_free_getenv(layerEnv, inst);
Jon Ashburn38a497f2016-01-04 14:01:38 -07003862
Jon Ashburn23d36b12016-02-02 17:47:28 -07003863 while (name && *name) {
Jon Ashburneb6d5682015-07-02 14:10:53 -06003864 next = loader_get_next_path(name);
Jon Ashburn71483442016-02-11 18:59:43 -07003865 if (!strcmp(std_validation_str, name)) {
3866 /* add meta list of layers
3867 don't attempt to remove duplicate layers already added by app or
3868 env var
3869 */
3870 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
3871 "Expanding meta layer %s found in environment variable",
3872 std_validation_str);
Jon Ashburn491cd042016-05-16 14:01:18 -06003873 if (type == VK_LAYER_TYPE_INSTANCE_EXPLICIT)
3874 inst->activated_layers_are_std_val = true;
Jon Ashburn71483442016-02-11 18:59:43 -07003875 for (uint32_t i = 0; i < sizeof(std_validation_names) /
3876 sizeof(std_validation_names[0]);
3877 i++) {
3878 loader_find_layer_name_add_list(inst, std_validation_names[i],
3879 type, search_list, layer_list);
3880 }
3881 } else {
3882 loader_find_layer_name_add_list(inst, name, type, search_list,
3883 layer_list);
3884 }
Jon Ashburneb6d5682015-07-02 14:10:53 -06003885 name = next;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07003886 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003887
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003888 return;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003889}
3890
Jon Ashburn23d36b12016-02-02 17:47:28 -07003891VkResult
3892loader_enable_instance_layers(struct loader_instance *inst,
3893 const VkInstanceCreateInfo *pCreateInfo,
3894 const struct loader_layer_list *instance_layers) {
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06003895 VkResult err;
3896
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06003897 assert(inst && "Cannot have null instance");
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003898
Jon Ashburne39a4f82015-08-28 13:38:21 -06003899 if (!loader_init_layer_list(inst, &inst->activated_layer_list)) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003900 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07003901 "loader_enable_instance_layers: Failed to initialize"
3902 " the layer list");
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06003903 return VK_ERROR_OUT_OF_HOST_MEMORY;
Jon Ashburnbd6c4882015-07-02 12:59:25 -06003904 }
3905
Jon Ashburn0c26e712015-07-02 16:10:32 -06003906 /* Add any implicit layers first */
Jon Ashburn23d36b12016-02-02 17:47:28 -07003907 loader_add_layer_implicit(inst, VK_LAYER_TYPE_INSTANCE_IMPLICIT,
3908 &inst->activated_layer_list, instance_layers);
Jon Ashburn0c26e712015-07-02 16:10:32 -06003909
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003910 /* Add any layers specified via environment variable next */
Jon Ashburn23d36b12016-02-02 17:47:28 -07003911 loader_add_layer_env(inst, VK_LAYER_TYPE_INSTANCE_EXPLICIT,
3912 "VK_INSTANCE_LAYERS", &inst->activated_layer_list,
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003913 instance_layers);
Jon Ashburnbd6c4882015-07-02 12:59:25 -06003914
3915 /* Add layers specified by the application */
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06003916 err = loader_add_layer_names_to_list(
Jon Ashburn23d36b12016-02-02 17:47:28 -07003917 inst, &inst->activated_layer_list, pCreateInfo->enabledLayerCount,
3918 pCreateInfo->ppEnabledLayerNames, instance_layers);
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06003919
3920 return err;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003921}
3922
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003923/*
3924 * Given the list of layers to activate in the loader_instance
3925 * structure. This function will add a VkLayerInstanceCreateInfo
3926 * structure to the VkInstanceCreateInfo.pNext pointer.
3927 * Each activated layer will have it's own VkLayerInstanceLink
3928 * structure that tells the layer what Get*ProcAddr to call to
3929 * get function pointers to the next layer down.
3930 * Once the chain info has been created this function will
3931 * execute the CreateInstance call chain. Each layer will
3932 * then have an opportunity in it's CreateInstance function
3933 * to setup it's dispatch table when the lower layer returns
3934 * successfully.
3935 * Each layer can wrap or not-wrap the returned VkInstance object
3936 * as it sees fit.
3937 * The instance chain is terminated by a loader function
3938 * that will call CreateInstance on all available ICD's and
3939 * cache those VkInstance objects for future use.
3940 */
3941VkResult loader_create_instance_chain(const VkInstanceCreateInfo *pCreateInfo,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003942 const VkAllocationCallbacks *pAllocator,
Jon Ashburn373c1802016-01-20 08:08:25 -07003943 struct loader_instance *inst,
Jon Ashburn6e0a2132016-02-03 12:37:30 -07003944 VkInstance *created_instance) {
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003945 uint32_t activated_layers = 0;
3946 VkLayerInstanceCreateInfo chain_info;
3947 VkLayerInstanceLink *layer_instance_link_info = NULL;
3948 VkInstanceCreateInfo loader_create_info;
3949 VkResult res;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003950
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003951 PFN_vkGetInstanceProcAddr nextGIPA = loader_gpa_instance_internal;
3952 PFN_vkGetInstanceProcAddr fpGIPA = loader_gpa_instance_internal;
Jon Ashburn27cd5842015-05-12 17:26:48 -06003953
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003954 memcpy(&loader_create_info, pCreateInfo, sizeof(VkInstanceCreateInfo));
Jon Ashburn27cd5842015-05-12 17:26:48 -06003955
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003956 if (inst->activated_layer_list.count > 0) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003957
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003958 chain_info.u.pLayerInfo = NULL;
3959 chain_info.pNext = pCreateInfo->pNext;
3960 chain_info.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
3961 chain_info.function = VK_LAYER_LINK_INFO;
3962 loader_create_info.pNext = &chain_info;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003963
Jon Ashburn23d36b12016-02-02 17:47:28 -07003964 layer_instance_link_info = loader_stack_alloc(
3965 sizeof(VkLayerInstanceLink) * inst->activated_layer_list.count);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003966 if (!layer_instance_link_info) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003967 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07003968 "loader_create_instance_chain: Failed to alloc Instance"
3969 " objects for layer");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003970 return VK_ERROR_OUT_OF_HOST_MEMORY;
Jon Ashburn27cd5842015-05-12 17:26:48 -06003971 }
3972
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003973 /* Create instance chain of enabled layers */
3974 for (int32_t i = inst->activated_layer_list.count - 1; i >= 0; i--) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003975 struct loader_layer_properties *layer_prop =
3976 &inst->activated_layer_list.list[i];
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003977 loader_platform_dl_handle lib_handle;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06003978
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06003979 lib_handle = loader_open_layer_lib(inst, "instance", layer_prop);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003980 if (!lib_handle)
Courtney Goeltzenleuchter524b7e32016-01-14 16:06:06 -07003981 continue;
Jon Ashburn23d36b12016-02-02 17:47:28 -07003982 if ((fpGIPA = layer_prop->functions.get_instance_proc_addr) ==
3983 NULL) {
Jamie Madillc3d3f072016-12-14 17:21:43 -05003984 if (strlen(layer_prop->functions.str_gipa) == 0) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003985 fpGIPA = (PFN_vkGetInstanceProcAddr)
3986 loader_platform_get_proc_address(
3987 lib_handle, "vkGetInstanceProcAddr");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003988 layer_prop->functions.get_instance_proc_addr = fpGIPA;
3989 } else
Jon Ashburn23d36b12016-02-02 17:47:28 -07003990 fpGIPA = (PFN_vkGetInstanceProcAddr)
3991 loader_platform_get_proc_address(
3992 lib_handle, layer_prop->functions.str_gipa);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003993 if (!fpGIPA) {
Mark Youngb6399312017-01-10 14:22:15 -07003994 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3995 "loader_create_instance_chain: Failed to find "
3996 "\'vkGetInstanceProcAddr\' in layer %s",
3997 layer_prop->lib_name);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003998 continue;
3999 }
4000 }
4001
Jon Ashburn23d36b12016-02-02 17:47:28 -07004002 layer_instance_link_info[activated_layers].pNext =
4003 chain_info.u.pLayerInfo;
4004 layer_instance_link_info[activated_layers]
4005 .pfnNextGetInstanceProcAddr = nextGIPA;
4006 chain_info.u.pLayerInfo =
4007 &layer_instance_link_info[activated_layers];
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004008 nextGIPA = fpGIPA;
4009
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07004010 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -07004011 "Insert instance layer %s (%s)",
4012 layer_prop->info.layerName, layer_prop->lib_name);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004013
4014 activated_layers++;
4015 }
Jon Ashburn27cd5842015-05-12 17:26:48 -06004016 }
4017
Jon Ashburn23d36b12016-02-02 17:47:28 -07004018 PFN_vkCreateInstance fpCreateInstance =
Jon Ashburn6e0a2132016-02-03 12:37:30 -07004019 (PFN_vkCreateInstance)nextGIPA(*created_instance, "vkCreateInstance");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004020 if (fpCreateInstance) {
Jon Ashburnc3c58772016-03-29 11:16:01 -06004021 VkLayerInstanceCreateInfo create_info_disp;
4022
Jon Ashburncc407a22016-04-15 09:25:03 -06004023 create_info_disp.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
Jon Ashburned8f2312016-03-31 10:52:22 -06004024 create_info_disp.function = VK_LOADER_DATA_CALLBACK;
Jon Ashburnc3c58772016-03-29 11:16:01 -06004025
4026 create_info_disp.u.pfnSetInstanceLoaderData = vkSetInstanceDispatch;
4027
4028 create_info_disp.pNext = loader_create_info.pNext;
4029 loader_create_info.pNext = &create_info_disp;
Jon Ashburnf2b4e382016-02-10 20:50:19 -07004030 res =
4031 fpCreateInstance(&loader_create_info, pAllocator, created_instance);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004032 } else {
Mark Youngb6399312017-01-10 14:22:15 -07004033 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4034 "loader_create_instance_chain: Failed to find "
4035 "\'vkCreateInstance\'");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004036 // Couldn't find CreateInstance function!
4037 res = VK_ERROR_INITIALIZATION_FAILED;
4038 }
4039
4040 if (res != VK_SUCCESS) {
4041 // TODO: Need to clean up here
4042 } else {
Jon Ashburn23d36b12016-02-02 17:47:28 -07004043 loader_init_instance_core_dispatch_table(inst->disp, nextGIPA,
Jon Ashburn6e0a2132016-02-03 12:37:30 -07004044 *created_instance);
Jon Ashburn4e8c4162016-03-08 15:21:30 -07004045 inst->instance = *created_instance;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004046 }
4047
4048 return res;
Jon Ashburn27cd5842015-05-12 17:26:48 -06004049}
4050
Jon Ashburn23d36b12016-02-02 17:47:28 -07004051void loader_activate_instance_layer_extensions(struct loader_instance *inst,
4052 VkInstance created_inst) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06004053
Jon Ashburn23d36b12016-02-02 17:47:28 -07004054 loader_init_instance_extension_dispatch_table(
4055 inst->disp, inst->disp->GetInstanceProcAddr, created_inst);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06004056}
4057
Jon Ashburn1530c342016-02-26 13:14:27 -07004058VkResult
Jon Ashburncc407a22016-04-15 09:25:03 -06004059loader_create_device_chain(const struct loader_physical_device_tramp *pd,
4060 const VkDeviceCreateInfo *pCreateInfo,
4061 const VkAllocationCallbacks *pAllocator,
4062 const struct loader_instance *inst,
4063 struct loader_device *dev) {
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004064 uint32_t activated_layers = 0;
4065 VkLayerDeviceLink *layer_device_link_info;
4066 VkLayerDeviceCreateInfo chain_info;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004067 VkDeviceCreateInfo loader_create_info;
4068 VkResult res;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06004069
Piers Daniell295fe402016-03-29 11:51:11 -06004070 PFN_vkGetDeviceProcAddr fpGDPA, nextGDPA = loader_gpa_device_internal;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004071 PFN_vkGetInstanceProcAddr fpGIPA, nextGIPA = loader_gpa_instance_internal;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06004072
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004073 memcpy(&loader_create_info, pCreateInfo, sizeof(VkDeviceCreateInfo));
4074
Jon Ashburn23d36b12016-02-02 17:47:28 -07004075 layer_device_link_info = loader_stack_alloc(
4076 sizeof(VkLayerDeviceLink) * dev->activated_layer_list.count);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004077 if (!layer_device_link_info) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07004078 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07004079 "loader_create_device_chain: Failed to alloc Device objects"
4080 " for layer. Skipping Layer.");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004081 return VK_ERROR_OUT_OF_HOST_MEMORY;
David Pinedoa0a8a242015-06-24 15:29:18 -06004082 }
Jon Ashburn94e70492015-06-10 10:13:10 -06004083
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004084 if (dev->activated_layer_list.count > 0) {
Jon Ashburn72690f22016-03-29 12:52:13 -06004085 chain_info.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO;
4086 chain_info.function = VK_LAYER_LINK_INFO;
4087 chain_info.u.pLayerInfo = NULL;
4088 chain_info.pNext = pCreateInfo->pNext;
4089 loader_create_info.pNext = &chain_info;
4090
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004091 /* Create instance chain of enabled layers */
4092 for (int32_t i = dev->activated_layer_list.count - 1; i >= 0; i--) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07004093 struct loader_layer_properties *layer_prop =
4094 &dev->activated_layer_list.list[i];
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004095 loader_platform_dl_handle lib_handle;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06004096
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004097 lib_handle = loader_open_layer_lib(inst, "device", layer_prop);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004098 if (!lib_handle)
Courtney Goeltzenleuchter524b7e32016-01-14 16:06:06 -07004099 continue;
Jon Ashburn23d36b12016-02-02 17:47:28 -07004100 if ((fpGIPA = layer_prop->functions.get_instance_proc_addr) ==
4101 NULL) {
Jamie Madillc3d3f072016-12-14 17:21:43 -05004102 if (strlen(layer_prop->functions.str_gipa) == 0) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07004103 fpGIPA = (PFN_vkGetInstanceProcAddr)
4104 loader_platform_get_proc_address(
4105 lib_handle, "vkGetInstanceProcAddr");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004106 layer_prop->functions.get_instance_proc_addr = fpGIPA;
4107 } else
Jon Ashburn23d36b12016-02-02 17:47:28 -07004108 fpGIPA = (PFN_vkGetInstanceProcAddr)
4109 loader_platform_get_proc_address(
4110 lib_handle, layer_prop->functions.str_gipa);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004111 if (!fpGIPA) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07004112 loader_log(
4113 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07004114 "loader_create_device_chain: Failed to find "
4115 "\'vkGetInstanceProcAddr\' in layer %s. Skipping"
4116 " layer.",
Jon Ashburn23d36b12016-02-02 17:47:28 -07004117 layer_prop->lib_name);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004118 continue;
4119 }
Jon Ashburn21c21ee2015-09-09 11:29:24 -06004120 }
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004121 if ((fpGDPA = layer_prop->functions.get_device_proc_addr) == NULL) {
Jamie Madillc3d3f072016-12-14 17:21:43 -05004122 if (strlen(layer_prop->functions.str_gdpa) == 0) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07004123 fpGDPA = (PFN_vkGetDeviceProcAddr)
4124 loader_platform_get_proc_address(lib_handle,
4125 "vkGetDeviceProcAddr");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004126 layer_prop->functions.get_device_proc_addr = fpGDPA;
4127 } else
Jon Ashburn23d36b12016-02-02 17:47:28 -07004128 fpGDPA = (PFN_vkGetDeviceProcAddr)
4129 loader_platform_get_proc_address(
4130 lib_handle, layer_prop->functions.str_gdpa);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004131 if (!fpGDPA) {
Jon Ashburnc0dc07c2016-05-16 17:35:43 -06004132 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -07004133 "Failed to find vkGetDeviceProcAddr in layer %s",
4134 layer_prop->lib_name);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004135 continue;
4136 }
4137 }
4138
Jon Ashburn23d36b12016-02-02 17:47:28 -07004139 layer_device_link_info[activated_layers].pNext =
4140 chain_info.u.pLayerInfo;
4141 layer_device_link_info[activated_layers]
4142 .pfnNextGetInstanceProcAddr = nextGIPA;
4143 layer_device_link_info[activated_layers].pfnNextGetDeviceProcAddr =
4144 nextGDPA;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004145 chain_info.u.pLayerInfo = &layer_device_link_info[activated_layers];
4146 nextGIPA = fpGIPA;
4147 nextGDPA = fpGDPA;
4148
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07004149 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004150 "Insert device layer %s (%s)",
Jon Ashburn23d36b12016-02-02 17:47:28 -07004151 layer_prop->info.layerName, layer_prop->lib_name);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004152
4153 activated_layers++;
Jon Ashburn94e70492015-06-10 10:13:10 -06004154 }
Jon Ashburn94e70492015-06-10 10:13:10 -06004155 }
4156
Jon Ashburncc407a22016-04-15 09:25:03 -06004157 VkDevice created_device = (VkDevice)dev;
Jon Ashburn23d36b12016-02-02 17:47:28 -07004158 PFN_vkCreateDevice fpCreateDevice =
Jon Ashburn4e8c4162016-03-08 15:21:30 -07004159 (PFN_vkCreateDevice)nextGIPA(inst->instance, "vkCreateDevice");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004160 if (fpCreateDevice) {
Jon Ashburned8f2312016-03-31 10:52:22 -06004161 VkLayerDeviceCreateInfo create_info_disp;
4162
Jon Ashburncc407a22016-04-15 09:25:03 -06004163 create_info_disp.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO;
Jon Ashburned8f2312016-03-31 10:52:22 -06004164 create_info_disp.function = VK_LOADER_DATA_CALLBACK;
4165
4166 create_info_disp.u.pfnSetDeviceLoaderData = vkSetDeviceDispatch;
4167
4168 create_info_disp.pNext = loader_create_info.pNext;
4169 loader_create_info.pNext = &create_info_disp;
Jon Ashburn014438f2016-03-01 19:51:07 -07004170 res = fpCreateDevice(pd->phys_dev, &loader_create_info, pAllocator,
Jon Ashburn72690f22016-03-29 12:52:13 -06004171 &created_device);
Piers Daniellefbbfc12016-04-05 17:28:06 -06004172 if (res != VK_SUCCESS) {
4173 return res;
4174 }
Mark Young65cb3662016-11-07 13:27:02 -07004175 dev->chain_device = created_device;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004176 } else {
Mark Youngb6399312017-01-10 14:22:15 -07004177 loader_log(
4178 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4179 "loader_create_device_chain: Failed to find \'vkCreateDevice\' "
4180 "in layer %s");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004181 // Couldn't find CreateDevice function!
4182 return VK_ERROR_INITIALIZATION_FAILED;
4183 }
Jon Ashburn94e70492015-06-10 10:13:10 -06004184
Mark Young65cb3662016-11-07 13:27:02 -07004185 // Initialize device dispatch table
Jon Ashburn23d36b12016-02-02 17:47:28 -07004186 loader_init_device_dispatch_table(&dev->loader_dispatch, nextGDPA,
Mark Young65cb3662016-11-07 13:27:02 -07004187 dev->chain_device);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004188
4189 return res;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06004190}
Jon Ashburnd38bfb12014-10-14 19:15:22 -06004191
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004192VkResult loader_validate_layers(const struct loader_instance *inst,
4193 const uint32_t layer_count,
Jon Ashburn23d36b12016-02-02 17:47:28 -07004194 const char *const *ppEnabledLayerNames,
4195 const struct loader_layer_list *list) {
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06004196 struct loader_layer_properties *prop;
4197
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004198 for (uint32_t i = 0; i < layer_count; i++) {
Jon Ashburnf2b4e382016-02-10 20:50:19 -07004199 VkStringErrorFlags result =
4200 vk_string_validate(MaxLoaderStringLength, ppEnabledLayerNames[i]);
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004201 if (result != VK_STRING_ERROR_NONE) {
4202 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07004203 "loader_validate_layers: Device ppEnabledLayerNames "
4204 " contains string that is too long or is badly formed");
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004205 return VK_ERROR_LAYER_NOT_PRESENT;
4206 }
4207
Jon Ashburn23d36b12016-02-02 17:47:28 -07004208 prop = loader_get_layer_property(ppEnabledLayerNames[i], list);
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06004209 if (!prop) {
Mark Youngb6399312017-01-10 14:22:15 -07004210 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4211 "loader_validate_layers: Layer %d does not exist in "
4212 "the list of available layers",
4213 i);
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06004214 return VK_ERROR_LAYER_NOT_PRESENT;
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06004215 }
4216 }
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06004217 return VK_SUCCESS;
4218}
4219
4220VkResult loader_validate_instance_extensions(
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004221 const struct loader_instance *inst,
Jon Ashburn23d36b12016-02-02 17:47:28 -07004222 const struct loader_extension_list *icd_exts,
Michael Jurka5c16c002016-12-19 16:31:43 +01004223 const struct loader_layer_list *instance_layers,
Jon Ashburn23d36b12016-02-02 17:47:28 -07004224 const VkInstanceCreateInfo *pCreateInfo) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004225
Jon Ashburn5c042ea2015-08-04 11:14:18 -06004226 VkExtensionProperties *extension_prop;
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004227 struct loader_layer_properties *layer_prop;
4228
Jon Ashburnf19916e2016-01-11 13:12:43 -07004229 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
Jon Ashburnf2b4e382016-02-10 20:50:19 -07004230 VkStringErrorFlags result = vk_string_validate(
4231 MaxLoaderStringLength, pCreateInfo->ppEnabledExtensionNames[i]);
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004232 if (result != VK_STRING_ERROR_NONE) {
4233 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07004234 "loader_validate_instance_extensions: Instance "
4235 "ppEnabledExtensionNames contains "
Jon Ashburnf2b4e382016-02-10 20:50:19 -07004236 "string that is too long or is badly formed");
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004237 return VK_ERROR_EXTENSION_NOT_PRESENT;
4238 }
4239
Lenny Komow4053b812016-12-29 16:27:28 -07004240 // See if the extension is in the list of supported extensions
4241 bool found = false;
4242 for (uint32_t j = 0; LOADER_INSTANCE_EXTENSIONS[j] != NULL; j++) {
4243 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i],
4244 LOADER_INSTANCE_EXTENSIONS[j]) == 0) {
4245 found = true;
4246 break;
4247 }
4248 }
4249
4250 // If it isn't in the list, return an error
4251 if (!found) {
Mark Youngb6399312017-01-10 14:22:15 -07004252 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4253 "loader_validate_instance_extensions: Extension %d "
4254 "not found in list of available extensions.",
4255 i);
Lenny Komow4053b812016-12-29 16:27:28 -07004256 return VK_ERROR_EXTENSION_NOT_PRESENT;
4257 }
4258
Jon Ashburn23d36b12016-02-02 17:47:28 -07004259 extension_prop = get_extension_property(
4260 pCreateInfo->ppEnabledExtensionNames[i], icd_exts);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004261
4262 if (extension_prop) {
4263 continue;
4264 }
4265
4266 extension_prop = NULL;
4267
4268 /* Not in global list, search layer extension lists */
Jon Ashburnf19916e2016-01-11 13:12:43 -07004269 for (uint32_t j = 0; j < pCreateInfo->enabledLayerCount; j++) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07004270 layer_prop = loader_get_layer_property(
Michael Jurka5c16c002016-12-19 16:31:43 +01004271 pCreateInfo->ppEnabledLayerNames[j], instance_layers);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004272 if (!layer_prop) {
Courtney Goeltzenleuchter6f5b00c2015-07-06 20:46:50 -06004273 /* Should NOT get here, loader_validate_layers
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004274 * should have already filtered this case out.
4275 */
4276 continue;
4277 }
4278
Jon Ashburn23d36b12016-02-02 17:47:28 -07004279 extension_prop =
4280 get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
4281 &layer_prop->instance_extension_list);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004282 if (extension_prop) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07004283 /* Found the extension in one of the layers enabled by the app.
4284 */
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004285 break;
4286 }
4287 }
4288
4289 if (!extension_prop) {
Mark Youngb6399312017-01-10 14:22:15 -07004290 // Didn't find extension name in any of the global layers, error out
4291 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4292 "loader_validate_instance_extensions: Extension %d "
4293 "not found in enabled layer list extensions.",
4294 i);
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06004295 return VK_ERROR_EXTENSION_NOT_PRESENT;
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004296 }
4297 }
4298 return VK_SUCCESS;
4299}
4300
4301VkResult loader_validate_device_extensions(
Jon Ashburn787eb252016-03-24 15:49:57 -06004302 struct loader_physical_device_tramp *phys_dev,
Jon Ashburn23d36b12016-02-02 17:47:28 -07004303 const struct loader_layer_list *activated_device_layers,
Jon Ashburn014438f2016-03-01 19:51:07 -07004304 const struct loader_extension_list *icd_exts,
Jon Ashburn23d36b12016-02-02 17:47:28 -07004305 const VkDeviceCreateInfo *pCreateInfo) {
Jon Ashburn5c042ea2015-08-04 11:14:18 -06004306 VkExtensionProperties *extension_prop;
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004307 struct loader_layer_properties *layer_prop;
4308
Jon Ashburnf19916e2016-01-11 13:12:43 -07004309 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004310
Jon Ashburnf2b4e382016-02-10 20:50:19 -07004311 VkStringErrorFlags result = vk_string_validate(
4312 MaxLoaderStringLength, pCreateInfo->ppEnabledExtensionNames[i]);
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004313 if (result != VK_STRING_ERROR_NONE) {
Jon Ashburncc407a22016-04-15 09:25:03 -06004314 loader_log(phys_dev->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT,
Mark Youngb6399312017-01-10 14:22:15 -07004315 0, "loader_validate_device_extensions: Device "
4316 "ppEnabledExtensionNames contains "
Jon Ashburncc407a22016-04-15 09:25:03 -06004317 "string that is too long or is badly formed");
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004318 return VK_ERROR_EXTENSION_NOT_PRESENT;
4319 }
4320
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004321 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
Jon Ashburn014438f2016-03-01 19:51:07 -07004322 extension_prop = get_extension_property(extension_name, icd_exts);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004323
4324 if (extension_prop) {
4325 continue;
4326 }
4327
Mark Youngb6399312017-01-10 14:22:15 -07004328 // Not in global list, search activated layer extension lists
Jon Ashburn471f44c2016-01-13 12:51:43 -07004329 for (uint32_t j = 0; j < activated_device_layers->count; j++) {
4330 layer_prop = &activated_device_layers->list[j];
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004331
Jon Ashburn23d36b12016-02-02 17:47:28 -07004332 extension_prop = get_dev_extension_property(
4333 extension_name, &layer_prop->device_extension_list);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004334 if (extension_prop) {
Mark Youngb6399312017-01-10 14:22:15 -07004335 // Found the extension in one of the layers enabled by the app.
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004336 break;
4337 }
4338 }
4339
4340 if (!extension_prop) {
Mark Youngb6399312017-01-10 14:22:15 -07004341 // Didn't find extension name in any of the device layers, error out
4342 loader_log(phys_dev->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT,
4343 0, "loader_validate_device_extensions: Extension %d "
4344 "not found in enabled layer list extensions.",
4345 i);
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06004346 return VK_ERROR_EXTENSION_NOT_PRESENT;
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004347 }
4348 }
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06004349 return VK_SUCCESS;
4350}
4351
Mark Youngb6399312017-01-10 14:22:15 -07004352// Terminator functions for the Instance chain
4353// All named terminator_<Vulakn API name>
Mark Young0ad83132016-06-30 13:02:42 -06004354VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateInstance(
4355 const VkInstanceCreateInfo *pCreateInfo,
4356 const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) {
Mark Young0153e0b2016-11-03 14:27:13 -06004357 struct loader_icd_term *icd_term;
Jon Ashburn5c042ea2015-08-04 11:14:18 -06004358 VkExtensionProperties *prop;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06004359 char **filtered_extension_names = NULL;
4360 VkInstanceCreateInfo icd_create_info;
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06004361 VkResult res = VK_SUCCESS;
Mark Young8b4edb52016-11-11 09:31:55 -07004362 bool one_icd_successful = false;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07004363
Jon Ashburncc407a22016-04-15 09:25:03 -06004364 struct loader_instance *ptr_instance = (struct loader_instance *)*pInstance;
Tony Barbour3c78ff42015-12-04 13:24:39 -07004365 memcpy(&icd_create_info, pCreateInfo, sizeof(icd_create_info));
4366
Jon Ashburnf19916e2016-01-11 13:12:43 -07004367 icd_create_info.enabledLayerCount = 0;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06004368 icd_create_info.ppEnabledLayerNames = NULL;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06004369
Mark Youngb6399312017-01-10 14:22:15 -07004370 // NOTE: Need to filter the extensions to only those supported by the ICD.
4371 // No ICD will advertise support for layers. An ICD library could
4372 // support a layer, but it would be independent of the actual ICD,
4373 // just in the same library.
Jon Ashburn23d36b12016-02-02 17:47:28 -07004374 filtered_extension_names =
4375 loader_stack_alloc(pCreateInfo->enabledExtensionCount * sizeof(char *));
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06004376 if (!filtered_extension_names) {
Mark Youngb6399312017-01-10 14:22:15 -07004377 loader_log(ptr_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4378 "terminator_CreateInstance: Failed create extension name "
4379 "array for %d extensions",
4380 pCreateInfo->enabledExtensionCount);
Mark Young3a587792016-08-19 15:25:08 -06004381 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4382 goto out;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06004383 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07004384 icd_create_info.ppEnabledExtensionNames =
4385 (const char *const *)filtered_extension_names;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06004386
Mark Young0153e0b2016-11-03 14:27:13 -06004387 for (uint32_t i = 0; i < ptr_instance->icd_tramp_list.count; i++) {
4388 icd_term = loader_icd_add(
4389 ptr_instance, &ptr_instance->icd_tramp_list.scanned_list[i]);
4390 if (NULL == icd_term) {
Mark Youngb6399312017-01-10 14:22:15 -07004391 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT,
4392 0,
4393 "terminator_CreateInstance: Failed to add ICD %d to ICD "
4394 "trampoline list.",
4395 i);
Mark Young3a587792016-08-19 15:25:08 -06004396 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4397 goto out;
Mark Young0ad83132016-06-30 13:02:42 -06004398 }
Mark Young6267ae62017-01-12 12:27:19 -07004399
Mark Young0ad83132016-06-30 13:02:42 -06004400 icd_create_info.enabledExtensionCount = 0;
4401 struct loader_extension_list icd_exts;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06004402
Mark Young0ad83132016-06-30 13:02:42 -06004403 loader_log(ptr_instance, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
4404 "Build ICD instance extension list");
4405 // traverse scanned icd list adding non-duplicate extensions to the
4406 // list
Mark Young3a587792016-08-19 15:25:08 -06004407 res = loader_init_generic_list(ptr_instance,
Mark Young0153e0b2016-11-03 14:27:13 -06004408 (struct loader_generic_list *)&icd_exts,
4409 sizeof(VkExtensionProperties));
Mark Young3a587792016-08-19 15:25:08 -06004410 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
4411 // If out of memory, bail immediately.
4412 goto out;
4413 } else if (VK_SUCCESS != res) {
Mark Young7e471292016-09-06 09:53:45 -06004414 // Something bad happened with this ICD, so free it and try the
4415 // next.
Mark Young0153e0b2016-11-03 14:27:13 -06004416 ptr_instance->icd_terms = icd_term->next;
4417 icd_term->next = NULL;
4418 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
Mark Young3a587792016-08-19 15:25:08 -06004419 continue;
4420 }
4421
4422 res = loader_add_instance_extensions(
Mark Young0ad83132016-06-30 13:02:42 -06004423 ptr_instance,
Mark Young0153e0b2016-11-03 14:27:13 -06004424 icd_term->scanned_icd->EnumerateInstanceExtensionProperties,
4425 icd_term->scanned_icd->lib_name, &icd_exts);
Mark Youngdb13a2a2016-09-06 13:53:03 -06004426 if (VK_SUCCESS != res) {
Mark Young0153e0b2016-11-03 14:27:13 -06004427 loader_destroy_generic_list(
4428 ptr_instance, (struct loader_generic_list *)&icd_exts);
Mark Youngdb13a2a2016-09-06 13:53:03 -06004429 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
4430 // If out of memory, bail immediately.
4431 goto out;
4432 } else {
4433 // Something bad happened with this ICD, so free it and try
4434 // the next.
Mark Young0153e0b2016-11-03 14:27:13 -06004435 ptr_instance->icd_terms = icd_term->next;
4436 icd_term->next = NULL;
4437 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
Mark Youngdb13a2a2016-09-06 13:53:03 -06004438 continue;
4439 }
Mark Young3a587792016-08-19 15:25:08 -06004440 }
Courtney Goeltzenleuchter36eeb742015-12-21 16:41:47 -07004441
Mark Young0ad83132016-06-30 13:02:42 -06004442 for (uint32_t j = 0; j < pCreateInfo->enabledExtensionCount; j++) {
4443 prop = get_extension_property(
4444 pCreateInfo->ppEnabledExtensionNames[j], &icd_exts);
4445 if (prop) {
4446 filtered_extension_names[icd_create_info
4447 .enabledExtensionCount] =
4448 (char *)pCreateInfo->ppEnabledExtensionNames[j];
4449 icd_create_info.enabledExtensionCount++;
Jon Ashburn46888392015-01-29 15:45:51 -07004450 }
4451 }
Mark Young0ad83132016-06-30 13:02:42 -06004452
4453 loader_destroy_generic_list(ptr_instance,
4454 (struct loader_generic_list *)&icd_exts);
4455
Mark Young8b4edb52016-11-11 09:31:55 -07004456 VkResult icd_result =
4457 ptr_instance->icd_tramp_list.scanned_list[i].CreateInstance(
4458 &icd_create_info, pAllocator, &(icd_term->instance));
4459 if (VK_ERROR_OUT_OF_HOST_MEMORY == icd_result) {
Mark Young3a587792016-08-19 15:25:08 -06004460 // If out of memory, bail immediately.
Mark Young8b4edb52016-11-11 09:31:55 -07004461 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young3a587792016-08-19 15:25:08 -06004462 goto out;
Mark Young8b4edb52016-11-11 09:31:55 -07004463 } else if (VK_SUCCESS != icd_result) {
Mark Young3a587792016-08-19 15:25:08 -06004464 loader_log(ptr_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07004465 "terminator_CreateInstance: Failed to CreateInstance in "
4466 "ICD %d. Skipping ICD.",
4467 i);
Mark Young0153e0b2016-11-03 14:27:13 -06004468 ptr_instance->icd_terms = icd_term->next;
4469 icd_term->next = NULL;
4470 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
Mark Young3a587792016-08-19 15:25:08 -06004471 continue;
4472 }
Mark Young0ad83132016-06-30 13:02:42 -06004473
Mark Young0153e0b2016-11-03 14:27:13 -06004474 if (!loader_icd_init_entrys(icd_term, icd_term->instance,
4475 ptr_instance->icd_tramp_list.scanned_list[i]
4476 .GetInstanceProcAddr)) {
Mark Youngb6399312017-01-10 14:22:15 -07004477 loader_log(
4478 ptr_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
4479 "terminator_CreateInstance: Failed to CreateInstance and find "
4480 "entrypoints with ICD. Skipping ICD.");
Mark Young3a587792016-08-19 15:25:08 -06004481 continue;
Mark Young0ad83132016-06-30 13:02:42 -06004482 }
Mark Young8b4edb52016-11-11 09:31:55 -07004483
4484 // If we made it this far, at least one ICD was successful
4485 one_icd_successful = true;
Jon Ashburn46888392015-01-29 15:45:51 -07004486 }
Jon Ashburn1beab2d2015-01-26 14:51:40 -07004487
Mark Young8b4edb52016-11-11 09:31:55 -07004488 // If no ICDs were added to instance list and res is unchanged
4489 // from it's initial value, the loader was unable to find
4490 // a suitable ICD.
4491 if (VK_SUCCESS == res &&
4492 (ptr_instance->icd_terms == NULL || !one_icd_successful)) {
Mark Young3a587792016-08-19 15:25:08 -06004493 res = VK_ERROR_INCOMPATIBLE_DRIVER;
4494 }
4495
4496out:
4497
4498 if (VK_SUCCESS != res) {
Mark Young0153e0b2016-11-03 14:27:13 -06004499 while (NULL != ptr_instance->icd_terms) {
4500 icd_term = ptr_instance->icd_terms;
4501 ptr_instance->icd_terms = icd_term->next;
4502 if (NULL != icd_term->instance) {
4503 icd_term->DestroyInstance(icd_term->instance, pAllocator);
Mark Young3a587792016-08-19 15:25:08 -06004504 }
Mark Young0153e0b2016-11-03 14:27:13 -06004505 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06004506 }
Ian Elliotteb450762015-02-05 15:19:15 -07004507 }
Jon Ashburn46888392015-01-29 15:45:51 -07004508
Mark Young3a587792016-08-19 15:25:08 -06004509 return res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07004510}
4511
Mark Young0ad83132016-06-30 13:02:42 -06004512VKAPI_ATTR void VKAPI_CALL terminator_DestroyInstance(
4513 VkInstance instance, const VkAllocationCallbacks *pAllocator) {
Courtney Goeltzenleuchterdeceded2015-06-08 15:04:02 -06004514 struct loader_instance *ptr_instance = loader_instance(instance);
Mark Young0153e0b2016-11-03 14:27:13 -06004515 struct loader_icd_term *icd_terms = ptr_instance->icd_terms;
4516 struct loader_icd_term *next_icd_term;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07004517
4518 // Remove this instance from the list of instances:
4519 struct loader_instance *prev = NULL;
4520 struct loader_instance *next = loader.instances;
4521 while (next != NULL) {
4522 if (next == ptr_instance) {
4523 // Remove this instance from the list:
4524 if (prev)
4525 prev->next = next->next;
Jon Ashburnc5c49602015-02-03 09:26:59 -07004526 else
4527 loader.instances = next->next;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07004528 break;
4529 }
4530 prev = next;
4531 next = next->next;
4532 }
Jon Ashburn1beab2d2015-01-26 14:51:40 -07004533
Mark Young0153e0b2016-11-03 14:27:13 -06004534 while (NULL != icd_terms) {
4535 if (icd_terms->instance) {
4536 icd_terms->DestroyInstance(icd_terms->instance, pAllocator);
Tony Barbourf20f87b2015-04-22 09:02:32 -06004537 }
Mark Young0153e0b2016-11-03 14:27:13 -06004538 next_icd_term = icd_terms->next;
4539 icd_terms->instance = VK_NULL_HANDLE;
4540 loader_icd_destroy(ptr_instance, icd_terms, pAllocator);
Jon Ashburna6fd2612015-06-16 14:43:19 -06004541
Mark Young0153e0b2016-11-03 14:27:13 -06004542 icd_terms = next_icd_term;
Jon Ashburn46888392015-01-29 15:45:51 -07004543 }
Jon Ashburn491cd042016-05-16 14:01:18 -06004544
Jon Ashburn23d36b12016-02-02 17:47:28 -07004545 loader_delete_layer_properties(ptr_instance,
4546 &ptr_instance->instance_layer_list);
Mark Young0153e0b2016-11-03 14:27:13 -06004547 loader_scanned_icd_clear(ptr_instance, &ptr_instance->icd_tramp_list);
Jon Ashburn23d36b12016-02-02 17:47:28 -07004548 loader_destroy_generic_list(
4549 ptr_instance, (struct loader_generic_list *)&ptr_instance->ext_list);
Lenny Komow8a1f8a52016-12-20 15:35:11 -07004550 if (ptr_instance->phys_devs_term) {
Mark Young0193d652016-12-28 16:10:10 -07004551 for (uint32_t i = 0; i < ptr_instance->phys_dev_count_term; i++) {
Lenny Komow8a1f8a52016-12-20 15:35:11 -07004552 loader_instance_heap_free(ptr_instance,
4553 ptr_instance->phys_devs_term[i]);
4554 }
Mark Young0ad83132016-06-30 13:02:42 -06004555 loader_instance_heap_free(ptr_instance, ptr_instance->phys_devs_term);
Lenny Komow8a1f8a52016-12-20 15:35:11 -07004556 }
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004557 loader_free_dev_ext_table(ptr_instance);
Jon Ashburn1beab2d2015-01-26 14:51:40 -07004558}
4559
Mark Young0ad83132016-06-30 13:02:42 -06004560VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDevice(
4561 VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo,
4562 const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
4563 VkResult res = VK_SUCCESS;
Mark Young0153e0b2016-11-03 14:27:13 -06004564 struct loader_physical_device_term *phys_dev_term;
4565 phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
4566 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Jon Ashburn24cd4be2015-11-01 14:04:06 -07004567
Jon Ashburncc407a22016-04-15 09:25:03 -06004568 struct loader_device *dev = (struct loader_device *)*pDevice;
Mark Young0153e0b2016-11-03 14:27:13 -06004569 PFN_vkCreateDevice fpCreateDevice = icd_term->CreateDevice;
Mark Young0ad83132016-06-30 13:02:42 -06004570 struct loader_extension_list icd_exts;
4571
Mark Young65cb3662016-11-07 13:27:02 -07004572 dev->phys_dev_term = phys_dev_term;
4573
Mark Young0ad83132016-06-30 13:02:42 -06004574 icd_exts.list = NULL;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06004575
Jon Ashburn1530c342016-02-26 13:14:27 -07004576 if (fpCreateDevice == NULL) {
Mark Young0153e0b2016-11-03 14:27:13 -06004577 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07004578 "terminator_CreateDevice: No vkCreateDevice command exposed "
4579 "by ICD %s",
Mark Young0153e0b2016-11-03 14:27:13 -06004580 icd_term->scanned_icd->lib_name);
Mark Young0ad83132016-06-30 13:02:42 -06004581 res = VK_ERROR_INITIALIZATION_FAILED;
4582 goto out;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06004583 }
4584
Jon Ashburn1530c342016-02-26 13:14:27 -07004585 VkDeviceCreateInfo localCreateInfo;
4586 memcpy(&localCreateInfo, pCreateInfo, sizeof(localCreateInfo));
Jon Ashburn1530c342016-02-26 13:14:27 -07004587
Mark Youngb6399312017-01-10 14:22:15 -07004588 // NOTE: Need to filter the extensions to only those supported by the ICD.
4589 // No ICD will advertise support for layers. An ICD library could
4590 // support a layer, but it would be independent of the actual ICD,
4591 // just in the same library.
Jon Ashburn1530c342016-02-26 13:14:27 -07004592 char **filtered_extension_names = NULL;
4593 filtered_extension_names =
4594 loader_stack_alloc(pCreateInfo->enabledExtensionCount * sizeof(char *));
Mark Youngb6399312017-01-10 14:22:15 -07004595 if (NULL == filtered_extension_names) {
4596 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4597 "terminator_CreateDevice: Failed to create extension name "
4598 "storage for %d extensions %d",
4599 pCreateInfo->enabledExtensionCount);
Jon Ashburn24cd4be2015-11-01 14:04:06 -07004600 return VK_ERROR_OUT_OF_HOST_MEMORY;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06004601 }
4602
Jon Ashburn1530c342016-02-26 13:14:27 -07004603 localCreateInfo.enabledLayerCount = 0;
4604 localCreateInfo.ppEnabledLayerNames = NULL;
4605
4606 localCreateInfo.enabledExtensionCount = 0;
4607 localCreateInfo.ppEnabledExtensionNames =
4608 (const char *const *)filtered_extension_names;
4609
Mark Youngb6399312017-01-10 14:22:15 -07004610 // Get the physical device (ICD) extensions
Mark Young0153e0b2016-11-03 14:27:13 -06004611 res = loader_init_generic_list(icd_term->this_instance,
4612 (struct loader_generic_list *)&icd_exts,
4613 sizeof(VkExtensionProperties));
Mark Young3a587792016-08-19 15:25:08 -06004614 if (VK_SUCCESS != res) {
Mark Young0ad83132016-06-30 13:02:42 -06004615 goto out;
Jon Ashburn014438f2016-03-01 19:51:07 -07004616 }
4617
4618 res = loader_add_device_extensions(
Mark Young0153e0b2016-11-03 14:27:13 -06004619 icd_term->this_instance, icd_term->EnumerateDeviceExtensionProperties,
4620 phys_dev_term->phys_dev, icd_term->scanned_icd->lib_name, &icd_exts);
Jon Ashburn014438f2016-03-01 19:51:07 -07004621 if (res != VK_SUCCESS) {
Mark Young0ad83132016-06-30 13:02:42 -06004622 goto out;
Jon Ashburn014438f2016-03-01 19:51:07 -07004623 }
4624
Jon Ashburn1530c342016-02-26 13:14:27 -07004625 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
4626 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
Jon Ashburn014438f2016-03-01 19:51:07 -07004627 VkExtensionProperties *prop =
4628 get_extension_property(extension_name, &icd_exts);
Jon Ashburn1530c342016-02-26 13:14:27 -07004629 if (prop) {
4630 filtered_extension_names[localCreateInfo.enabledExtensionCount] =
4631 (char *)extension_name;
4632 localCreateInfo.enabledExtensionCount++;
Mark Young9a3ddd42016-10-21 16:25:47 -06004633 } else {
Mark Young0153e0b2016-11-03 14:27:13 -06004634 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT,
4635 0, "vkCreateDevice extension %s not available for "
4636 "devices associated with ICD %s",
4637 extension_name, icd_term->scanned_icd->lib_name);
Jon Ashburn1530c342016-02-26 13:14:27 -07004638 }
4639 }
4640
Mark Young0153e0b2016-11-03 14:27:13 -06004641 res = fpCreateDevice(phys_dev_term->phys_dev, &localCreateInfo, pAllocator,
Mark Young65cb3662016-11-07 13:27:02 -07004642 &dev->icd_device);
Jon Ashburn1530c342016-02-26 13:14:27 -07004643 if (res != VK_SUCCESS) {
Mark Young0153e0b2016-11-03 14:27:13 -06004644 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07004645 "terminator_CreateDevice: Failed in ICD %s vkCreateDevice"
4646 "call",
Mark Young0153e0b2016-11-03 14:27:13 -06004647 icd_term->scanned_icd->lib_name);
Mark Young0ad83132016-06-30 13:02:42 -06004648 goto out;
Jon Ashburn1530c342016-02-26 13:14:27 -07004649 }
4650
Mark Young65cb3662016-11-07 13:27:02 -07004651 *pDevice = dev->icd_device;
Mark Young0153e0b2016-11-03 14:27:13 -06004652 loader_add_logical_device(icd_term->this_instance, icd_term, dev);
Jon Ashburn1530c342016-02-26 13:14:27 -07004653
4654 /* Init dispatch pointer in new device object */
4655 loader_init_dispatch(*pDevice, &dev->loader_dispatch);
4656
Mark Young0ad83132016-06-30 13:02:42 -06004657out:
4658 if (NULL != icd_exts.list) {
Mark Young0153e0b2016-11-03 14:27:13 -06004659 loader_destroy_generic_list(icd_term->this_instance,
Mark Young0ad83132016-06-30 13:02:42 -06004660 (struct loader_generic_list *)&icd_exts);
4661 }
4662
Jon Ashburn1530c342016-02-26 13:14:27 -07004663 return res;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06004664}
4665
Mark Young6267ae62017-01-12 12:27:19 -07004666VkResult setupLoaderTrampPhysDevs(VkInstance instance) {
Jon Ashburn24cd4be2015-11-01 14:04:06 -07004667 VkResult res = VK_SUCCESS;
Mark Young6267ae62017-01-12 12:27:19 -07004668 VkPhysicalDevice *local_phys_devs = NULL;
4669 struct loader_instance *inst;
4670 uint32_t total_count = 0;
4671 struct loader_physical_device_tramp **new_phys_devs = NULL;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07004672
Mark Young6267ae62017-01-12 12:27:19 -07004673 inst = loader_get_instance(instance);
4674 if (NULL == inst) {
4675 res = VK_ERROR_INITIALIZATION_FAILED;
4676 goto out;
4677 }
4678 total_count = inst->total_gpu_count;
4679
4680 // Create an array for the new physical devices, which will be stored
4681 // in the instance for the trampoline code.
4682 new_phys_devs =
4683 (struct loader_physical_device_tramp **)loader_instance_heap_alloc(
4684 inst,
4685 total_count * sizeof(struct loader_physical_device_tramp *),
4686 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
4687 if (NULL == new_phys_devs) {
Lenny Komow5e4ad102017-01-12 15:47:53 -07004688 loader_log(
4689 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4690 "setupLoaderTrampPhysDevs: Failed to allocate new physical device "
4691 "array of size %d",
4692 total_count);
Mark Youngd8382d72016-12-23 16:59:58 -07004693 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4694 goto out;
4695 }
Mark Young6267ae62017-01-12 12:27:19 -07004696 memset(new_phys_devs, 0,
4697 total_count * sizeof(struct loader_physical_device_tramp *));
Jon Ashburn014438f2016-03-01 19:51:07 -07004698
Mark Young6267ae62017-01-12 12:27:19 -07004699 // Create a temporary array (on the stack) to keep track of the
4700 // returned VkPhysicalDevice values.
4701 local_phys_devs =
4702 loader_stack_alloc(sizeof(VkPhysicalDevice) * total_count);
4703 if (NULL == local_phys_devs) {
4704 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4705 "setupLoaderTrampPhysDevs: Failed to allocate local "
4706 "physical device array of size %d",
4707 total_count);
4708 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4709 goto out;
4710 }
4711 memset(local_phys_devs, 0, sizeof(VkPhysicalDevice) * total_count);
4712
4713 res = inst->disp->EnumeratePhysicalDevices(instance, &total_count,
4714 local_phys_devs);
4715 if (VK_SUCCESS != res) {
4716 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4717 "setupLoaderTrampPhysDevs: Failed during dispatch call "
4718 "of \'vkEnumeratePhysicalDevices\' to lower layers or "
4719 "loader.");
4720 goto out;
4721 }
4722
4723 // Copy or create everything to fill the new array of physical devices
4724 for (uint32_t new_idx = 0; new_idx < total_count; new_idx++) {
4725
4726 // Check if this physical device is already in the old buffer
4727 for (uint32_t old_idx = 0;
4728 old_idx < inst->phys_dev_count_tramp;
4729 old_idx++) {
4730 if (local_phys_devs[new_idx] ==
4731 inst->phys_devs_tramp[old_idx]->phys_dev) {
4732 new_phys_devs[new_idx] = inst->phys_devs_tramp[old_idx];
4733 break;
4734 }
Mark Youngd8382d72016-12-23 16:59:58 -07004735 }
4736
Mark Young6267ae62017-01-12 12:27:19 -07004737 // If this physical device isn't in the old buffer, create it
4738 if (NULL == new_phys_devs[new_idx]) {
4739 new_phys_devs[new_idx] = (struct loader_physical_device_tramp *)
4740 loader_instance_heap_alloc(
4741 inst, sizeof(struct loader_physical_device_tramp),
4742 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
4743 if (NULL == new_phys_devs[new_idx]) {
Mark Youngb6399312017-01-10 14:22:15 -07004744 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young6267ae62017-01-12 12:27:19 -07004745 "setupLoaderTrampPhysDevs: Failed to allocate "
4746 "physical device trampoline object %d",
4747 new_idx);
4748 total_count = new_idx;
Mark Youngd8382d72016-12-23 16:59:58 -07004749 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4750 goto out;
4751 }
4752
Mark Young6267ae62017-01-12 12:27:19 -07004753 // Initialize the new physicalDevice object
4754 loader_set_dispatch((void *)new_phys_devs[new_idx], inst->disp);
4755 new_phys_devs[new_idx]->this_instance = inst;
4756 new_phys_devs[new_idx]->phys_dev = local_phys_devs[new_idx];
Mark Young559d7502016-09-26 11:38:46 -06004757 }
Lenny Komowa5e01122016-12-22 15:29:43 -07004758 }
Mark Young559d7502016-09-26 11:38:46 -06004759
Lenny Komowa5e01122016-12-22 15:29:43 -07004760out:
Mark Youngd8382d72016-12-23 16:59:58 -07004761
Mark Young6267ae62017-01-12 12:27:19 -07004762 if (VK_SUCCESS != res) {
4763 if (NULL != new_phys_devs) {
4764 for (uint32_t i = 0; i < total_count; i++) {
4765 loader_instance_heap_free(inst, new_phys_devs[i]);
Lenny Komowa5e01122016-12-22 15:29:43 -07004766 }
4767 loader_instance_heap_free(inst, new_phys_devs);
Mark Young6267ae62017-01-12 12:27:19 -07004768 }
4769 total_count = 0;
4770 } else {
4771 // Free everything that didn't carry over to the new array of
4772 // physical devices
4773 if (NULL != inst->phys_devs_tramp) {
4774 for (uint32_t i = 0; i < inst->phys_dev_count_tramp; i++) {
4775 bool found = false;
4776 for (uint32_t j = 0; j < total_count; j++) {
4777 if (inst->phys_devs_tramp[i] == new_phys_devs[j]) {
4778 found = true;
4779 break;
4780 }
4781 }
4782 if (!found) {
4783 loader_instance_heap_free(inst,
4784 inst->phys_devs_tramp[i]);
4785 }
4786 }
4787 loader_instance_heap_free(inst, inst->phys_devs_tramp);
4788 }
Mark Youngd8382d72016-12-23 16:59:58 -07004789
Mark Young6267ae62017-01-12 12:27:19 -07004790 // Swap in the new physical device list
4791 inst->phys_dev_count_tramp = total_count;
4792 inst->phys_devs_tramp = new_phys_devs;
4793 }
4794
4795 return res;
4796}
4797
4798VkResult setupLoaderTermPhysDevs(struct loader_instance *inst) {
4799 VkResult res = VK_SUCCESS;
4800 struct loader_icd_term *icd_term;
4801 struct loader_phys_dev_per_icd *icd_phys_dev_array = NULL;
4802 struct loader_physical_device_term **new_phys_devs = NULL;
4803 uint32_t i = 0;
4804
4805 inst->total_gpu_count = 0;
4806
4807 // Allocate something to store the physical device characteristics
4808 // that we read from each ICD.
4809 icd_phys_dev_array = (struct loader_phys_dev_per_icd *)loader_stack_alloc(
4810 sizeof(struct loader_phys_dev_per_icd) * inst->total_icd_count);
4811 if (NULL == icd_phys_dev_array) {
4812 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4813 "setupLoaderTermPhysDevs: Failed to allocate temporary "
4814 " ICD Physical device info array of size %d",
4815 inst->total_gpu_count);
4816 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4817 goto out;
4818 }
4819 memset(icd_phys_dev_array, 0,
4820 sizeof(struct loader_phys_dev_per_icd) * inst->total_icd_count);
4821 icd_term = inst->icd_terms;
4822
4823 // For each ICD, query the number of physical devices, and then get an
4824 // internal value for those physical devices.
4825 while (NULL != icd_term) {
4826 res = icd_term->EnumeratePhysicalDevices(
4827 icd_term->instance, &icd_phys_dev_array[i].count, NULL);
4828 if (VK_SUCCESS != res) {
4829 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4830 "setupLoaderTermPhysDevs: Call to "
4831 "ICD %d's \'vkEnumeratePhysicalDevices\' failed with"
4832 " error 0x%08x",
4833 i, res);
4834 goto out;
4835 }
4836
4837 icd_phys_dev_array[i].phys_devs =
4838 (VkPhysicalDevice *)loader_stack_alloc(icd_phys_dev_array[i].count *
4839 sizeof(VkPhysicalDevice));
4840 if (NULL == icd_phys_dev_array[i].phys_devs) {
4841 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4842 "setupLoaderTermPhysDevs: Failed to allocate temporary "
4843 " ICD Physical device array for ICD %d of size %d",
4844 i, inst->total_gpu_count);
4845 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4846 goto out;
4847 }
4848
4849 res = icd_term->EnumeratePhysicalDevices(
4850 icd_term->instance, &(icd_phys_dev_array[i].count),
4851 icd_phys_dev_array[i].phys_devs);
4852 if (VK_SUCCESS != res) {
4853 goto out;
4854 }
4855 inst->total_gpu_count += icd_phys_dev_array[i].count;
4856 icd_phys_dev_array[i].this_icd_term = icd_term;
4857
4858 icd_term = icd_term->next;
4859 i++;
4860 }
4861
4862 if (0 == inst->total_gpu_count) {
4863 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4864 "setupLoaderTermPhysDevs: Failed to detect any valid"
4865 " GPUs in the current config");
4866 res = VK_ERROR_INITIALIZATION_FAILED;
4867 goto out;
4868 }
4869
4870 new_phys_devs = loader_instance_heap_alloc(
4871 inst,
4872 sizeof(struct loader_physical_device_term *) * inst->total_gpu_count,
4873 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
4874 if (NULL == new_phys_devs) {
4875 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4876 "setupLoaderTermPhysDevs: Failed to allocate new physical"
4877 " device array of size %d",
4878 inst->total_gpu_count);
4879 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4880 goto out;
4881 }
4882 memset(new_phys_devs, 0, sizeof(struct loader_physical_device_term *) *
4883 inst->total_gpu_count);
4884
4885 // Copy or create everything to fill the new array of physical devices
4886 uint32_t idx = 0;
4887 for (uint32_t icd_idx = 0; icd_idx < inst->total_icd_count; icd_idx++) {
4888 for (uint32_t pd_idx = 0; pd_idx < icd_phys_dev_array[icd_idx].count;
4889 pd_idx++) {
4890
4891 // Check if this physical device is already in the old buffer
4892 if (NULL != inst->phys_devs_term) {
4893 for (uint32_t old_idx = 0;
4894 old_idx < inst->phys_dev_count_term;
4895 old_idx++) {
4896 if (icd_phys_dev_array[icd_idx].phys_devs[pd_idx] ==
4897 inst->phys_devs_term[old_idx]->phys_dev) {
4898 new_phys_devs[idx] = inst->phys_devs_term[old_idx];
4899 break;
4900 }
4901 }
4902 }
4903 // If this physical device isn't in the old buffer, then we
4904 // need to create it.
4905 if (NULL == new_phys_devs[idx]) {
4906 new_phys_devs[idx] = loader_instance_heap_alloc(
4907 inst, sizeof(struct loader_physical_device_term),
4908 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
4909 if (NULL == new_phys_devs[idx]) {
4910 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4911 "setupLoaderTermPhysDevs: Failed to allocate "
4912 "physical device terminator object %d",
4913 idx);
4914 inst->total_gpu_count = idx;
4915 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4916 goto out;
4917 }
4918
4919 loader_set_dispatch((void *)new_phys_devs[idx], inst->disp);
4920 new_phys_devs[idx]->this_icd_term =
4921 icd_phys_dev_array[icd_idx].this_icd_term;
4922 new_phys_devs[idx]->icd_index = (uint8_t)(icd_idx);
4923 new_phys_devs[idx]->phys_dev =
4924 icd_phys_dev_array[icd_idx].phys_devs[pd_idx];
4925 }
4926 idx++;
4927 }
4928 }
4929
4930out:
4931
4932 if (VK_SUCCESS != res) {
4933 if (NULL != inst->phys_devs_term) {
4934 // We've encountered an error, so we should free the
4935 // new buffers.
4936 for (uint32_t i = 0; i < inst->total_gpu_count; i++) {
4937 loader_instance_heap_free(inst, new_phys_devs[i]);
4938 }
4939 loader_instance_heap_free(inst, inst->phys_devs_term);
4940 inst->total_gpu_count = 0;
4941 }
4942 } else {
4943 // Free everything that didn't carry over to the new array of
4944 // physical devices. Everything else will have been copied over
4945 // to the new array.
4946 if (NULL != inst->phys_devs_term) {
4947 for (uint32_t cur_pd = 0; cur_pd < inst->phys_dev_count_term;
4948 cur_pd++) {
4949 bool found = false;
4950 for (uint32_t new_pd_idx = 0;
4951 new_pd_idx < inst->total_gpu_count;
4952 new_pd_idx++) {
4953 if (inst->phys_devs_term[cur_pd] ==
4954 new_phys_devs[new_pd_idx]) {
4955 found = true;
4956 break;
4957 }
4958 }
4959 if (!found) {
4960 loader_instance_heap_free(inst,
4961 inst->phys_devs_term[cur_pd]);
4962 }
4963 }
4964 loader_instance_heap_free(inst, inst->phys_devs_term);
4965 }
4966
4967 // Swap out old and new devices list
4968 inst->phys_dev_count_term = inst->total_gpu_count;
4969 inst->phys_devs_term = new_phys_devs;
4970 }
4971
4972 return res;
4973}
4974
4975VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDevices(
4976 VkInstance instance, uint32_t *pPhysicalDeviceCount,
4977 VkPhysicalDevice *pPhysicalDevices) {
4978 struct loader_instance *inst = (struct loader_instance *)instance;
4979 VkResult res = VK_SUCCESS;
4980
4981 // Only do the setup if we're re-querying the number of devices, or
4982 // our count is currently 0.
4983 if (NULL == pPhysicalDevices || 0 == inst->total_gpu_count) {
4984 res = setupLoaderTermPhysDevs(inst);
4985 if (VK_SUCCESS != res) {
4986 goto out;
4987 }
4988 }
4989
4990 uint32_t copy_count = inst->total_gpu_count;
4991 if (NULL != pPhysicalDevices) {
4992 if (copy_count > *pPhysicalDeviceCount) {
4993 copy_count = *pPhysicalDeviceCount;
4994 res = VK_INCOMPLETE;
4995 }
4996
4997 for (uint32_t i = 0; i < copy_count; i++) {
4998 pPhysicalDevices[i] = (VkPhysicalDevice)inst->phys_devs_term[i];
Jon Ashburn014438f2016-03-01 19:51:07 -07004999 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06005000 }
Mark Young559d7502016-09-26 11:38:46 -06005001
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07005002 *pPhysicalDeviceCount = copy_count;
5003
Mark Young6267ae62017-01-12 12:27:19 -07005004out:
5005
Jon Ashburn24cd4be2015-11-01 14:04:06 -07005006 return res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07005007}
5008
Jon Ashburn1530c342016-02-26 13:14:27 -07005009VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceProperties(
5010 VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties *pProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06005011 struct loader_physical_device_term *phys_dev_term =
5012 (struct loader_physical_device_term *)physicalDevice;
5013 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Youngb6399312017-01-10 14:22:15 -07005014 if (NULL != icd_term->GetPhysicalDeviceProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06005015 icd_term->GetPhysicalDeviceProperties(phys_dev_term->phys_dev,
5016 pProperties);
Mark Youngb6399312017-01-10 14:22:15 -07005017 }
Tony Barbour59a47322015-06-24 16:06:58 -06005018}
5019
Jon Ashburn1530c342016-02-26 13:14:27 -07005020VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceQueueFamilyProperties(
Jon Ashburn23d36b12016-02-02 17:47:28 -07005021 VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount,
5022 VkQueueFamilyProperties *pProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06005023 struct loader_physical_device_term *phys_dev_term =
5024 (struct loader_physical_device_term *)physicalDevice;
5025 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Youngb6399312017-01-10 14:22:15 -07005026 if (NULL != icd_term->GetPhysicalDeviceQueueFamilyProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06005027 icd_term->GetPhysicalDeviceQueueFamilyProperties(
5028 phys_dev_term->phys_dev, pQueueFamilyPropertyCount, pProperties);
Mark Youngb6399312017-01-10 14:22:15 -07005029 }
Tony Barbour59a47322015-06-24 16:06:58 -06005030}
5031
Jon Ashburn1530c342016-02-26 13:14:27 -07005032VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceMemoryProperties(
Jon Ashburn23d36b12016-02-02 17:47:28 -07005033 VkPhysicalDevice physicalDevice,
5034 VkPhysicalDeviceMemoryProperties *pProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06005035 struct loader_physical_device_term *phys_dev_term =
5036 (struct loader_physical_device_term *)physicalDevice;
5037 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Youngb6399312017-01-10 14:22:15 -07005038 if (NULL != icd_term->GetPhysicalDeviceMemoryProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06005039 icd_term->GetPhysicalDeviceMemoryProperties(phys_dev_term->phys_dev,
5040 pProperties);
Mark Youngb6399312017-01-10 14:22:15 -07005041 }
Jon Ashburn3da71f22015-05-14 12:43:38 -06005042}
5043
Mark Young0153e0b2016-11-03 14:27:13 -06005044VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFeatures(
5045 VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures *pFeatures) {
5046 struct loader_physical_device_term *phys_dev_term =
5047 (struct loader_physical_device_term *)physicalDevice;
5048 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Youngb6399312017-01-10 14:22:15 -07005049 if (NULL != icd_term->GetPhysicalDeviceFeatures) {
Mark Young0153e0b2016-11-03 14:27:13 -06005050 icd_term->GetPhysicalDeviceFeatures(phys_dev_term->phys_dev, pFeatures);
Mark Youngb6399312017-01-10 14:22:15 -07005051 }
Chris Forbesbc0bb772015-06-21 22:55:02 +12005052}
5053
Mark Young0153e0b2016-11-03 14:27:13 -06005054VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFormatProperties(
5055 VkPhysicalDevice physicalDevice, VkFormat format,
5056 VkFormatProperties *pFormatInfo) {
5057 struct loader_physical_device_term *phys_dev_term =
5058 (struct loader_physical_device_term *)physicalDevice;
5059 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Youngb6399312017-01-10 14:22:15 -07005060 if (NULL != icd_term->GetPhysicalDeviceFormatProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06005061 icd_term->GetPhysicalDeviceFormatProperties(phys_dev_term->phys_dev,
5062 format, pFormatInfo);
Mark Youngb6399312017-01-10 14:22:15 -07005063 }
Chris Forbesbc0bb772015-06-21 22:55:02 +12005064}
5065
Jon Ashburn1530c342016-02-26 13:14:27 -07005066VKAPI_ATTR VkResult VKAPI_CALL
5067terminator_GetPhysicalDeviceImageFormatProperties(
Jon Ashburn23d36b12016-02-02 17:47:28 -07005068 VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type,
5069 VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags,
5070 VkImageFormatProperties *pImageFormatProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06005071 struct loader_physical_device_term *phys_dev_term =
5072 (struct loader_physical_device_term *)physicalDevice;
5073 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Youngb6399312017-01-10 14:22:15 -07005074 if (NULL == icd_term->GetPhysicalDeviceImageFormatProperties) {
5075 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5076 "Encountered the vkEnumerateDeviceLayerProperties "
5077 "terminator. This means a layer improperly continued.");
Chia-I Wu17241042015-10-31 00:31:16 +08005078 return VK_ERROR_INITIALIZATION_FAILED;
Mark Youngb6399312017-01-10 14:22:15 -07005079 }
Mark Young0153e0b2016-11-03 14:27:13 -06005080 return icd_term->GetPhysicalDeviceImageFormatProperties(
5081 phys_dev_term->phys_dev, format, type, tiling, usage, flags,
Jon Ashburn23d36b12016-02-02 17:47:28 -07005082 pImageFormatProperties);
Jon Ashburn754864f2015-07-23 18:49:07 -06005083}
5084
Jon Ashburn1530c342016-02-26 13:14:27 -07005085VKAPI_ATTR void VKAPI_CALL
5086terminator_GetPhysicalDeviceSparseImageFormatProperties(
Jon Ashburn23d36b12016-02-02 17:47:28 -07005087 VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type,
5088 VkSampleCountFlagBits samples, VkImageUsageFlags usage,
5089 VkImageTiling tiling, uint32_t *pNumProperties,
5090 VkSparseImageFormatProperties *pProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06005091 struct loader_physical_device_term *phys_dev_term =
5092 (struct loader_physical_device_term *)physicalDevice;
5093 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Youngb6399312017-01-10 14:22:15 -07005094 if (NULL != icd_term->GetPhysicalDeviceSparseImageFormatProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06005095 icd_term->GetPhysicalDeviceSparseImageFormatProperties(
5096 phys_dev_term->phys_dev, format, type, samples, usage, tiling,
Jon Ashburn23d36b12016-02-02 17:47:28 -07005097 pNumProperties, pProperties);
Mark Youngb6399312017-01-10 14:22:15 -07005098 }
Mark Lobodzinski16e8bef2015-07-03 15:58:09 -06005099}
5100
Jon Ashburn1530c342016-02-26 13:14:27 -07005101VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateDeviceExtensionProperties(
5102 VkPhysicalDevice physicalDevice, const char *pLayerName,
5103 uint32_t *pPropertyCount, VkExtensionProperties *pProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06005104 struct loader_physical_device_term *phys_dev_term;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07005105
Mark Young3a587792016-08-19 15:25:08 -06005106 struct loader_layer_list implicit_layer_list = {0};
5107 struct loader_extension_list all_exts = {0};
5108 struct loader_extension_list icd_exts = {0};
Jon Ashburn471f44c2016-01-13 12:51:43 -07005109
Jon Ashburndc5d9202016-02-29 13:00:51 -07005110 assert(pLayerName == NULL || strlen(pLayerName) == 0);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06005111
Jon Ashburndc5d9202016-02-29 13:00:51 -07005112 /* Any layer or trampoline wrapping should be removed at this point in time
5113 * can just cast to the expected type for VkPhysicalDevice. */
Mark Young0153e0b2016-11-03 14:27:13 -06005114 phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Jon Ashburn471f44c2016-01-13 12:51:43 -07005115
Jon Ashburndc5d9202016-02-29 13:00:51 -07005116 /* this case is during the call down the instance chain with pLayerName
5117 * == NULL*/
Mark Young0153e0b2016-11-03 14:27:13 -06005118 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Jon Ashburndc5d9202016-02-29 13:00:51 -07005119 uint32_t icd_ext_count = *pPropertyCount;
5120 VkResult res;
Jon Ashburn471f44c2016-01-13 12:51:43 -07005121
Jon Ashburndc5d9202016-02-29 13:00:51 -07005122 /* get device extensions */
Mark Young0153e0b2016-11-03 14:27:13 -06005123 res = icd_term->EnumerateDeviceExtensionProperties(
5124 phys_dev_term->phys_dev, NULL, &icd_ext_count, pProperties);
Mark Young3a587792016-08-19 15:25:08 -06005125 if (res != VK_SUCCESS) {
5126 goto out;
5127 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07005128
Mark Young0153e0b2016-11-03 14:27:13 -06005129 if (!loader_init_layer_list(icd_term->this_instance,
5130 &implicit_layer_list)) {
Mark Young3a587792016-08-19 15:25:08 -06005131 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5132 goto out;
5133 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07005134
Jon Ashburndc5d9202016-02-29 13:00:51 -07005135 loader_add_layer_implicit(
Mark Young0153e0b2016-11-03 14:27:13 -06005136 icd_term->this_instance, VK_LAYER_TYPE_INSTANCE_IMPLICIT,
5137 &implicit_layer_list, &icd_term->this_instance->instance_layer_list);
Jon Ashburndc5d9202016-02-29 13:00:51 -07005138 /* we need to determine which implicit layers are active,
5139 * and then add their extensions. This can't be cached as
5140 * it depends on results of environment variables (which can change).
5141 */
5142 if (pProperties != NULL) {
5143 /* initialize dev_extension list within the physicalDevice object */
Mark Young0153e0b2016-11-03 14:27:13 -06005144 res = loader_init_device_extensions(icd_term->this_instance,
5145 phys_dev_term, icd_ext_count,
5146 pProperties, &icd_exts);
Mark Young3a587792016-08-19 15:25:08 -06005147 if (res != VK_SUCCESS) {
5148 goto out;
5149 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07005150
Jon Ashburndc5d9202016-02-29 13:00:51 -07005151 /* we need to determine which implicit layers are active,
5152 * and then add their extensions. This can't be cached as
5153 * it depends on results of environment variables (which can
5154 * change).
5155 */
Mark Young0153e0b2016-11-03 14:27:13 -06005156 res = loader_add_to_ext_list(icd_term->this_instance, &all_exts,
Mark Young3a587792016-08-19 15:25:08 -06005157 icd_exts.count, icd_exts.list);
5158 if (res != VK_SUCCESS) {
5159 goto out;
5160 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07005161
Jon Ashburndc5d9202016-02-29 13:00:51 -07005162 loader_add_layer_implicit(
Mark Young0153e0b2016-11-03 14:27:13 -06005163 icd_term->this_instance, VK_LAYER_TYPE_INSTANCE_IMPLICIT,
5164 &implicit_layer_list,
5165 &icd_term->this_instance->instance_layer_list);
Jon Ashburn471f44c2016-01-13 12:51:43 -07005166
Jon Ashburndc5d9202016-02-29 13:00:51 -07005167 for (uint32_t i = 0; i < implicit_layer_list.count; i++) {
5168 for (uint32_t j = 0;
Jon Ashburn014438f2016-03-01 19:51:07 -07005169 j < implicit_layer_list.list[i].device_extension_list.count;
5170 j++) {
Mark Young0153e0b2016-11-03 14:27:13 -06005171 res = loader_add_to_ext_list(icd_term->this_instance, &all_exts,
5172 1,
Mark Young3a587792016-08-19 15:25:08 -06005173 &implicit_layer_list.list[i]
5174 .device_extension_list.list[j]
5175 .props);
5176 if (res != VK_SUCCESS) {
5177 goto out;
5178 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07005179 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07005180 }
Jon Ashburndc5d9202016-02-29 13:00:51 -07005181 uint32_t capacity = *pPropertyCount;
5182 VkExtensionProperties *props = pProperties;
Jon Ashburn471f44c2016-01-13 12:51:43 -07005183
Jon Ashburndc5d9202016-02-29 13:00:51 -07005184 for (uint32_t i = 0; i < all_exts.count && i < capacity; i++) {
5185 props[i] = all_exts.list[i];
5186 }
5187 /* wasn't enough space for the extensions, we did partial copy now
5188 * return VK_INCOMPLETE */
5189 if (capacity < all_exts.count) {
5190 res = VK_INCOMPLETE;
5191 } else {
5192 *pPropertyCount = all_exts.count;
5193 }
Jon Ashburndc5d9202016-02-29 13:00:51 -07005194 } else {
5195 /* just return the count; need to add in the count of implicit layer
5196 * extensions
5197 * don't worry about duplicates being added in the count */
5198 *pPropertyCount = icd_ext_count;
5199
5200 for (uint32_t i = 0; i < implicit_layer_list.count; i++) {
5201 *pPropertyCount +=
Jon Ashburn014438f2016-03-01 19:51:07 -07005202 implicit_layer_list.list[i].device_extension_list.count;
Jon Ashburndc5d9202016-02-29 13:00:51 -07005203 }
5204 res = VK_SUCCESS;
Jon Ashburnb82c1852015-08-11 14:49:54 -06005205 }
Jon Ashburndc5d9202016-02-29 13:00:51 -07005206
Mark Young3a587792016-08-19 15:25:08 -06005207out:
5208
5209 if (NULL != implicit_layer_list.list) {
5210 loader_destroy_generic_list(
Mark Young0153e0b2016-11-03 14:27:13 -06005211 icd_term->this_instance,
Mark Young3a587792016-08-19 15:25:08 -06005212 (struct loader_generic_list *)&implicit_layer_list);
5213 }
5214 if (NULL != all_exts.list) {
Mark Young0153e0b2016-11-03 14:27:13 -06005215 loader_destroy_generic_list(icd_term->this_instance,
Mark Young3a587792016-08-19 15:25:08 -06005216 (struct loader_generic_list *)&all_exts);
5217 }
5218 if (NULL != icd_exts.list) {
Mark Young0153e0b2016-11-03 14:27:13 -06005219 loader_destroy_generic_list(icd_term->this_instance,
Mark Young3a587792016-08-19 15:25:08 -06005220 (struct loader_generic_list *)&icd_exts);
5221 }
5222
Jon Ashburndc5d9202016-02-29 13:00:51 -07005223 return res;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06005224}
5225
Mark Young0153e0b2016-11-03 14:27:13 -06005226VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateDeviceLayerProperties(
5227 VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
5228 VkLayerProperties *pProperties) {
Mark Youngb6399312017-01-10 14:22:15 -07005229 struct loader_physical_device_term *phys_dev_term =
5230 (struct loader_physical_device_term *)physicalDevice;
5231 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
5232 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5233 "Encountered the vkEnumerateDeviceLayerProperties "
5234 "terminator. This means a layer improperly continued.");
5235 // Should never get here this call isn't dispatched down the chain
Jon Ashburndc5d9202016-02-29 13:00:51 -07005236 return VK_ERROR_INITIALIZATION_FAILED;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06005237}
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07005238
Jon Ashburnf2b4e382016-02-10 20:50:19 -07005239VkStringErrorFlags vk_string_validate(const int max_length, const char *utf8) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07005240 VkStringErrorFlags result = VK_STRING_ERROR_NONE;
Karl Schultz2558bd32016-02-24 14:39:39 -07005241 int num_char_bytes = 0;
Jon Ashburnf2b4e382016-02-10 20:50:19 -07005242 int i, j;
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07005243
Courtney Goeltzenleuchter7a3486d2016-12-21 16:24:34 -07005244 for (i = 0; i <= max_length; i++) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07005245 if (utf8[i] == 0) {
5246 break;
Courtney Goeltzenleuchter7a3486d2016-12-21 16:24:34 -07005247 } else if (i == max_length) {
5248 result |= VK_STRING_ERROR_LENGTH;
5249 break;
Mark Lobodzinski36b4de22016-02-12 11:30:14 -07005250 } else if ((utf8[i] >= 0x20) && (utf8[i] < 0x7f)) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07005251 num_char_bytes = 0;
Jon Ashburnf2b4e382016-02-10 20:50:19 -07005252 } else if ((utf8[i] & UTF8_ONE_BYTE_MASK) == UTF8_ONE_BYTE_CODE) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07005253 num_char_bytes = 1;
Jon Ashburnf2b4e382016-02-10 20:50:19 -07005254 } else if ((utf8[i] & UTF8_TWO_BYTE_MASK) == UTF8_TWO_BYTE_CODE) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07005255 num_char_bytes = 2;
5256 } else if ((utf8[i] & UTF8_THREE_BYTE_MASK) == UTF8_THREE_BYTE_CODE) {
5257 num_char_bytes = 3;
5258 } else {
5259 result = VK_STRING_ERROR_BAD_DATA;
5260 }
5261
5262 // Validate the following num_char_bytes of data
5263 for (j = 0; (j < num_char_bytes) && (i < max_length); j++) {
5264 if (++i == max_length) {
5265 result |= VK_STRING_ERROR_LENGTH;
5266 break;
5267 }
5268 if ((utf8[i] & UTF8_DATA_BYTE_MASK) != UTF8_DATA_BYTE_CODE) {
5269 result |= VK_STRING_ERROR_BAD_DATA;
5270 }
5271 }
5272 }
5273 return result;
5274}