我尝试创建一个基于 Vulkan v1.3.275.0(以及适用于 macOS 的 MoltenVK 驱动程序)的小应用程序。
我成功地将我的应用程序捆绑到
*.app
中,并使用推荐的 macOS Vulkan 结构。我的应用程序使用 metal-cpp 库打开一个窗口,并使用 MoltenVK 驱动程序创建一个 Vulkan 实例。
但是,现在我需要为 Vulkan 设备创建一个表面,但在这里我遇到了麻烦。
当我要在 macOS 上创建一个 Surface 时,我需要从
vkCreateMacOSSurfaceMVK()
调用 #include <vulkan/vulkan_macos.h>
(ref),但是当我尝试包含此标头时,我的应用程序崩溃并出现错误:
[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);
如果要打开此标头,这些类型实际上没有声明或其他包含:
#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
我发现了一个标题
<vulkan/vulkan_metal.h>
,但也没有帮助。
在 macOS 上为 Vulkan 创建金属表面的正确方法是什么?
P.S. 我知道有
GLFW
和类似的库,但我只想深入研究干净的 Cocoa 和 Vulkan (MoltenVK) 以了解如何手动连接它们。
P.P.S. 我不确定将 AppKit、MetalKit 和其他框架称为 Cocoa 的一部分是否正确,如果我错了请纠正我。
研究了GLFW的源代码我终于知道了如何调用
vkCreateMacOSSurfaceMVK(...)
。
我们需要打开两个扩展中的一个(取决于版本):
#define VK_EXT_METAL_SURFACE_NAME "VK_EXT_metal_surface"
#define VK_MVK_MACOS_SURFACE_NAME "VK_MVK_macos_surface"
std::vector<const char*> ext_names = {
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
VK_EXT_METAL_SURFACE_NAME,
VK_MVK_MACOS_SURFACE_NAME,
// VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
};
// initialize the VkInstanceCreateInfo structure
VkInstanceCreateInfo inst_info = {};
inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
inst_info.pNext = NULL;
inst_info.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
inst_info.pApplicationInfo = &app_info;
inst_info.enabledExtensionCount = static_cast<uint32_t>(ext_names.size());;
inst_info.ppEnabledExtensionNames = ext_names.data();
inst_info.enabledLayerCount = 0;
inst_info.ppEnabledLayerNames = NULL;
需要为这些扩展中的函数定义原型:
// A little changed code of GLFW
typedef VkFlags VkMacOSSurfaceCreateFlagsMVK;
typedef VkFlags VkMetalSurfaceCreateFlagsEXT;
typedef struct VkMacOSSurfaceCreateInfoMVK
{
VkStructureType sType;
const void* pNext;
VkMacOSSurfaceCreateFlagsMVK flags;
const void* pView;
} VkMacOSSurfaceCreateInfoMVK;
typedef struct VkMetalSurfaceCreateInfoEXT
{
VkStructureType sType;
const void* pNext;
VkMetalSurfaceCreateFlagsEXT flags;
const void* pLayer;
} VkMetalSurfaceCreateInfoEXT;
typedef VkResult (*PFN_vkCreateMacOSSurfaceMVK)(VkInstance, const VkMacOSSurfaceCreateInfoMVK*, const VkAllocationCallbacks*, VkSurfaceKHR*);
typedef VkResult (*PFN_vkCreateMetalSurfaceEXT)(VkInstance, const VkMetalSurfaceCreateInfoEXT*, const VkAllocationCallbacks*, VkSurfaceKHR*);
第三步,我们需要从这些函数中找到任意一个的地址:
#define VK_CREATE_MACOS_SURFACE_MVK "vkCreateMacOSSurfaceMVK"
#define VK_CREATE_METAL_SURFACE_EXT "vkCreateMetalSurfaceEXT"
// In my case it's `vkCreateMacOSSurfaceMVK`, so I will call this variant
auto address = (PFN_vkCreateMacOSSurfaceMVK)vkGetInstanceProcAddr(instance, VK_CREATE_MACOS_SURFACE_MVK);
利润!
P.S. 上面的所有代码大部分都是 GLFW 的复制粘贴,因此您可以通过研究 GLFW 的源代码来了解更多信息。不幸的是,我是 C++ 新手,如果你也是,我希望这个代码片段能够节省你几个小时的时间和几杯咖啡。