[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 VK_KHR_ANDROID_SURFACE_EXTENSION_NAME
#elif defined VK_USE_PLATFORM_WIN32_KHR #elif defined VK_USE_PLATFORM_WIN32_KHR
VK_KHR_WIN32_SURFACE_EXTENSION_NAME VK_KHR_WIN32_SURFACE_EXTENSION_NAME
#elif defined VK_USE_PLATFORM_METAL_EXT
VK_EXT_METAL_SURFACE_EXTENSION_NAME
#else #else
#warning "VulkanContext::CreateInstance: VK_KHR_*_surface extension not defined on this platform" #warning "VulkanContext::CreateInstance: VK_KHR_*_surface extension not defined on this platform"
#endif #endif
}; // TODO: support more platforms }; // 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) { if (m_validationLayersEnabled) {
exts.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); exts.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
} }
@@ -740,8 +747,31 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} else { } else {
deviceCreateInfo.enabledLayerCount = 0; 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"); VK_VERIFY(vkCreateDevice(m_physicalDevice.handle, &deviceCreateInfo, nullptr, &m_device), "vkCreateDevice");
MGLOG_I("Logical device created."); MGLOG_I("Logical device created.");
@@ -1215,6 +1245,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkWin32SurfaceCreateInfoKHR sci{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR}; VkWin32SurfaceCreateInfoKHR sci{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR};
sci.hwnd = hwnd; sci.hwnd = hwnd;
VK_VERIFY(vkCreateWin32SurfaceKHR(m_instance, &sci, nullptr, &m_surface), "vkCreateWin32SurfaceKHR failed"); 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 #else
//#warning "VulkanRenderer::Initialize called on a platform which is not supported yet" //#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 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> #include <EGL/egl.h>
#ifdef _WIN32 #ifdef _WIN32
#define GLFW_EXPOSE_NATIVE_WIN32 #define GLFW_EXPOSE_NATIVE_WIN32
#elif defined(__APPLE__)
#define GLFW_EXPOSE_NATIVE_COCOA
#endif #endif
#include <GLFW/glfw3native.h> #include <GLFW/glfw3native.h>
#ifdef __APPLE__
#include <objc/message.h>
#include <objc/objc.h>
#include <objc/runtime.h>
#endif
TEST(DirectVulkanSanity, ContextCreation) { TEST(DirectVulkanSanity, ContextCreation) {
glfwInit(); glfwInit();
@@ -67,8 +74,26 @@ TEST(DirectVulkanSanity, ContextCreation) {
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = glfwCreateWindow(800, 600, "MobileGL ContextCreation", nullptr, nullptr); GLFWwindow* window = glfwCreateWindow(800, 600, "MobileGL ContextCreation", nullptr, nullptr);
EGLNativeWindowType nativewindow = nullptr;
#ifdef _WIN32 #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 #endif
EGLSurface surface = eglCreateWindowSurface(display, config, nativewindow, nullptr); EGLSurface surface = eglCreateWindowSurface(display, config, nativewindow, nullptr);
eglMakeCurrent(display, surface, surface, context); eglMakeCurrent(display, surface, surface, context);
@@ -16,11 +16,18 @@
#include <EGL/egl.h> #include <EGL/egl.h>
#ifdef _WIN32 #ifdef _WIN32
#define GLFW_EXPOSE_NATIVE_WIN32 #define GLFW_EXPOSE_NATIVE_WIN32
#elif defined(__APPLE__)
#define GLFW_EXPOSE_NATIVE_COCOA
#endif #endif
#include "MG_Backend/DirectVulkan/DirectVulkan.h" #include "MG_Backend/DirectVulkan/DirectVulkan.h"
#include "MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h" #include "MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h"
#include <GLFW/glfw3native.h> #include <GLFW/glfw3native.h>
#ifdef __APPLE__
#include <objc/message.h>
#include <objc/objc.h>
#include <objc/runtime.h>
#endif
int main() { int main() {
glfwInit(); glfwInit();
@@ -41,8 +48,26 @@ int main() {
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = glfwCreateWindow(800, 600, "MobileGL ContextCreation", nullptr, nullptr); GLFWwindow* window = glfwCreateWindow(800, 600, "MobileGL ContextCreation", nullptr, nullptr);
EGLNativeWindowType nativewindow = nullptr;
#ifdef _WIN32 #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 #endif
EGLSurface surface = eglCreateWindowSurface(display, config, nativewindow, nullptr); EGLSurface surface = eglCreateWindowSurface(display, config, nativewindow, nullptr);
eglMakeCurrent(display, surface, surface, context); eglMakeCurrent(display, surface, surface, context);