/* Following the vulkan tutorial on : https://vulkan-tutorial.com/en/Drawing_a_triangle/Presentation/Window_surface */ #define GLFW_INCLUDE_VULKAN #include #include #include #include #include #include #include const uint32_t WIDTH = 800; const uint32_t HEIGHT = 600; const std::vector validationLayers ={ //"VK_LAYER_KHRONOS_validation" "VK_LAYER_LUNARG_standard_validation" }; #ifdef NDEBUG const bool enableValidationLayers = false; # else const bool enableValidationLayers = true; #endif class HelloTriangleApplication{ public : void run (){ initWindow(); initVulkan(); mainLoop(); cleanup(); } private: GLFWwindow* window; VkInstance instance; VkDebugUtilsMessengerEXT debugMessenger; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; VkDevice device; VkQueue graphicsQueue; void initWindow(){ glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr); } void initVulkan(){ createInstance(); setupDebugMessenger(); pickPhysicalDevice(); createLogicalDevice(); } void createLogicalDevice(){ QueueFamilyIndices indices = findQueueFamilies(physicalDevice); VkDeviceQueueCreateInfo queueCreateInfo {}; queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queueCreateInfo.queueFamilyIndex = indices.graphicsFamily.value(); queueCreateInfo.queueCount = 1; float queuePriority = 1.0f; queueCreateInfo.pQueuePriorities = &queuePriority; VkPhysicalDeviceFeatures deviceFeatures{}; VkDeviceCreateInfo createInfo{}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; createInfo.pQueueCreateInfos = &queueCreateInfo; createInfo.queueCreateInfoCount = 1; createInfo.pEnabledFeatures = &deviceFeatures; createInfo.enabledExtensionCount = 0; if(enableValidationLayers){ createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else{ createInfo.enabledLayerCount = 0 ; } if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS){ throw std::runtime_error("failed to create logical device"); } vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0 , &graphicsQueue); } void pickPhysicalDevice(){ uint32_t deviceCount = 0; vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr); if(deviceCount == 0 ){ throw std::runtime_error("failed to find GPU's with Vulkan support!"); } std::vector devices(deviceCount); vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data()); for(const auto& device : devices){ if(isDeviceSuitable(device)){ physicalDevice = device; break; } } if(physicalDevice == VK_NULL_HANDLE){ throw std::runtime_error("failed to find a suitable GPU"); } } bool isDeviceSuitable(VkPhysicalDevice device){ VkPhysicalDeviceProperties deviceProperties; vkGetPhysicalDeviceProperties(device, &deviceProperties); VkPhysicalDeviceFeatures deviceFeatures; vkGetPhysicalDeviceFeatures(device, &deviceFeatures); QueueFamilyIndices indices = findQueueFamilies(device); return indices.isComplete(); } struct QueueFamilyIndices { std::optional graphicsFamily; bool isComplete(){ return graphicsFamily.has_value(); } }; QueueFamilyIndices findQueueFamilies (VkPhysicalDevice device ){ QueueFamilyIndices indices; uint32_t queueFamilyCount = 0; vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr); std::vector queueFamilies(queueFamilyCount); vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data()); int i = 0; for (const auto& queueFamily : queueFamilies){ if(queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT){ indices.graphicsFamily = i; } if(indices.isComplete()){ break; } i++; } return indices; } VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pDebugMessenger) { auto func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT"); if (func != nullptr) { return func(instance, pCreateInfo, pAllocator, pDebugMessenger); } else { return VK_ERROR_EXTENSION_NOT_PRESENT; } } void setupDebugMessenger(){ if(!enableValidationLayers) return; VkDebugUtilsMessengerCreateInfoEXT createinfo; populateDebugMessengerCreateInfo(createinfo); if (CreateDebugUtilsMessengerEXT(instance, &createinfo, nullptr, &debugMessenger) != VK_SUCCESS) { throw std::runtime_error("failed to set up debug messenger!"); } } bool checkValidationLayerSupport(){ uint32_t layerCount ; vkEnumerateInstanceLayerProperties(&layerCount, nullptr); std::vector availableLayers(layerCount); vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data()); for( const char* layerName: validationLayers) { bool layerFound = false; for (const auto & layerProperties : availableLayers){ if( strcmp(layerName, layerProperties.layerName) == 0){ layerFound = true; break; } } if(!layerFound ){ return false; } } return true; } std::vector getRequiredExtensions(){ uint32_t glfwExtensionCount = 0; const char** glfwExtensions; glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); std::vector extensions (glfwExtensions, glfwExtensions + glfwExtensionCount); if(enableValidationLayers){ extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); } return extensions; } void createInstance(){ if ( enableValidationLayers && !checkValidationLayerSupport()){ throw std::runtime_error("Validation layer requested, but not available!"); } VkApplicationInfo appInfo{}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; appInfo.pApplicationName = "Hello Triangle"; appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); appInfo.pEngineName = "No Engine"; appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); appInfo.apiVersion = VK_API_VERSION_1_0; VkInstanceCreateInfo createInfo{}; createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; createInfo.pApplicationInfo = &appInfo; VkDebugUtilsMessengerCreateInfoEXT debugcreateinfo{}; if(enableValidationLayers){ createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); populateDebugMessengerCreateInfo(debugcreateinfo); createInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*) &debugcreateinfo; } else{ createInfo.enabledLayerCount = 0; createInfo.pNext = nullptr; } auto extensions = getRequiredExtensions(); createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); if(enableValidationLayers){ createInfo.enabledLayerCount = static_cast (validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else{ createInfo.enabledLayerCount = 0; } if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS ){ throw std::runtime_error("Failed to create instance!"); } } void mainLoop(){ while (!glfwWindowShouldClose(window)){ glfwPollEvents(); } } void cleanup(){ vkDestroyDevice(device, nullptr); if(enableValidationLayers){ DestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr); } vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); glfwTerminate(); } void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo) { createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; createInfo.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; createInfo.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; createInfo.pfnUserCallback = debugCallback; } void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator) { auto func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT"); if (func != nullptr) { func(instance, debugMessenger, pAllocator); } } static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback( VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData){ std::cerr << "Validation layer: " << pCallbackData->pMessage << std::endl; return VK_FALSE; } }; int main ( ) { HelloTriangleApplication app; try{ app.run(); } catch (const std::exception& e){ std::cerr << e.what() << std::endl; return EXIT_FAILURE; } return EXIT_SUCCESS; }