#include "RenderEngine.h" #include #include #include #include #include "CoreInstance.h" #include "Log/Log.h" #include "GLFW/glfw3.h" #ifdef _DEBUG static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback( VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) { std::string msg = "validation layer: "; msg += pCallbackData->pMessage; Log(msg); return VK_FALSE; } VkResult RenderEngine::enable_layer_validation(VkDebugUtilsMessengerCreateInfoEXT* create_info) { PFN_vkCreateDebugUtilsMessengerEXT debug_creator = reinterpret_cast(vkGetInstanceProcAddr(instance_, "vkCreateDebugUtilsMessengerEXT")); return debug_creator(instance_, create_info, nullptr, &debug_messenger_); } #endif std::vector RenderEngine::get_required_extensions() { uint32_t extensions_count = 0; const char** glfw_extension = glfwGetRequiredInstanceExtensions(&extensions_count); std::vector extensions(glfw_extension, glfw_extension + extensions_count); #ifdef _DEBUG extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); #endif return extensions; } bool RenderEngine::QueueFamilyIndices::is_complete() { return graphycs_family.has_value() && present_family.has_value(); } bool RenderEngine::is_device_suitable(VkPhysicalDevice device, VkSurfaceKHR surface) { VkPhysicalDeviceProperties device_properties; VkPhysicalDeviceFeatures device_features; vkGetPhysicalDeviceProperties(device, &device_properties); vkGetPhysicalDeviceFeatures(device, &device_features); QueueFamilyIndices indices = find_queue_family_indices(device, surface); return device_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && device_features.geometryShader && indices.is_complete(); } RenderEngine::QueueFamilyIndices RenderEngine::find_queue_family_indices(VkPhysicalDevice physical_device, VkSurfaceKHR surface) { QueueFamilyIndices queue_family_indices; uint32_t queueFamilyCount = 0; vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queueFamilyCount, nullptr); std::vector family_propertieses(queueFamilyCount); vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queueFamilyCount, family_propertieses.data()); for (uint32_t i = 0; i < family_propertieses.size(); ++i) { if (family_propertieses[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) queue_family_indices.graphycs_family = i; VkBool32 present_support = false; VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, i, surface, &present_support)); if (present_support) queue_family_indices.present_family = i; if(queue_family_indices.is_complete()) break; } return queue_family_indices; } void RenderEngine::create_instance() { std::vector extensions = get_required_extensions(); VkApplicationInfo app_info{}; app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; app_info.apiVersion = VK_API_VERSION_1_0; app_info.applicationVersion = VK_MAKE_VERSION(0, 0, 0); app_info.pApplicationName = core_.getGameName().c_str(); app_info.pEngineName = "UwU Engine"; app_info.engineVersion = VK_MAKE_VERSION(0, 0, 0); VkInstanceCreateInfo instance_create_info{}; instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; instance_create_info.pApplicationInfo = &app_info; instance_create_info.enabledExtensionCount = static_cast(extensions.size()); instance_create_info.ppEnabledExtensionNames = extensions.data(); #ifdef _DEBUG std::vector layers_validation = { "VK_LAYER_KHRONOS_validation" }; instance_create_info.enabledLayerCount = static_cast(layers_validation.size()); instance_create_info.ppEnabledLayerNames = layers_validation.data(); VkDebugUtilsMessengerCreateInfoEXT debug_messenger_create_info{}; debug_messenger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; debug_messenger_create_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; debug_messenger_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; debug_messenger_create_info.pfnUserCallback = &debugCallback; instance_create_info.pNext = &debug_messenger_create_info; #endif VK_CHECK(vkCreateInstance(&instance_create_info, nullptr, &instance_)); #ifdef _DEBUG VK_CHECK(enable_layer_validation(&debug_messenger_create_info)); #endif } void RenderEngine::pick_physical_device() { uint32_t device_count = 0; std::vector devices; VK_CHECK(vkEnumeratePhysicalDevices(instance_, &device_count, nullptr)); devices.resize(device_count); VK_CHECK(vkEnumeratePhysicalDevices(instance_, &device_count, devices.data())); for (const auto& device : devices) { if (is_device_suitable(device, surface_)) { physical_device_ = device; VkPhysicalDeviceProperties device_properties; vkGetPhysicalDeviceProperties(physical_device_, &device_properties); Log("Using device: " + std::string(device_properties.deviceName)); break; } } if (VK_NULL_HANDLE == physical_device_) throw std::runtime_error("No suitable device found"); } void RenderEngine::create_logical_device() { QueueFamilyIndices indices = find_queue_family_indices(physical_device_, surface_); VkPhysicalDeviceFeatures device_features{}; std::vector queue_create_infos; std::set unique_queue_families = {indices.graphycs_family.value(), indices.present_family.value()}; float queue_priority = 1.0f; VkDeviceQueueCreateInfo device_queue_create_info{}; device_queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; device_queue_create_info.pQueuePriorities = &queue_priority; for (auto queue_family : unique_queue_families) { device_queue_create_info.queueFamilyIndex = queue_family; device_queue_create_info.queueCount = 1; queue_create_infos.push_back(device_queue_create_info); } VkDeviceCreateInfo device_create_info{}; device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; device_create_info.queueCreateInfoCount = static_cast(unique_queue_families.size()); device_create_info.pQueueCreateInfos = queue_create_infos.data(); device_create_info.pEnabledFeatures = &device_features; device_create_info.enabledExtensionCount = 0; device_create_info.ppEnabledExtensionNames = nullptr; #ifdef _DEBUG std::vector layers_validation = { "VK_LAYER_KHRONOS_validation" }; device_create_info.enabledLayerCount = static_cast(layers_validation.size()); device_create_info.ppEnabledLayerNames = layers_validation.data(); #else device_create_info.enabledLayerCount = 0; device_create_info.ppEnabledLayerNames = nullptr; #endif VK_CHECK(vkCreateDevice(physical_device_, &device_create_info, nullptr, &device_)); vkGetDeviceQueue(device_, indices.graphycs_family.value(), 0, &graphics_queue_); vkGetDeviceQueue(device_, indices.present_family.value(), 0, &present_queue_); } void RenderEngine::create_surface() { VK_CHECK(glfwCreateWindowSurface(instance_, window_, nullptr, &surface_)); } RenderEngine::RenderEngine(CoreInstance& core, GLFWwindow* window): core_(core), window_(window) #ifdef _DEBUG ,debug_messenger_(nullptr) #endif { create_instance(); create_surface(); pick_physical_device(); create_logical_device(); } RenderEngine::~RenderEngine() { if (device_ != VK_NULL_HANDLE) vkDestroyDevice(device_, nullptr); if (surface_ != VK_NULL_HANDLE) vkDestroySurfaceKHR(instance_, surface_, nullptr); #ifdef _DEBUG if (debug_messenger_ != nullptr && instance_ != nullptr) { PFN_vkDestroyDebugUtilsMessengerEXT destroyer_messenger = reinterpret_cast(vkGetInstanceProcAddr(instance_, "vkDestroyDebugUtilsMessengerEXT")); destroyer_messenger(instance_, debug_messenger_, nullptr); } #endif if (instance_ != VK_NULL_HANDLE) vkDestroyInstance(instance_, nullptr); if (window_ != nullptr) glfwDestroyWindow(window_); glfwTerminate(); } void RenderEngine::start() { while (!glfwWindowShouldClose(window_)) { glfwSwapBuffers(window_); glfwPollEvents(); } } void RenderEngine::stop_render() { if (window_ != nullptr && !glfwWindowShouldClose(window_)) glfwSetWindowShouldClose(window_, true); }