1 /* 2 * Copyright 2021 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24 #include "vk_instance.h" 25 26 #include "vk_alloc.h" 27 #include "vk_common_entrypoints.h" 28 #include "vk_log.h" 29 #include "vk_util.h" 30 #include "vk_debug_utils.h" 31 32 #include "compiler/glsl_types.h" 33 34 VkResult 35 vk_instance_init(struct vk_instance *instance, 36 const struct vk_instance_extension_table *supported_extensions, 37 const struct vk_instance_dispatch_table *dispatch_table, 38 const VkInstanceCreateInfo *pCreateInfo, 39 const VkAllocationCallbacks *alloc) 40 { 41 memset(instance, 0, sizeof(*instance)); 42 vk_object_base_init(NULL, &instance->base, VK_OBJECT_TYPE_INSTANCE); 43 instance->alloc = *alloc; 44 45 /* VK_EXT_debug_utils */ 46 /* These messengers will only be used during vkCreateInstance or 47 * vkDestroyInstance calls. We do this first so that it's safe to use 48 * vk_errorf and friends. 49 */ 50 list_inithead(&instance->debug_utils.instance_callbacks); 51 vk_foreach_struct_const(ext, pCreateInfo->pNext) { 52 if (ext->sType == 53 VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) { 54 const VkDebugUtilsMessengerCreateInfoEXT *debugMessengerCreateInfo = 55 (const VkDebugUtilsMessengerCreateInfoEXT *)ext; 56 struct vk_debug_utils_messenger *messenger = 57 vk_alloc2(alloc, alloc, sizeof(struct vk_debug_utils_messenger), 8, 58 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 59 60 if (!messenger) 61 return vk_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY); 62 63 vk_object_base_init(NULL, &messenger->base, 64 VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT); 65 66 messenger->alloc = *alloc; 67 messenger->severity = debugMessengerCreateInfo->messageSeverity; 68 messenger->type = debugMessengerCreateInfo->messageType; 69 messenger->callback = debugMessengerCreateInfo->pfnUserCallback; 70 messenger->data = debugMessengerCreateInfo->pUserData; 71 72 list_addtail(&messenger->link, 73 &instance->debug_utils.instance_callbacks); 74 } 75 } 76 77 instance->app_info = (struct vk_app_info) { .api_version = 0 }; 78 if (pCreateInfo->pApplicationInfo) { 79 const VkApplicationInfo *app = pCreateInfo->pApplicationInfo; 80 81 instance->app_info.app_name = 82 vk_strdup(&instance->alloc, app->pApplicationName, 83 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 84 instance->app_info.app_version = app->applicationVersion; 85 86 instance->app_info.engine_name = 87 vk_strdup(&instance->alloc, app->pEngineName, 88 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 89 instance->app_info.engine_version = app->engineVersion; 90 91 instance->app_info.api_version = app->apiVersion; 92 } 93 94 if (instance->app_info.api_version == 0) 95 instance->app_info.api_version = VK_API_VERSION_1_0; 96 97 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) { 98 int idx; 99 for (idx = 0; idx < VK_INSTANCE_EXTENSION_COUNT; idx++) { 100 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], 101 vk_instance_extensions[idx].extensionName) == 0) 102 break; 103 } 104 105 if (idx >= VK_INSTANCE_EXTENSION_COUNT) 106 return vk_errorf(instance, VK_ERROR_EXTENSION_NOT_PRESENT, 107 "%s not supported", 108 pCreateInfo->ppEnabledExtensionNames[i]); 109 110 if (!supported_extensions->extensions[idx]) 111 return vk_errorf(instance, VK_ERROR_EXTENSION_NOT_PRESENT, 112 "%s not supported", 113 pCreateInfo->ppEnabledExtensionNames[i]); 114 115 #ifdef ANDROID 116 if (!vk_android_allowed_instance_extensions.extensions[idx]) 117 return vk_errorf(instance, VK_ERROR_EXTENSION_NOT_PRESENT, 118 "%s not supported", 119 pCreateInfo->ppEnabledExtensionNames[i]); 120 #endif 121 122 instance->enabled_extensions.extensions[idx] = true; 123 } 124 125 instance->dispatch_table = *dispatch_table; 126 127 /* Add common entrypoints without overwriting driver-provided ones. */ 128 vk_instance_dispatch_table_from_entrypoints( 129 &instance->dispatch_table, &vk_common_instance_entrypoints, false); 130 131 if (mtx_init(&instance->debug_report.callbacks_mutex, mtx_plain) != 0) 132 return vk_error(instance, VK_ERROR_INITIALIZATION_FAILED); 133 134 list_inithead(&instance->debug_report.callbacks); 135 136 if (mtx_init(&instance->debug_utils.callbacks_mutex, mtx_plain) != 0) { 137 mtx_destroy(&instance->debug_report.callbacks_mutex); 138 return vk_error(instance, VK_ERROR_INITIALIZATION_FAILED); 139 } 140 141 list_inithead(&instance->debug_utils.callbacks); 142 143 glsl_type_singleton_init_or_ref(); 144 145 return VK_SUCCESS; 146 } 147 148 void 149 vk_instance_finish(struct vk_instance *instance) 150 { 151 glsl_type_singleton_decref(); 152 if (unlikely(!list_is_empty(&instance->debug_utils.callbacks))) { 153 list_for_each_entry_safe(struct vk_debug_utils_messenger, messenger, 154 &instance->debug_utils.callbacks, link) { 155 list_del(&messenger->link); 156 vk_object_base_finish(&messenger->base); 157 vk_free2(&instance->alloc, &messenger->alloc, messenger); 158 } 159 } 160 if (unlikely(!list_is_empty(&instance->debug_utils.instance_callbacks))) { 161 list_for_each_entry_safe(struct vk_debug_utils_messenger, messenger, 162 &instance->debug_utils.instance_callbacks, 163 link) { 164 list_del(&messenger->link); 165 vk_object_base_finish(&messenger->base); 166 vk_free2(&instance->alloc, &messenger->alloc, messenger); 167 } 168 } 169 mtx_destroy(&instance->debug_report.callbacks_mutex); 170 mtx_destroy(&instance->debug_utils.callbacks_mutex); 171 vk_free(&instance->alloc, (char *)instance->app_info.app_name); 172 vk_free(&instance->alloc, (char *)instance->app_info.engine_name); 173 vk_object_base_finish(&instance->base); 174 } 175 176 VkResult 177 vk_enumerate_instance_extension_properties( 178 const struct vk_instance_extension_table *supported_extensions, 179 uint32_t *pPropertyCount, 180 VkExtensionProperties *pProperties) 181 { 182 VK_OUTARRAY_MAKE_TYPED(VkExtensionProperties, out, pProperties, pPropertyCount); 183 184 for (int i = 0; i < VK_INSTANCE_EXTENSION_COUNT; i++) { 185 if (!supported_extensions->extensions[i]) 186 continue; 187 188 #ifdef ANDROID 189 if (!vk_android_allowed_instance_extensions.extensions[i]) 190 continue; 191 #endif 192 193 vk_outarray_append_typed(VkExtensionProperties, &out, prop) { 194 *prop = vk_instance_extensions[i]; 195 } 196 } 197 198 return vk_outarray_status(&out); 199 } 200 201 PFN_vkVoidFunction 202 vk_instance_get_proc_addr(const struct vk_instance *instance, 203 const struct vk_instance_entrypoint_table *entrypoints, 204 const char *name) 205 { 206 PFN_vkVoidFunction func; 207 208 /* The Vulkan 1.0 spec for vkGetInstanceProcAddr has a table of exactly 209 * when we have to return valid function pointers, NULL, or it's left 210 * undefined. See the table for exact details. 211 */ 212 if (name == NULL) 213 return NULL; 214 215 #define LOOKUP_VK_ENTRYPOINT(entrypoint) \ 216 if (strcmp(name, "vk" #entrypoint) == 0) \ 217 return (PFN_vkVoidFunction)entrypoints->entrypoint 218 219 LOOKUP_VK_ENTRYPOINT(EnumerateInstanceExtensionProperties); 220 LOOKUP_VK_ENTRYPOINT(EnumerateInstanceLayerProperties); 221 LOOKUP_VK_ENTRYPOINT(EnumerateInstanceVersion); 222 LOOKUP_VK_ENTRYPOINT(CreateInstance); 223 224 /* GetInstanceProcAddr() can also be called with a NULL instance. 225 * See https://gitlab.khronos.org/vulkan/vulkan/issues/2057 226 */ 227 LOOKUP_VK_ENTRYPOINT(GetInstanceProcAddr); 228 229 #undef LOOKUP_VK_ENTRYPOINT 230 231 if (instance == NULL) 232 return NULL; 233 234 func = vk_instance_dispatch_table_get_if_supported(&instance->dispatch_table, 235 name, 236 instance->app_info.api_version, 237 &instance->enabled_extensions); 238 if (func != NULL) 239 return func; 240 241 func = vk_physical_device_dispatch_table_get_if_supported(&vk_physical_device_trampolines, 242 name, 243 instance->app_info.api_version, 244 &instance->enabled_extensions); 245 if (func != NULL) 246 return func; 247 248 func = vk_device_dispatch_table_get_if_supported(&vk_device_trampolines, 249 name, 250 instance->app_info.api_version, 251 &instance->enabled_extensions, 252 NULL); 253 if (func != NULL) 254 return func; 255 256 return NULL; 257 } 258 259 PFN_vkVoidFunction 260 vk_instance_get_proc_addr_unchecked(const struct vk_instance *instance, 261 const char *name) 262 { 263 PFN_vkVoidFunction func; 264 265 if (instance == NULL || name == NULL) 266 return NULL; 267 268 func = vk_instance_dispatch_table_get(&instance->dispatch_table, name); 269 if (func != NULL) 270 return func; 271 272 func = vk_physical_device_dispatch_table_get( 273 &vk_physical_device_trampolines, name); 274 if (func != NULL) 275 return func; 276 277 func = vk_device_dispatch_table_get(&vk_device_trampolines, name); 278 if (func != NULL) 279 return func; 280 281 return NULL; 282 } 283 284 PFN_vkVoidFunction 285 vk_instance_get_physical_device_proc_addr(const struct vk_instance *instance, 286 const char *name) 287 { 288 if (instance == NULL || name == NULL) 289 return NULL; 290 291 return vk_physical_device_dispatch_table_get_if_supported(&vk_physical_device_trampolines, 292 name, 293 instance->app_info.api_version, 294 &instance->enabled_extensions); 295 } 296