#define GLFW_INCLUDE_VULKAN #include #include #include #include #include #include const int WIDTH = 800; const int HEIGHT = 600; const std::vector validationLayers = { "VK_LAYER_LUNARG_standard_validation" }; #ifdef NDEBUG const bool enableValidationLayers = false; #else const bool enableValidationLayers = true; #endif VkResult CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback) { auto func = (PFN_vkCreateDebugReportCallbackEXT) vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"); if (func != nullptr) { return func(instance, pCreateInfo, pAllocator, pCallback); } else { return VK_ERROR_EXTENSION_NOT_PRESENT; } } void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator) { auto func = (PFN_vkDestroyDebugReportCallbackEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT"); if (func != nullptr) { func(instance, callback, pAllocator); } } template class VDeleter { public: VDeleter() : VDeleter([](T, VkAllocationCallbacks*) {}) {} VDeleter(std::function deletef) { this->deleter = [=](T obj) { deletef(obj, nullptr); }; } VDeleter(const VDeleter& instance, std::function deletef) { this->deleter = [&instance, deletef](T obj) { deletef(instance, obj, nullptr); }; } VDeleter(const VDeleter& device, std::function deletef) { this->deleter = [&device, deletef](T obj) { deletef(device, obj, nullptr); }; } ~VDeleter() { cleanup(); } const T* operator &() const { return &object; } T* replace() { cleanup(); return &object; } operator T() const { return object; } void operator=(T rhs) { if (rhs != object) { cleanup(); object = rhs; } } template bool operator==(V rhs) { return object == T(rhs); } private: T object{VK_NULL_HANDLE}; std::function deleter; void cleanup() { if (object != VK_NULL_HANDLE) { deleter(object); } object = VK_NULL_HANDLE; } }; class HelloTriangleApplication { public: void run() { initWindow(); initVulkan(); mainLoop(); } private: GLFWwindow* window; VDeleter instance{vkDestroyInstance}; VDeleter callback{instance, DestroyDebugReportCallbackEXT}; 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(); setupDebugCallback(); } void mainLoop() { while (!glfwWindowShouldClose(window)) { glfwPollEvents(); } } void createInstance() { if (enableValidationLayers && !checkValidationLayerSupport()) { throw std::runtime_error("validation layers 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; auto extensions = getRequiredExtensions(); createInfo.enabledExtensionCount = extensions.size(); createInfo.ppEnabledExtensionNames = extensions.data(); if (enableValidationLayers) { createInfo.enabledLayerCount = validationLayers.size(); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } void setupDebugCallback() { if (!enableValidationLayers) return; VkDebugReportCallbackCreateInfoEXT createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT; createInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT; createInfo.pfnCallback = debugCallback; if (CreateDebugReportCallbackEXT(instance, &createInfo, nullptr, callback.replace()) != VK_SUCCESS) { throw std::runtime_error("failed to set up debug callback!"); } } std::vector getRequiredExtensions() { std::vector extensions; unsigned int glfwExtensionCount = 0; const char** glfwExtensions; glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); for (unsigned int i = 0; i < glfwExtensionCount; i++) { extensions.push_back(glfwExtensions[i]); } if (enableValidationLayers) { extensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); } return extensions; } 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; } static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t obj, size_t location, int32_t code, const char* layerPrefix, const char* msg, void* userData) { std::cerr << "validation layer: " << msg << std::endl; return VK_FALSE; } }; int main() { HelloTriangleApplication app; try { app.run(); } catch (const std::runtime_error& e) { std::cerr << e.what() << std::endl; return EXIT_FAILURE; } return EXIT_SUCCESS; }