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>
#endif
#ifdef VK_USE_PLATFORM_METAL_EXT
#include <vulkan/vulkan_metal.h>
#endif
#ifdef VK_USE_PLATFORM_XLIB_KHR
typedef struct _XDisplay Display;
typedef unsigned long XID;

View File

@ -97,6 +97,12 @@ NAZARA_VULKANRENDERER_INSTANCE_EXT_BEGIN(VK_KHR_win32_surface)
NAZARA_VULKANRENDERER_INSTANCE_EXT_END()
#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_EXT_BEGIN
#undef NAZARA_VULKANRENDERER_INSTANCE_EXT_END

View File

@ -12,6 +12,11 @@
#include <Nazara/VulkanRenderer/Wrapper/Instance.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 Vk
@ -54,6 +59,11 @@ namespace Nz
inline bool Create(HINSTANCE instance, HWND handle, VkWin32SurfaceCreateFlagsKHR flags = 0, const VkAllocationCallbacks* allocator = nullptr);
#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();
bool GetCapabilities(VkPhysicalDevice physicalDevice, VkSurfaceCapabilitiesKHR* surfaceCapabilities) const;

View File

@ -140,6 +140,27 @@ namespace Nz
}
#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()
{
if (m_surface != VK_NULL_HANDLE)
@ -262,6 +283,10 @@ namespace Nz
return true;
#endif
#ifdef VK_USE_PLATFORM_METAL_EXT
if (instance.IsExtensionLoaded(VK_EXT_METAL_SURFACE_EXTENSION_NAME))
return true;
#endif
return false;
}

View File

@ -244,6 +244,10 @@ namespace Nz
enabledExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#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))
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 <Nazara/VulkanRenderer/Debug.hpp>
#ifdef VK_USE_PLATFORM_METAL_EXT
#include <objc/runtime.h>
#include <vulkan/vulkan_metal.h>
#endif
namespace Nz
{
#ifdef VK_USE_PLATFORM_METAL_EXT
id CreateAndAttachMetalLayer(void* window);
#endif
VulkanSurface::VulkanSurface() :
m_surface(Vulkan::GetInstance())
{
@ -60,6 +69,11 @@ namespace Nz
}
}
#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
#error This OS is not supported by Vulkan
#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")
elseif is_plat("macosx") then
add_defines("VK_USE_PLATFORM_METAL_EXT")
add_files("src/Nazara/VulkanRenderer/**.mm")
add_frameworks("quartzcore", "AppKit")
end
end
},