VulkanRenderer: implement metal view

The metal view backing the MoltenVK compatibility wrapper is written in
Obj-C.

It would have been possible to use the Objective-C runtime in C++ but
the code is less performant (the symbol binding is done at first use
instead of the beginning of the program) and actually harder to get
right.

Note that MoltenVK is not linked to the loader, so the libMoltenVK.dylib
object must be available for loading.
This commit is contained in:
Alexandre Janniaux 2022-03-20 20:12:40 +01:00 committed by Jérôme Leclercq
parent 162456c5b6
commit f146661a76
8 changed files with 81 additions and 0 deletions

View File

@ -34,6 +34,10 @@
#include <vulkan/vulkan_xcb.h> #include <vulkan/vulkan_xcb.h>
#endif #endif
#ifdef VK_USE_PLATFORM_METAL_EXT
#include <vulkan/vulkan_metal.h>
#endif
#ifdef VK_USE_PLATFORM_XLIB_KHR #ifdef VK_USE_PLATFORM_XLIB_KHR
typedef struct _XDisplay Display; typedef struct _XDisplay Display;
typedef unsigned long XID; typedef unsigned long XID;

View File

@ -97,6 +97,12 @@ NAZARA_VULKANRENDERER_INSTANCE_EXT_BEGIN(VK_KHR_win32_surface)
NAZARA_VULKANRENDERER_INSTANCE_EXT_END() NAZARA_VULKANRENDERER_INSTANCE_EXT_END()
#endif #endif
#ifdef VK_USE_PLATFORM_METAL_EXT
NAZARA_VULKANRENDERER_INSTANCE_EXT_BEGIN(VK_EXT_metal_surface)
NAZARA_VULKANRENDERER_INSTANCE_FUNCTION(vkCreateMetalSurfaceEXT)
NAZARA_VULKANRENDERER_INSTANCE_EXT_END()
#endif
#undef NAZARA_VULKANRENDERER_INSTANCE_CORE_EXT_FUNCTION #undef NAZARA_VULKANRENDERER_INSTANCE_CORE_EXT_FUNCTION
#undef NAZARA_VULKANRENDERER_INSTANCE_EXT_BEGIN #undef NAZARA_VULKANRENDERER_INSTANCE_EXT_BEGIN
#undef NAZARA_VULKANRENDERER_INSTANCE_EXT_END #undef NAZARA_VULKANRENDERER_INSTANCE_EXT_END

View File

@ -12,6 +12,11 @@
#include <Nazara/VulkanRenderer/Wrapper/Instance.hpp> #include <Nazara/VulkanRenderer/Wrapper/Instance.hpp>
#include <Nazara/VulkanRenderer/Wrapper/Loader.hpp> #include <Nazara/VulkanRenderer/Wrapper/Loader.hpp>
#ifdef VK_USE_PLATFORM_METAL_EXT
#include <objc/runtime.h>
#include <vulkan/vulkan_metal.h>
#endif
namespace Nz namespace Nz
{ {
namespace Vk namespace Vk
@ -54,6 +59,11 @@ namespace Nz
inline bool Create(HINSTANCE instance, HWND handle, VkWin32SurfaceCreateFlagsKHR flags = 0, const VkAllocationCallbacks* allocator = nullptr); inline bool Create(HINSTANCE instance, HWND handle, VkWin32SurfaceCreateFlagsKHR flags = 0, const VkAllocationCallbacks* allocator = nullptr);
#endif #endif
#ifdef VK_USE_PLATFORM_METAL_EXT
inline bool Create(const VkMetalSurfaceCreateInfoEXT& createInfo, const VkAllocationCallbacks* allocator = nullptr);
inline bool Create(id layer, const VkAllocationCallbacks* allocator = nullptr);
#endif
inline void Destroy(); inline void Destroy();
bool GetCapabilities(VkPhysicalDevice physicalDevice, VkSurfaceCapabilitiesKHR* surfaceCapabilities) const; bool GetCapabilities(VkPhysicalDevice physicalDevice, VkSurfaceCapabilitiesKHR* surfaceCapabilities) const;

View File

@ -140,6 +140,27 @@ namespace Nz
} }
#endif #endif
#ifdef VK_USE_PLATFORM_METAL_EXT
inline bool Surface::Create(const VkMetalSurfaceCreateInfoEXT& createInfo, const VkAllocationCallbacks* allocator)
{
m_lastErrorCode = m_instance.vkCreateMetalSurfaceEXT(m_instance, &createInfo, allocator, &m_surface);
return Create(allocator);
}
inline bool Surface::Create(id layer, const VkAllocationCallbacks* allocator)
{
VkMetalSurfaceCreateInfoEXT createInfo =
{
VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT,
nullptr,
0,
layer
};
return Create(createInfo, allocator);
}
#endif
inline void Surface::Destroy() inline void Surface::Destroy()
{ {
if (m_surface != VK_NULL_HANDLE) if (m_surface != VK_NULL_HANDLE)
@ -262,6 +283,10 @@ namespace Nz
return true; return true;
#endif #endif
#ifdef VK_USE_PLATFORM_METAL_EXT
if (instance.IsExtensionLoaded(VK_EXT_METAL_SURFACE_EXTENSION_NAME))
return true;
#endif
return false; return false;
} }

