/* * GStreamer * Copyright (C) 2015 Matthew Waters * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "vkinstance.h" #include "vkutils.h" #include #define APP_SHORT_NAME "GStreamer" static const char *instance_validation_layers[] = { /* FIXME: until the loader stops segfaulting/hanging we don't have any * validation layers for the instance */ "Threading", "MemTracker", "ObjectTracker", "DrawState", "ParamChecker", "ShaderChecker", "Swapchain", "DeviceLimits", "Image", }; #define GST_CAT_DEFAULT gst_vulkan_instance_debug GST_DEBUG_CATEGORY (GST_CAT_DEFAULT); GST_DEBUG_CATEGORY (GST_VULKAN_DEBUG_CAT); #define gst_vulkan_instance_parent_class parent_class G_DEFINE_TYPE_WITH_CODE (GstVulkanInstance, gst_vulkan_instance, GST_TYPE_OBJECT, GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "vulkaninstance", 0, "Vulkan Instance"); GST_DEBUG_CATEGORY_INIT (GST_VULKAN_DEBUG_CAT, "vulkandebug", 0, "Vulkan Debug")); static void gst_vulkan_instance_finalize (GObject * object); GstVulkanInstance * gst_vulkan_instance_new (void) { return g_object_new (GST_TYPE_VULKAN_INSTANCE, NULL); } static void gst_vulkan_instance_init (GstVulkanInstance * instance) { } static void gst_vulkan_instance_class_init (GstVulkanInstanceClass * instance_class) { gst_vulkan_memory_init_once (); gst_vulkan_image_memory_init_once (); G_OBJECT_CLASS (instance_class)->finalize = gst_vulkan_instance_finalize; } static void gst_vulkan_instance_finalize (GObject * object) { GstVulkanInstance *instance = GST_VULKAN_INSTANCE (object); if (instance->instance) vkDestroyInstance (instance->instance); instance->instance = NULL; } static VkBool32 _gst_vk_debug_callback (VkFlags msgFlags, VkDbgObjectType objType, uint64_t srcObject, size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg, void *pUserData) { if (msgFlags & VK_DBG_REPORT_ERROR_BIT) { GST_CAT_ERROR (GST_VULKAN_DEBUG_CAT, "[%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); } else if (msgFlags & VK_DBG_REPORT_WARN_BIT) { GST_CAT_WARNING (GST_VULKAN_DEBUG_CAT, "[%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); } else if (msgFlags & VK_DBG_REPORT_INFO_BIT) { GST_CAT_LOG (GST_VULKAN_DEBUG_CAT, "[%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); } else if (msgFlags & VK_DBG_REPORT_PERF_WARN_BIT) { GST_CAT_FIXME (GST_VULKAN_DEBUG_CAT, "[%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); } else if (msgFlags & VK_DBG_REPORT_DEBUG_BIT) { GST_CAT_TRACE (GST_VULKAN_DEBUG_CAT, "[%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); } else { return FALSE; } /* * false indicates that layer should not bail-out of an * API call that had validation failures. This may mean that the * app dies inside the driver due to invalid parameter(s). * That's what would happen without validation layers, so we'll * keep that behavior here. */ return FALSE; } gboolean gst_vulkan_instance_open (GstVulkanInstance * instance, GError ** error) { VkExtensionProperties *instance_extensions; char *extension_names[64]; /* FIXME: make dynamic */ VkLayerProperties *instance_layers; uint32_t instance_extension_count = 0; uint32_t enabled_extension_count = 0; uint32_t instance_layer_count = 0; uint32_t enabled_layer_count = 0; gboolean validation_found; gboolean have_swapchain_ext = FALSE; VkResult err; /* Look for validation layers */ err = vkEnumerateInstanceLayerProperties (&instance_layer_count, NULL); if (gst_vulkan_error_to_g_error (err, error, "vKEnumerateInstanceLayerProperties") < 0) return FALSE; instance_layers = g_new0 (VkLayerProperties, instance_layer_count); err = vkEnumerateInstanceLayerProperties (&instance_layer_count, instance_layers); if (gst_vulkan_error_to_g_error (err, error, "vKEnumerateInstanceLayerProperties") < 0) { g_free (instance_layers); return FALSE; } /* TODO: allow outside selection */ validation_found = _check_for_all_layers (G_N_ELEMENTS (instance_validation_layers), instance_validation_layers, instance_layer_count, instance_layers); if (!validation_found) { g_error ("vkEnumerateInstanceLayerProperties failed to find" "required validation layer.\n\n" "Please look at the Getting Started guide for additional " "information.\nvkCreateInstance Failure"); } enabled_layer_count = G_N_ELEMENTS (instance_validation_layers); err = vkEnumerateInstanceExtensionProperties (NULL, &instance_extension_count, NULL); if (gst_vulkan_error_to_g_error (err, error, "vkEnumerateInstanceExtensionProperties") < 0) { g_free (instance_layers); return FALSE; } memset (extension_names, 0, sizeof (extension_names)); instance_extensions = g_new0 (VkExtensionProperties, instance_extension_count); err = vkEnumerateInstanceExtensionProperties (NULL, &instance_extension_count, instance_extensions); if (gst_vulkan_error_to_g_error (err, error, "vkEnumerateInstanceExtensionProperties") < 0) { g_free (instance_layers); g_free (instance_extensions); return FALSE; } /* TODO: allow outside selection */ for (uint32_t i = 0; i < instance_extension_count; i++) { if (!g_strcmp0 ("VK_EXT_KHR_swapchain", instance_extensions[i].extName)) { have_swapchain_ext = TRUE; extension_names[enabled_extension_count++] = (gchar *) "VK_EXT_KHR_swapchain"; } if (!g_strcmp0 (VK_DEBUG_REPORT_EXTENSION_NAME, instance_extensions[i].extName)) { extension_names[enabled_extension_count++] = (gchar *) VK_DEBUG_REPORT_EXTENSION_NAME; } g_assert (enabled_extension_count < 64); } if (!have_swapchain_ext) { g_error ("vkEnumerateInstanceExtensionProperties failed to find the " "\"VK_EXT_KHR_swapchain\" extension.\n\nDo you have a compatible " "Vulkan installable client driver (ICD) installed?\nPlease " "look at the Getting Started guide for additional " "information.\nvkCreateInstance Failure"); } { const VkApplicationInfo app = { .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .pNext = NULL, .pAppName = APP_SHORT_NAME, .appVersion = 0, .pEngineName = APP_SHORT_NAME, .engineVersion = 0, .apiVersion = VK_API_VERSION, }; VkInstanceCreateInfo inst_info = { .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, .pNext = NULL, .pAppInfo = &app, .pAllocCb = NULL, .layerCount = enabled_layer_count, .ppEnabledLayerNames = (const char *const *) instance_validation_layers, .extensionCount = enabled_extension_count, .ppEnabledExtensionNames = (const char *const *) extension_names, }; err = vkCreateInstance (&inst_info, &instance->instance); if (gst_vulkan_error_to_g_error (err, error, "vkCreateInstance") < 0) { g_free (instance_layers); g_free (instance_extensions); return FALSE; } } g_free (instance_layers); g_free (instance_extensions); err = vkEnumeratePhysicalDevices (instance->instance, &instance->n_physical_devices, NULL); if (gst_vulkan_error_to_g_error (err, error, "vkEnumeratePhysicalDevices") < 0) return FALSE; g_assert (instance->n_physical_devices > 0); instance->physical_devices = g_new0 (VkPhysicalDevice, instance->n_physical_devices); err = vkEnumeratePhysicalDevices (instance->instance, &instance->n_physical_devices, instance->physical_devices); if (gst_vulkan_error_to_g_error (err, error, "vkEnumeratePhysicalDevices") < 0) return FALSE; instance->dbgCreateMsgCallback = (PFN_vkDbgCreateMsgCallback) gst_vulkan_instance_get_proc_address (instance, "vkDbgCreateMsgCallback"); if (!instance->dbgCreateMsgCallback) { g_set_error (error, GST_VULKAN_ERROR, GST_VULKAN_ERROR_FAILED, "Failed to retreive vkDbgCreateMsgCallback"); return FALSE; } instance->dbgDestroyMsgCallback = (PFN_vkDbgDestroyMsgCallback) gst_vulkan_instance_get_proc_address (instance, "vkDbgDestroyMsgCallback"); if (!instance->dbgDestroyMsgCallback) { g_set_error (error, GST_VULKAN_ERROR, GST_VULKAN_ERROR_FAILED, "Failed to retreive vkDbgDestroyMsgCallback"); return FALSE; } instance->dbgBreakCallback = (PFN_vkDbgMsgCallback) gst_vulkan_instance_get_proc_address (instance, "vkDbgBreakCallback"); if (!instance->dbgBreakCallback) { g_set_error (error, GST_VULKAN_ERROR, GST_VULKAN_ERROR_FAILED, "Failed to retreive vkDbgBreakCallback"); return FALSE; } err = instance->dbgCreateMsgCallback (instance->instance, VK_DBG_REPORT_ERROR_BIT | VK_DBG_REPORT_WARN_BIT | VK_DBG_REPORT_INFO_BIT | VK_DBG_REPORT_DEBUG_BIT | VK_DBG_REPORT_PERF_WARN_BIT, _gst_vk_debug_callback, NULL, &instance->msg_callback); if (gst_vulkan_error_to_g_error (err, error, "vkDbgCreateMsgCallback") < 0) return FALSE; return TRUE; } gpointer gst_vulkan_instance_get_proc_address (GstVulkanInstance * instance, const gchar * name) { g_return_val_if_fail (GST_IS_VULKAN_INSTANCE (instance), NULL); g_return_val_if_fail (instance->instance != NULL, NULL); g_return_val_if_fail (name != NULL, NULL); GST_TRACE_OBJECT (instance, "%s", name); return vkGetInstanceProcAddr (instance->instance, name); } void gst_vulkan_instance_close (GstVulkanInstance * instance) { g_return_if_fail (GST_IS_VULKAN_INSTANCE (instance)); g_return_if_fail (instance->instance != NULL); if (instance->dbgDestroyMsgCallback) instance->dbgDestroyMsgCallback (instance->instance, instance->msg_callback); g_free (instance->physical_devices); }