diff options
Diffstat (limited to 'render/vulkan/context.c')
-rw-r--r-- | render/vulkan/context.c | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/render/vulkan/context.c b/render/vulkan/context.c new file mode 100644 index 0000000..c0fa650 --- /dev/null +++ b/render/vulkan/context.c @@ -0,0 +1,176 @@ +#include "context.h" +#include <rune/core/logging.h> +#include <rune/core/alloc.h> +#include <stdlib.h> +#include <string.h> + +char* _get_vkerr_str(VkResult res) { + char *ret; + switch (res) { + case VK_SUCCESS: + ret = "SUCCESS"; + break; + case VK_ERROR_OUT_OF_HOST_MEMORY: + ret = "OUT OF HOST MEMORY"; + break; + case VK_ERROR_OUT_OF_DEVICE_MEMORY: + ret = "OUT OF DEVICE MEMORY"; + break; + case VK_ERROR_INITIALIZATION_FAILED: + ret = "INITIALIZATION FAILED"; + break; + case VK_ERROR_LAYER_NOT_PRESENT: + ret = "VALIDATION LAYER NOT PRESENT"; + break; + case VK_ERROR_EXTENSION_NOT_PRESENT: + ret = "EXTENSION NOT PRESENT"; + break; + case VK_ERROR_INCOMPATIBLE_DRIVER: + ret = "INCOMPATIBLE DRIVER"; + break; + default: + ret = "UNKNOWN RESULT"; + break; + } + return strdup(ret); +} + +VKAPI_ATTR VkBool32 VKAPI_CALL _vulkan_db_callback( + VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, + VkDebugUtilsMessageTypeFlagsEXT message_types, + const VkDebugUtilsMessengerCallbackDataEXT *callback_data, + void *user_data) { + switch (message_severity) { + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: + log_output(LOG_ERROR, callback_data->pMessage); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: + log_output(LOG_WARN, callback_data->pMessage); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: + log_output(LOG_INFO, callback_data->pMessage); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: + log_output(LOG_DEBUG, callback_data->pMessage); + break; + default: + break; + } + return VK_FALSE; +} + +int _init_vkdebugger(struct vkcontext *context) { + log_output(LOG_INFO, "Initializing Vulkan debugger"); + uint32_t log_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; + VkDebugUtilsMessengerCreateInfoEXT dbinfo = {VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT}; + dbinfo.messageSeverity = log_severity; + dbinfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; + dbinfo.pfnUserCallback = _vulkan_db_callback; + dbinfo.pUserData = NULL; + PFN_vkCreateDebugUtilsMessengerEXT func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(context->instance, "vkCreateDebugUtilsMessengerEXT"); + if (func == NULL) { + log_output(LOG_ERROR, "Failed to create Vulkan debugger"); + return -1; + } + + VkResult res; + res = func(context->instance, &dbinfo, NULL, &context->db_messenger); + if (res != VK_SUCCESS) { + char *err_str = _get_vkerr_str(res); + log_output(LOG_ERROR, "Cannot create a Vulkan debug session: %s", err_str); + free(err_str); + return -1; + } + return 0; +} + +struct vkcontext* create_vkcontext(struct vklayer_container *vklayers, struct ext_container *ext) { + log_output(LOG_DEBUG, "Initializing Vulkan"); + VkApplicationInfo app_info = {VK_STRUCTURE_TYPE_APPLICATION_INFO}; + app_info.apiVersion = VK_API_VERSION_1_2; + app_info.pApplicationName = "RuneClient"; + app_info.applicationVersion = VK_MAKE_VERSION(1, 0, 0); + app_info.pEngineName = "RuneEngine"; + app_info.engineVersion = VK_MAKE_VERSION(1, 0, 0); + + VkInstanceCreateInfo cinfo = {VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO}; + cinfo.pApplicationInfo = &app_info; + cinfo.enabledExtensionCount = ext->ext_count; + cinfo.ppEnabledExtensionNames = ext->extensions; + cinfo.pNext = NULL; + + struct vkcontext *ret = rune_calloc(0, sizeof(struct vkcontext)); + ret->surface = rune_alloc(sizeof(struct vksurface)); + VkResult res; + res = vkCreateInstance(&cinfo, NULL, &ret->instance); + if (res != VK_SUCCESS) { + char *err_str = _get_vkerr_str(res); + log_output(LOG_FATAL, "Cannot create a Vulkan instance: %s", err_str); + free(err_str); + rune_free(ret); + ret = NULL; + } + + if (vklayers != NULL) { + log_output(LOG_INFO, "Validation layers enabled"); + _init_vkdebugger(ret); + cinfo.enabledLayerCount = vklayers->vklayer_count; + cinfo.ppEnabledLayerNames = vklayers->vklayer_names; + } else { + log_output(LOG_INFO, "Validation layers disabled"); + } + + ret->frame = 0; + return ret; +} + +void destroy_vkcontext(struct vkcontext *context) { + log_output(LOG_DEBUG, "Closing Vulkan instance"); + PFN_vkDestroyDebugUtilsMessengerEXT func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(context->instance, "vkDestroyDebugUtilsMessengerEXT"); + func(context->instance, context->db_messenger, NULL); + vkDestroySurfaceKHR(context->instance, context->surface->handle, NULL); + vkDestroyInstance(context->instance, NULL); + rune_free(context->surface); + rune_free(context); +} + +struct vklayer_container* init_vklayers(struct ext_container *ext) { + const char** new_extensions = rune_alloc(sizeof(char*) * ext->ext_count++); + for (uint32_t i = 0; i < ext->ext_count-1; i++) + new_extensions[i] = ext->extensions[i]; + new_extensions[ext->ext_count-1] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME; + ext->extensions = new_extensions; + + uint32_t layer_count; + vkEnumerateInstanceLayerProperties(&layer_count, NULL); + VkLayerProperties layer_props[layer_count]; + vkEnumerateInstanceLayerProperties(&layer_count, layer_props); + + struct vklayer_container *ret = rune_alloc(sizeof(struct vklayer_container)); + ret->vklayer_count = 1; + ret->vklayer_names = rune_alloc(sizeof(char*) * ret->vklayer_count); + ret->vklayer_names[0] = "VK_LAYER_KHRONOS_validation"; + + for (uint32_t i = 0; i < ret->vklayer_count; i++) { + log_output(LOG_DEBUG, "Searching for layer: %s", ret->vklayer_names[i]); + int found = 0; + for (uint32_t j = 0; j < layer_count; j++) { + if (strcmp(ret->vklayer_names[i], layer_props[j].layerName) == 0) { + found = 1; + break; + } + } + if (found == 0) { + log_output(LOG_WARN, "Required validation layer is missing: %s", ret->vklayer_names[i]); + rune_free(ret); + rune_free(ext->extensions); + return NULL; + } + } + log_output(LOG_INFO, "All prerequisite validation layers found"); + rune_free(ext->extensions); + return ret; +} |