Search code examples
c++macoscocoavulkanmoltenvk

How to call vkCreateMacOSSurfaceMVK from Vulkan library?


I try to create a small app based on Vulkan v1.3.275.0 (and MoltenVK driver for macOS).

I successfully bundle my app into *.app with recommended Vulkan structure for macOS. My app opens a window using metal-cpp library and creates a Vulkan instance using MoltenVK driver.

However, now I need to create a surface for Vulkan device and here I hit troubles.

As I got to create a surface on macOS, I need to call vkCreateMacOSSurfaceMVK() (ref) from #include <vulkan/vulkan_macos.h> but when I try to include this header my app crashes with errors:

[build] /Projects/my/third-party/vulkan/include/vulkan/vulkan_macos.h:26:9: error: unknown type name 'VkFlags'
[build] typedef VkFlags VkMacOSSurfaceCreateFlagsMVK;
[build]         ^
[build] /Projects/my/third-party/vulkan/include/vulkan/vulkan_macos.h:28:5: error: unknown type name 'VkStructureType'
[build]     VkStructureType                 sType;
[build]     ^
[build] /Projects/my/third-party/vulkan/include/vulkan/vulkan_macos.h:34:19: error: unknown type name 'VKAPI_PTR'
[build] typedef VkResult (VKAPI_PTR *PFN_vkCreateMacOSSurfaceMVK)(VkInstance instance, const VkMacOSSurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
[build]                   ^
[build] /Projects/my/third-party/vulkan/include/vulkan/vulkan_macos.h:34:59: error: unknown type name 'VkInstance'
[build] typedef VkResult (VKAPI_PTR *PFN_vkCreateMacOSSurfaceMVK)(VkInstance instance, const VkMacOSSurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);

And if to open this header there are really no declarations or other includes for these types:

#ifndef VULKAN_MACOS_H_
#define VULKAN_MACOS_H_ 1

/*
** Copyright 2015-2024 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/

/*
** This header is generated from the Khronos Vulkan XML API Registry.
**
*/


#ifdef __cplusplus
extern "C" {
#endif



// VK_MVK_macos_surface is a preprocessor guard. Do not pass it to API calls.
#define VK_MVK_macos_surface 1
#define VK_MVK_MACOS_SURFACE_SPEC_VERSION 3
#define VK_MVK_MACOS_SURFACE_EXTENSION_NAME "VK_MVK_macos_surface"
typedef VkFlags VkMacOSSurfaceCreateFlagsMVK;
typedef struct VkMacOSSurfaceCreateInfoMVK {
    VkStructureType                 sType;
    const void*                     pNext;
    VkMacOSSurfaceCreateFlagsMVK    flags;
    const void*                     pView;
} VkMacOSSurfaceCreateInfoMVK;

typedef VkResult (VKAPI_PTR *PFN_vkCreateMacOSSurfaceMVK)(VkInstance instance, const VkMacOSSurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);

#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR VkResult VKAPI_CALL vkCreateMacOSSurfaceMVK(
    VkInstance                                  instance,
    const VkMacOSSurfaceCreateInfoMVK*          pCreateInfo,
    const VkAllocationCallbacks*                pAllocator,
    VkSurfaceKHR*                               pSurface);
#endif

#ifdef __cplusplus
}
#endif

#endif

I found yet one header <vulkan/vulkan_metal.h> but it didn't help too.

What's a right way to create a Metal surface for Vulkan on macOS?

P.S. I know there are GLFW and similar libraries but I just want to dig into clean Cocoa and Vulkan (MoltenVK) to understand how to connect them manually.

P.P.S. I am not sure if it's right to call AppKit, MetalKit and other frameworks a part of Cocoa, fix me if I am wrong.


Solution

  • This is the combination of the two following questions and their answers (one of them being mine):

    TL;DR:

    • As for all Vulkan extensions, function pointers must be loaded dynamically using vkGetInstanceProcAddr or vkGetDeviceProcAddr. Note that you will need to specify the corresponding extensions upon instance creation in VkInstanceCreateInfo::ppEnabledExtensionNames. You can also use some libraries like Volk that exist for this purpose.

    • Headers such as vulkan_metal.h or vulkan_win32.h and their siblings require the contents of vulkan_core.h, that must be included before it. Though the vulkan.h header does this for you (provided you added the correct #define VK_USE_PLATFORM_XXX), it also #includes potentially-heavy platform-specific headers, such as <windows.h> on Windows, or <X11/Xlib.h> on Linux with X11. This isn't good for compile times. As far as I know, a few forward-declaration suffice, so you may build your own vulkan.h that may look like this instead:

    #ifndef YOUR_VULKAN_H
    #define YOUR_VULKAN_H
    
    #include <vulkan/vulkan_core.h>
    
    #if defined(VK_USE_PLATFORM_XXXX)
    
    // Some forward declarations
    
    #include <vulkan/the_platform_header.h>
    
    #endif // #if defined(VK_USE_PLATFORM_XXXX)
    
    #endif // YOUR_VULKAN_H
    

    Note: this is what Volk does.