Last active
January 28, 2019 01:35
-
-
Save Caellian/76f92c79ebb96a1dc9b566dcd1216237 to your computer and use it in GitHub Desktop.
Proper validification layer handling.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #define GLFW_INCLUDE_VULKAN | |
| #include <GLFW/glfw3.h> | |
| #include <iostream> | |
| #include <stdexcept> | |
| #include <functional> | |
| #include <cstdlib> | |
| #include <vector> | |
| #include <cstring> | |
| #include "constants.h" | |
| const int WIDTH = 800; | |
| const int HEIGHT = 600; | |
| #ifndef NDEBUG | |
| std::vector< const char* > validationLayers = { | |
| "VK_LAYER_LUNARG_standard_validation" | |
| }; | |
| std::vector< const char* > foundValidationLayers(0); | |
| VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback( | |
| VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, | |
| VkDebugUtilsMessageTypeFlagsEXT messageType, | |
| const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, | |
| void* pUserData | |
| ) { | |
| switch (messageSeverity) { | |
| case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: | |
| std::cerr << "[Verbose] "; | |
| break; | |
| case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: | |
| std::cerr << "[Info] "; | |
| break; | |
| case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: | |
| std::cerr << "[Warning] "; | |
| break; | |
| case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: | |
| std::cerr << "[Error] "; | |
| break; | |
| default: | |
| std::cout << " "; | |
| break; | |
| } | |
| switch (messageType) { | |
| case VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT: | |
| std::cout << "[General] "; | |
| break; | |
| case VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT: | |
| std::cout << "[Validation] "; | |
| break; | |
| case VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT: | |
| std::cout << "[Performance] "; | |
| break; | |
| default: | |
| std::cout << " "; | |
| break; | |
| } | |
| std::cerr << pCallbackData->pMessage << std::endl; | |
| return VK_FALSE; | |
| } | |
| 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 destroyDebugUtilsMessengerEXT( | |
| VkInstance instance, | |
| VkDebugUtilsMessengerEXT debugMessenger, | |
| const VkAllocationCallbacks* pAllocator | |
| ) { | |
| auto func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT"); | |
| if (func != nullptr) { | |
| func(instance, debugMessenger, pAllocator); | |
| } | |
| } | |
| #endif | |
| std::vector< const char* > requiredExtensions = { | |
| #ifndef NDEBUG | |
| VK_EXT_DEBUG_UTILS_EXTENSION_NAME | |
| #endif | |
| }; | |
| class VoxelBox { | |
| public: | |
| void run() { | |
| initWindow(); | |
| initVulkan(); | |
| mainLoop(); | |
| cleanup(); | |
| } | |
| private: | |
| GLFWwindow* window; | |
| VkInstance instance; | |
| #ifndef NDEBUG | |
| VkDebugUtilsMessengerEXT debugMessenger; | |
| #endif | |
| void initWindow() { | |
| glfwInit(); | |
| glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); | |
| glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); // TODO: Enable resizing | |
| window = glfwCreateWindow(WIDTH, HEIGHT, PROGRAM_NAME " v" PROGRAM_VERSION, nullptr, nullptr); | |
| } | |
| void createInstance() { | |
| VkApplicationInfo appInfo = {}; | |
| appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; | |
| appInfo.pApplicationName = PROGRAM_NAME; | |
| appInfo.applicationVersion = VK_MAKE_VERSION(PROGRAM_VERSION_MAJOR, PROGRAM_VERSION_MINOR, PROGRAM_VERSION_PATCH); | |
| appInfo.pEngineName = PROGRAM_NAME " Engine"; | |
| appInfo.engineVersion = VK_MAKE_VERSION(PROGRAM_VERSION_MAJOR, PROGRAM_VERSION_MINOR, PROGRAM_VERSION_PATCH); | |
| appInfo.apiVersion = VK_API_VERSION_1_1; | |
| VkInstanceCreateInfo createInfo = {}; | |
| createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; | |
| createInfo.pApplicationInfo = &appInfo; | |
| uint32_t extensionCount = 0; | |
| vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr); | |
| std::vector<VkExtensionProperties> extensions(extensionCount); | |
| vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data()); | |
| #ifndef NDEBUG | |
| std::cout << "Available Vulkan extensions:" << std::endl; | |
| for (const auto& e: extensions) { | |
| std::cout << '\t' << e.extensionName << " (" << e.specVersion << ")" << std::endl; | |
| } | |
| uint32_t layerCount; | |
| vkEnumerateInstanceLayerProperties(&layerCount, nullptr); | |
| std::vector<VkLayerProperties> availableValidationLayers(layerCount); | |
| vkEnumerateInstanceLayerProperties(&layerCount, availableValidationLayers.data()); | |
| std::vector< const char* > missingValidationLayers(0); | |
| for (const auto &rl : validationLayers) { | |
| bool found = false; | |
| for (auto &al : availableValidationLayers) { | |
| if(found = (strcmp(al.layerName, rl) == 0)) break; | |
| } | |
| if (!found) { | |
| missingValidationLayers.push_back(rl); | |
| } else { | |
| foundValidationLayers.push_back(rl); | |
| } | |
| } | |
| validationLayers.clear(); | |
| if (!missingValidationLayers.empty()) { | |
| std::cerr << "Missing requested Vulkan validation layers:" << std::endl; | |
| for(auto &l : missingValidationLayers) { | |
| std::cerr << '\t' << l << std::endl; | |
| } | |
| } | |
| missingValidationLayers.clear(); | |
| #endif | |
| uint32_t glfwExtensionCount = 0; | |
| const char** glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); | |
| for (size_t i = 0; i < glfwExtensionCount; ++i) { | |
| requiredExtensions.push_back(glfwExtensions[i]); | |
| } | |
| // Check whether all extensions required by GLFW are available | |
| std::vector< const char* > missingExtensions(0); | |
| for (auto &re : requiredExtensions) { | |
| bool found = false; | |
| for (auto &ae : extensions) { | |
| if(found = (strcmp(ae.extensionName, re) == 0)) break; | |
| } | |
| if (!found) { | |
| missingExtensions.push_back(re); | |
| } | |
| } | |
| if (!missingExtensions.empty()) { | |
| std::cerr << "Missing Vulkan extensions:" << std::endl; | |
| for(auto &e : missingExtensions) { | |
| std::cerr << '\t' << e << std::endl; | |
| } | |
| throw std::runtime_error("required extensions missing!"); | |
| } | |
| createInfo.enabledExtensionCount = static_cast<uint32_t>(requiredExtensions.size()); | |
| createInfo.ppEnabledExtensionNames = const_cast<const char* const*>(requiredExtensions.data()); | |
| #ifdef NDEBUG | |
| createInfo.enabledLayerCount = 0; | |
| #else | |
| createInfo.enabledLayerCount = static_cast<uint32_t>(foundValidationLayers.size()); | |
| createInfo.ppEnabledLayerNames = const_cast<const char* const*>(foundValidationLayers.data()); | |
| #endif | |
| VkResult result = vkCreateInstance(&createInfo, nullptr, &instance); | |
| if (result != VK_SUCCESS) { | |
| throw std::runtime_error("failed to create Vulkan instance!"); | |
| } | |
| } | |
| #ifndef NDEBUG | |
| void setupDebugMessenger() { | |
| VkDebugUtilsMessengerCreateInfoEXT 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; | |
| createInfo.pUserData = nullptr; // Optional | |
| VkResult result = createDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger); | |
| if (result != VK_SUCCESS) { | |
| std::cerr << "unable to set up debug messenger!" << std::endl; | |
| } | |
| } | |
| #endif | |
| void initVulkan() { | |
| createInstance(); | |
| #ifndef NDEBUG | |
| setupDebugMessenger(); | |
| #endif | |
| } | |
| void mainLoop() { | |
| while (!glfwWindowShouldClose(window)) { | |
| glfwPollEvents(); | |
| } | |
| } | |
| void cleanup() { | |
| #ifndef NDEBUG | |
| destroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr); | |
| #endif | |
| vkDestroyInstance(instance, nullptr); | |
| glfwDestroyWindow(window); | |
| glfwTerminate(); | |
| } | |
| }; | |
| int main(int argc, char const *argv[]) { | |
| VoxelBox game; | |
| // TODO: Parse arguments - boost::program_options | |
| try { | |
| game.run(); | |
| } catch (const std::exception& e) { | |
| std::cerr << e.what() << std::endl; | |
| return EXIT_FAILURE; | |
| } | |
| return EXIT_SUCCESS; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment