c++xcodemacosvulkanvalidation-layers

Vulkan MacOS- Cannot setup Debug Messenger


I am following the tutorial https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Validation_layers

auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");

"func" returns nullptr in the CreateDebugUtilsMessengerEXT function. The Vulkan Instance is created successfully before the function to set up the debug messenger is called. I am using Xcode. I have set the environment variable VK_LOADER_DEBUG to all, but there is no output on what is causing the issue.

Full Code

#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>

#include <iostream>
#include <stdexcept>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <cstdlib>
#include <unistd.h>

const std::vector<const char*> validationLayers={"VK_LAYER_KHRONOS_validation"};
#ifdef NDEUBG
const bool enableValidationLayers=false;
#else
const bool enableValidationLayers=true;
#endif

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);
    }
}

class Application{
public:
void run(){
    initWindow();
    initVulkan();
    mainLoop();
    cleanUp();
    
}
private:
    GLFWwindow* window;
    VkInstance instanceVK;
    VkDebugUtilsMessengerEXT debugMessenger;
    void initWindow(){
        glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
        glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
        const uint32_t HEIGHT=600;
        const uint32_t WIDTH=800;
        window=glfwCreateWindow(WIDTH, HEIGHT, "VULKAN!", nullptr, nullptr);
        
        
    }
    void initVulkan(){
        createInstance();
        setupDebugMessenger();
        
    }
    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 setupDebugMessenger(){
        if(!enableValidationLayers) return;
        VkDebugUtilsMessengerCreateInfoEXT createInfo;
        populateDebugMessengerCreateInfo(createInfo);
        if (CreateDebugUtilsMessengerEXT(instanceVK, &createInfo, nullptr, &debugMessenger) != VK_SUCCESS) {
            throw std::runtime_error("failed to set up debug messenger!");
        }
        
    };
    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="Testing";
        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) {
                std::cout<<"apinspifnsfponasof\n\n\n\n\n\n\n\n\n\n";
                createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
                createInfo.ppEnabledLayerNames = validationLayers.data();

                populateDebugMessengerCreateInfo(debugCreateInfo);
                createInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*) &debugCreateInfo;
            } else {
                createInfo.enabledLayerCount = 0;

                createInfo.pNext = nullptr;
            }
        
        uint32_t glfwExtensionCount = 0;
        const char** glfwExtensions;

        glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
        createInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
        if(enableValidationLayers){
            createInfo.enabledLayerCount=static_cast<uint32_t>(validationLayers.size());
            createInfo.ppEnabledLayerNames = validationLayers.data();
        } else {
                createInfo.enabledLayerCount = 0;
            }
    
        uint32_t extensionCount = 0;
        vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
        std::vector<VkExtensionProperties> extensions(extensionCount);
        vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
        std::cout << "available extensions:\n";

        for (const auto& extension : extensions) {
            std::cout << '\t' << extension.extensionName << '\n';
        }
        // Make useable on MACOS
        std::vector<const char*> instanceExtensions(glfwExtensionCount);
        memcpy(instanceExtensions.data(), glfwExtensions, sizeof(const char*) * glfwExtensionCount);
        instanceExtensions.push_back("VK_KHR_portability_enumeration");
        createInfo.enabledExtensionCount = static_cast<uint32_t>(instanceExtensions.size());
        createInfo.ppEnabledExtensionNames = instanceExtensions.data();
        
        VkResult result= vkCreateInstance(&createInfo, nullptr, &instanceVK);
        if(result!= VK_SUCCESS){
            std::cout<<result;
            throw std::runtime_error("Falied to create Instance");
        }else{
            std::cout<<"SUCCESS";
        }
        for (const auto& extension : extensions) {
            std::cout << '\t' << extension.extensionName << '\n';
        }
    }
    void mainLoop(){
        while (!glfwWindowShouldClose(window)) {
            glfwPollEvents();
  
        }
    }
    void cleanUp(){
        if (enableValidationLayers) {
            DestroyDebugUtilsMessengerEXT(instanceVK, debugMessenger, nullptr);
        }
        vkDestroyInstance(instanceVK, nullptr);
        glfwDestroyWindow(window);

        glfwTerminate();

    };
    bool checkValidationLayerSupport(){
        uint32_t layerCount;
        vkEnumerateInstanceLayerProperties(&layerCount,nullptr);
        std::vector<VkLayerProperties> avaiableLayers(layerCount);
        vkEnumerateInstanceLayerProperties(&layerCount, avaiableLayers.data());
        for(const char* layerName:validationLayers){
            bool layerFound=false;
            for(const auto& layerProperties:avaiableLayers){
                if(strcmp(layerName, layerProperties.layerName)==0){
                    layerFound=true;
                    break;
                }
            }
            if(!layerFound){
                return false;
            }
        };
        return true;
        
    };
    std::vector<const char*> getRequiredExtensions() {
        uint32_t glfwExtensionCount = 0;
        const char** glfwExtensions;
        glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);

        std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);

        if (enableValidationLayers) {
            extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
        }

        return extensions;
    }
    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(){
    Application app;
    try {
        app.run();
    } catch (const std::exception& e) {
        std::cout<<"here";
        std::cerr << e.what() << std::endl;
        return EXIT_FAILURE;
    }
};

Solution

  • You have not enabled the VK_EXT_debug_utils extension beforehand:

    std::vector<const char*> instanceExtensions(glfwExtensionCount);
    memcpy(instanceExtensions.data(), glfwExtensions, sizeof(const char*) * glfwExtensionCount);
    instanceExtensions.push_back("VK_KHR_portability_enumeration");
    createInfo.enabledExtensionCount = static_cast<uint32_t>(instanceExtensions.size());
    createInfo.ppEnabledExtensionNames = instanceExtensions.data();
    

    Your getRequiredExtensions() which adds the extension remains uncalled.


    Just a heads up for next time you submit question to StackOverflow. Always post a minimal complete example, not your whole codebase as is. The reason is 90 % of times you find the problem yourself by the act of forming a minimal example itself, so you save other people time. And then the example ends up as short as possible to expose the problem, so you save them time a second time when they read it. In your case it can literally be just something as simple as:

    int main(){
        vkCreateInstance();
        pvkCreateDebugUtilsMessengerEXT = vkGetProcAddr();
        assert(pvkCreateDebugUtilsMessengerEXT);
    }