[Feat] (MG_Test/Backend/DirectVulkan): add support on macOS

This commit is contained in:
2026-02-15 08:50:53 +08:00
parent 92cdcd952b
commit 8a66b0a542
3 changed files with 90 additions and 4 deletions
@@ -450,11 +450,18 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VK_KHR_ANDROID_SURFACE_EXTENSION_NAME
#elif defined VK_USE_PLATFORM_WIN32_KHR
VK_KHR_WIN32_SURFACE_EXTENSION_NAME
#elif defined VK_USE_PLATFORM_METAL_EXT
VK_EXT_METAL_SURFACE_EXTENSION_NAME
#else
#warning "VulkanContext::CreateInstance: VK_KHR_*_surface extension not defined on this platform"
#endif
}; // TODO: support more platforms
#if defined(VK_USE_PLATFORM_METAL_EXT)
exts.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
instanceInfo.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
#endif
if (m_validationLayersEnabled) {
exts.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
}
@@ -740,8 +747,31 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} else {
deviceCreateInfo.enabledLayerCount = 0;
}
deviceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(std::size(s_deviceExtensionNames));
deviceCreateInfo.ppEnabledExtensionNames = s_deviceExtensionNames;
Vector<const char*> enabledDeviceExtensions;
enabledDeviceExtensions.reserve(std::size(s_deviceExtensionNames) + 1);
for (const char* extensionName : s_deviceExtensionNames) {
enabledDeviceExtensions.push_back(extensionName);
}
#ifdef VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME
Uint32 extensionCount = 0;
VK_VERIFY(vkEnumerateDeviceExtensionProperties(m_physicalDevice.handle, nullptr, &extensionCount, nullptr));
Vector<VkExtensionProperties> availableExtensions(extensionCount);
VK_VERIFY(vkEnumerateDeviceExtensionProperties(
m_physicalDevice.handle, nullptr, &extensionCount, availableExtensions.data()));
for (const auto& extension : availableExtensions) {
if (strcmp(extension.extensionName, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME) == 0) {
enabledDeviceExtensions.push_back(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME);
MGLOG_I("Enabled optional device extension: %s", VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME);
break;
}
}
#endif
deviceCreateInfo.enabledExtensionCount = static_cast<Uint32>(enabledDeviceExtensions.size());
deviceCreateInfo.ppEnabledExtensionNames = enabledDeviceExtensions.data();
VK_VERIFY(vkCreateDevice(m_physicalDevice.handle, &deviceCreateInfo, nullptr, &m_device), "vkCreateDevice");
MGLOG_I("Logical device created.");
@@ -1215,6 +1245,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkWin32SurfaceCreateInfoKHR sci{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR};
sci.hwnd = hwnd;
VK_VERIFY(vkCreateWin32SurfaceKHR(m_instance, &sci, nullptr, &m_surface), "vkCreateWin32SurfaceKHR failed");
#elif defined VK_USE_PLATFORM_METAL_EXT
MOBILEGL_ASSERT(m_window, "CAMetalLayer is null");
VkMetalSurfaceCreateInfoEXT sci{VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT};
sci.pLayer = reinterpret_cast<const void*>(m_window);
VK_VERIFY(vkCreateMetalSurfaceEXT(m_instance, &sci, nullptr, &m_surface), "vkCreateMetalSurfaceEXT failed");
#else
//#warning "VulkanRenderer::Initialize called on a platform which is not supported yet"
MGLOG_W("VulkanRenderer::Initialize called on a platform which is not supported yet"); // TODO: support more
@@ -46,8 +46,15 @@ TEST(DirectVulkanSanity, WindowCreation) {
#include <EGL/egl.h>
#ifdef _WIN32
#define GLFW_EXPOSE_NATIVE_WIN32
#elif defined(__APPLE__)
#define GLFW_EXPOSE_NATIVE_COCOA
#endif
#include <GLFW/glfw3native.h>
#ifdef __APPLE__
#include <objc/message.h>
#include <objc/objc.h>
#include <objc/runtime.h>
#endif
TEST(DirectVulkanSanity, ContextCreation) {
glfwInit();
@@ -67,8 +74,26 @@ TEST(DirectVulkanSanity, ContextCreation) {
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = glfwCreateWindow(800, 600, "MobileGL ContextCreation", nullptr, nullptr);
EGLNativeWindowType nativewindow = nullptr;
#ifdef _WIN32
EGLNativeWindowType nativewindow = glfwGetWin32Window(window);
nativewindow = glfwGetWin32Window(window);
#elif defined(__APPLE__)
void* cocoaWindow = glfwGetCocoaWindow(window);
ASSERT_NE(cocoaWindow, nullptr);
auto msgSendObj = reinterpret_cast<id (*)(id, SEL)>(objc_msgSend);
auto msgSendVoidObj = reinterpret_cast<void (*)(id, SEL, id)>(objc_msgSend);
auto msgSendVoidBool = reinterpret_cast<void (*)(id, SEL, bool)>(objc_msgSend);
id contentView = msgSendObj(static_cast<id>(cocoaWindow), sel_registerName("contentView"));
ASSERT_NE(contentView, nullptr);
msgSendVoidBool(contentView, sel_registerName("setWantsLayer:"), true);
id metalLayerClass = reinterpret_cast<id>(objc_getClass("CAMetalLayer"));
ASSERT_NE(metalLayerClass, nullptr);
id metalLayer = msgSendObj(metalLayerClass, sel_registerName("layer"));
ASSERT_NE(metalLayer, nullptr);
msgSendVoidObj(contentView, sel_registerName("setLayer:"), metalLayer);
nativewindow = reinterpret_cast<EGLNativeWindowType>(metalLayer);
#endif
EGLSurface surface = eglCreateWindowSurface(display, config, nativewindow, nullptr);
eglMakeCurrent(display, surface, surface, context);
@@ -16,11 +16,18 @@
#include <EGL/egl.h>
#ifdef _WIN32
#define GLFW_EXPOSE_NATIVE_WIN32
#elif defined(__APPLE__)
#define GLFW_EXPOSE_NATIVE_COCOA
#endif
#include "MG_Backend/DirectVulkan/DirectVulkan.h"
#include "MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h"
#include <GLFW/glfw3native.h>
#ifdef __APPLE__
#include <objc/message.h>
#include <objc/objc.h>
#include <objc/runtime.h>
#endif
int main() {
glfwInit();
@@ -41,8 +48,26 @@ int main() {
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = glfwCreateWindow(800, 600, "MobileGL ContextCreation", nullptr, nullptr);
EGLNativeWindowType nativewindow = nullptr;
#ifdef _WIN32
EGLNativeWindowType nativewindow = glfwGetWin32Window(window);
nativewindow = glfwGetWin32Window(window);
#elif defined(__APPLE__)
void* cocoaWindow = glfwGetCocoaWindow(window);
MOBILEGL_ASSERT(cocoaWindow, "glfwGetCocoaWindow returned null");
auto msgSendObj = reinterpret_cast<id (*)(id, SEL)>(objc_msgSend);
auto msgSendVoidObj = reinterpret_cast<void (*)(id, SEL, id)>(objc_msgSend);
auto msgSendVoidBool = reinterpret_cast<void (*)(id, SEL, bool)>(objc_msgSend);
id contentView = msgSendObj(static_cast<id>(cocoaWindow), sel_registerName("contentView"));
MOBILEGL_ASSERT(contentView, "Failed to query NSWindow.contentView");
msgSendVoidBool(contentView, sel_registerName("setWantsLayer:"), true);
id metalLayerClass = reinterpret_cast<id>(objc_getClass("CAMetalLayer"));
MOBILEGL_ASSERT(metalLayerClass, "Failed to lookup CAMetalLayer class");
id metalLayer = msgSendObj(metalLayerClass, sel_registerName("layer"));
MOBILEGL_ASSERT(metalLayer, "Failed to create CAMetalLayer");
msgSendVoidObj(contentView, sel_registerName("setLayer:"), metalLayer);
nativewindow = reinterpret_cast<EGLNativeWindowType>(metalLayer);
#endif
EGLSurface surface = eglCreateWindowSurface(display, config, nativewindow, nullptr);
eglMakeCurrent(display, surface, surface, context);