diff --git a/src/vkr_renderer.c b/src/vkr_renderer.c index 3126c09..6a64001 100644 --- a/src/vkr_renderer.c +++ b/src/vkr_renderer.c @@ -80,9 +80,13 @@ struct vkr_instance { struct vkr_object base; uint32_t api_version; + PFN_vkCreateDebugUtilsMessengerEXT create_debug_utils_messenger; + PFN_vkDestroyDebugUtilsMessengerEXT destroy_debug_utils_messenger; PFN_vkGetMemoryFdKHR get_memory_fd; PFN_vkGetFenceFdKHR get_fence_fd; + VkDebugUtilsMessengerEXT validation_messenger; + uint32_t physical_device_count; VkPhysicalDevice *physical_device_handles; struct vkr_physical_device **physical_devices; @@ -296,10 +300,20 @@ struct vkr_resource_attachment { struct list_head memories; }; +enum vkr_context_validate_level { + /* no validation */ + VKR_CONTEXT_VALIDATE_NONE, + /* force enabling the validation layer */ + VKR_CONTEXT_VALIDATE_FORCE_ON, + /* same as above but also treat validation errors as fatal errors */ + VKR_CONTEXT_VALIDATE_FORCE_FATAL, +}; + struct vkr_context { struct virgl_context base; char *debug_name; + enum vkr_context_validate_level validate_level; mtx_t mutex; @@ -671,6 +685,29 @@ vkr_dispatch_vkEnumerateInstanceExtensionProperties( args->ret = count == ARRAY_SIZE(private_extensions) ? VK_SUCCESS : VK_INCOMPLETE; } +static VkBool32 +vkr_validation_callback(UNUSED VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + UNUSED VkDebugUtilsMessageTypeFlagsEXT messageTypes, + const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, + void *pUserData) +{ + struct vkr_context *ctx = pUserData; + + vrend_printf("%s\n", pCallbackData->pMessage); + + if (ctx->validate_level != VKR_CONTEXT_VALIDATE_FORCE_FATAL) + return false; + + vkr_cs_decoder_set_fatal(&ctx->decoder); + + /* The spec says we "should" return false, because the meaning of true is + * layer-defined and is reserved for layer development. And we know that, + * for VK_LAYER_KHRONOS_validation, the return value indicates whether the + * call should be skipped. Let's do it for now and seek advices. + */ + return true; +} + static void vkr_dispatch_vkCreateInstance(struct vn_dispatch_context *dispatch, struct vn_command_vkCreateInstance *args) @@ -704,6 +741,50 @@ vkr_dispatch_vkCreateInstance(struct vn_dispatch_context *dispatch, } VkInstanceCreateInfo *create_info = (VkInstanceCreateInfo *)args->pCreateInfo; + const char *layer_names[8]; + const char *ext_names[8]; + uint32_t layer_count = 0; + uint32_t ext_count = 0; + + const VkValidationFeatureDisableEXT validation_feature_disables[] = { + VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT + }; + VkValidationFeaturesEXT validation_features; + VkDebugUtilsMessengerCreateInfoEXT messenger_create_info; + if (ctx->validate_level != VKR_CONTEXT_VALIDATE_NONE) { + /* let vkCreateInstance return VK_ERROR_LAYER_NOT_PRESENT or + * VK_ERROR_EXTENSION_NOT_PRESENT when the layer or extensions are + * missing + */ + layer_names[layer_count++] = "VK_LAYER_KHRONOS_validation"; + ext_names[ext_count++] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME; + ext_names[ext_count++] = VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME; + + validation_features = (const VkValidationFeaturesEXT){ + .sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT, + .pNext = create_info->pNext, + .disabledValidationFeatureCount = ARRAY_SIZE(validation_feature_disables), + .pDisabledValidationFeatures = validation_feature_disables, + }; + messenger_create_info = (VkDebugUtilsMessengerCreateInfoEXT){ + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + .pNext = &validation_features, + .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, + .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT, + .pfnUserCallback = vkr_validation_callback, + .pUserData = ctx, + }; + + create_info->pNext = &messenger_create_info; + } + + assert(layer_count <= ARRAY_SIZE(layer_names)); + create_info->enabledLayerCount = layer_count; + create_info->ppEnabledLayerNames = layer_names; + + assert(ext_count <= ARRAY_SIZE(ext_names)); + create_info->enabledExtensionCount = ext_count; + create_info->ppEnabledExtensionNames = ext_names; /* patch apiVersion */ VkApplicationInfo app_info = { @@ -740,6 +821,25 @@ vkr_dispatch_vkCreateInstance(struct vn_dispatch_context *dispatch, instance->get_fence_fd = (PFN_vkGetFenceFdKHR)vkGetInstanceProcAddr( instance->base.handle.instance, "vkGetFenceFdKHR"); + if (ctx->validate_level != VKR_CONTEXT_VALIDATE_NONE) { + instance->create_debug_utils_messenger = + (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr( + instance->base.handle.instance, "vkCreateDebugUtilsMessengerEXT"); + instance->destroy_debug_utils_messenger = + (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr( + instance->base.handle.instance, "vkDestroyDebugUtilsMessengerEXT"); + + messenger_create_info.pNext = NULL; + args->ret = instance->create_debug_utils_messenger(instance->base.handle.instance, + &messenger_create_info, NULL, + &instance->validation_messenger); + if (args->ret != VK_SUCCESS) { + vkDestroyInstance(instance->base.handle.instance, NULL); + free(instance); + return; + } + } + util_hash_table_set_u64(ctx->object_table, instance->base.id, instance); ctx->instance = instance; @@ -757,6 +857,11 @@ vkr_dispatch_vkDestroyInstance(struct vn_dispatch_context *dispatch, return; } + if (ctx->validate_level != VKR_CONTEXT_VALIDATE_NONE) { + instance->destroy_debug_utils_messenger(instance->base.handle.instance, + instance->validation_messenger, NULL); + } + vn_replace_vkDestroyInstance_args_handle(args); vkDestroyInstance(args->instance, NULL); @@ -4469,6 +4574,8 @@ vkr_context_create(size_t debug_len, const char *debug_name) memcpy(ctx->debug_name, debug_name, debug_len); ctx->debug_name[debug_len] = '\0'; + ctx->validate_level = VKR_CONTEXT_VALIDATE_NONE; + if (mtx_init(&ctx->mutex, mtx_plain) != thrd_success) { free(ctx->debug_name); free(ctx);