View File

@ -244,6 +244,10 @@ namespace Nz
enabledExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); enabledExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#endif #endif
#ifdef VK_USE_PLATFORM_METAL_EXT
enabledExtensions.push_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME);
#endif
if (availableExtensions.count(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) if (availableExtensions.count(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME))
enabledExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); enabledExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);

View File

@ -7,8 +7,17 @@
#include <vulkan/vk_sdk_platform.h> #include <vulkan/vk_sdk_platform.h>
#include <Nazara/VulkanRenderer/Debug.hpp> #include <Nazara/VulkanRenderer/Debug.hpp>
#ifdef VK_USE_PLATFORM_METAL_EXT
#include <objc/runtime.h>
#include <vulkan/vulkan_metal.h>
#endif
namespace Nz namespace Nz
{ {
#ifdef VK_USE_PLATFORM_METAL_EXT
id CreateAndAttachMetalLayer(void* window);
#endif
VulkanSurface::VulkanSurface() : VulkanSurface::VulkanSurface() :
m_surface(Vulkan::GetInstance()) m_surface(Vulkan::GetInstance())
{ {
@ -60,6 +69,11 @@ namespace Nz
} }
} }
#elif defined(NAZARA_PLATFORM_MACOS) #elif defined(NAZARA_PLATFORM_MACOS)
{
NazaraAssert(handle.type == WindowBackend::Cocoa, "expected cocoa window");
id layer = CreateAndAttachMetalLayer(handle.cocoa.window);
success = m_surface.Create(layer);
}
#else #else
#error This OS is not supported by Vulkan #error This OS is not supported by Vulkan
#endif #endif

View File

@ -0,0 +1,16 @@
#import <AppKit/NSView.h>
#import <AppKit/NSWindow.h>
#import <QuartzCore/CAMetalLayer.h>
namespace Nz
{
id CreateAndAttachMetalLayer(void* window) {
NSWindow* obj = (__bridge NSWindow*)window;
NSView* view = [[NSView alloc] initWithFrame:obj.frame];
[view setLayer:[CAMetalLayer layer]];
[view setWantsLayer:YES];
view.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
[obj.contentView addSubview:view];
return view.layer;
}
}

View File

@ -103,6 +103,8 @@ local modules = {
add_defines("VK_USE_PLATFORM_WAYLAND_KHR") add_defines("VK_USE_PLATFORM_WAYLAND_KHR")
elseif is_plat("macosx") then elseif is_plat("macosx") then
add_defines("VK_USE_PLATFORM_METAL_EXT") add_defines("VK_USE_PLATFORM_METAL_EXT")
add_files("src/Nazara/VulkanRenderer/**.mm")
add_frameworks("quartzcore", "AppKit")
end end
end end
}, },