Vulkan surface won't create with App Bundle on macOS

I’m having trouble creating a Vulkan surface from a bundle application in my Xcode project . But everything works just fine if i make the project a Command Line Tool using the exact same code and library files.

GLFW outputs this error -> Cocoa: Vulkan instance missing VK_EXT_metal_surface extension

I don’t think the extension is actually missing since glfwGetRequiredInstanceExtensions returns VK_KHR_surface and VK_EXT_metal_surface and the instance do get created without an error with those extensions added.

This is what I have:
GLFW 3.4 dynamic library
Vulkan SDK 1.2.154
Xcode 12.0.1
macOS 10.15.6
GPU 1: AMD Radeon Pro 5600M 8 GB
GPU 2: Intel UHD Graphics 630 1536 MB

The code:

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

void error_callback(int error, const char* description)
{
    std::cout << "GLFW Error -> " << description << std::endl;
}

int main(int argc, const char * argv[]) {

    GLFWwindow*     window;
    VkInstance      instance;
    VkSurfaceKHR    surface;

    if (glfwInit() == GLFW_FALSE) std::cout << "Failed initializing GLFW!" << std::endl;
    else {
        
        // Set error callback
        glfwSetErrorCallback(error_callback);
        
        // Do NOT create an OpenGL context
        glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
        
        // Create window
        window = glfwCreateWindow(720, 480, "Vulkan Testing", nullptr, nullptr);
        
        if (glfwVulkanSupported() == GLFW_FALSE) std::cout << "Vulkan not supported!" << std::endl;
        else {
            // Required extensions
            uint32_t glfwExtensionCount = 0;
            const char** glfwExtensions;
            glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);

            // Supported extensions
            uint32_t vulkanExtensionCount = 0;
            vkEnumerateInstanceExtensionProperties(nullptr, &vulkanExtensionCount, nullptr);
            std::vector<VkExtensionProperties> vulkanExtensions(vulkanExtensionCount);
            vkEnumerateInstanceExtensionProperties(nullptr, &vulkanExtensionCount, vulkanExtensions.data());

            // Check if requirements is supported
            std::string glfwExtensionName;
            std::string vulkanExtensionName;
            bool extensionSupported;
            for (uint32_t i = 0; i < glfwExtensionCount; ++i)
            {
                glfwExtensionName = glfwExtensions[i];
                extensionSupported = false;
                for (const auto& vulkanExtension : vulkanExtensions) {
                    vulkanExtensionName = vulkanExtension.extensionName;
                    if (glfwExtensionName == vulkanExtensionName) {
                        extensionSupported = true;
                        break;
                    }
                }
                if (!extensionSupported) std::cout << glfwExtensionName << " is not supported!" << std::endl;
            }

            // Create instance
            VkInstanceCreateInfo createInfo{};
            createInfo.enabledLayerCount = 0;
            createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
            createInfo.enabledExtensionCount = glfwExtensionCount;
            createInfo.ppEnabledExtensionNames = glfwExtensions;
            if (int instanceResult = vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
                std::cout << "Failed to create instance! VkResult: " << instanceResult << std::endl;
                return 1;
            }
            
            // Create surface
            if (int surfaceResult = glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS) {
                std::cout << "Failed to create surface: VkResult: " << surfaceResult << std::endl;
                return 2;
            }
        }
    }
    
    // Main loop
    while (!glfwWindowShouldClose(window))
    {
        glfwPollEvents();
    }
    
    // Cleanup
    vkDestroyInstance(instance, nullptr);
    glfwDestroyWindow(window);
    glfwTerminate();
    
    // Exit
    return 0;
}

Debug Console Output with Bundle Application:
2020-10-22 21:21:23.496901+0200 VulkanApp[15690:985664] Metal API Validation Enabled
GLFW Error -> Cocoa: Vulkan instance missing VK_EXT_metal_surface extension
Failed to create surface: VkResult: 1

Debug Console Output with Command Line Tool:
2020-10-22 20:47:29.205902+0200 VulkanTerminal[15386:958569] Metal API Validation Enabled
Program ended with exit code: 0

Any suggestions on what i’m missing here?

Hi @JimmyWinberg,

Welcome to the GLFW forum!

I’m wondering if the Info.plist for your bundle contains something which causes a different environment from your working command line code. Indeed perhaps vkCreateInstance is using a different Vulkan library to glfwCreateWindowSurface somehow?

See the following lines for how GLFW loads the Vulkan libraries, perhaps there’s a way to check which path the library is loaded from for you in the command line and bundled version:

I don’t recall how to check loaded library paths on MacOS, but I would have thought that XCode can display this - this link has some information which could be handy:

You might find browsing these issues useful:


I likely don’t know enough about MacOS & Vulkan to help further, but do update this thread if you get any new information and I’ll see what I can do.

Cheers,

Doug.

I’ve set the environment variable DYLD_PRINT_LIBRARIES=1 in my Xcode products scheme and from what I could tell from the console output it gave me it did loading the right library.

But anyways I think you where right because what I tried then was to delete the alias libvulkan.1.dylib and renamed the library file libvulkan.1.2.154.dylib to be libvulkan.1.dylib. Then it all started to work… the surface was created so clearly something was wrong with the loading part as you suggested.

Thanks for the tip!