diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index cef5a656..fc8aa761 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -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(std::size(s_deviceExtensionNames)); - deviceCreateInfo.ppEnabledExtensionNames = s_deviceExtensionNames; + + Vector 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 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(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(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 diff --git a/MobileGL/MG_Test/Backend/DirectVulkan/SanityTest.cpp b/MobileGL/MG_Test/Backend/DirectVulkan/SanityTest.cpp index ea3d5e01..9f274a1d 100644 --- a/MobileGL/MG_Test/Backend/DirectVulkan/SanityTest.cpp +++ b/MobileGL/MG_Test/Backend/DirectVulkan/SanityTest.cpp @@ -46,8 +46,15 @@ TEST(DirectVulkanSanity, WindowCreation) { #include #ifdef _WIN32 #define GLFW_EXPOSE_NATIVE_WIN32 +#elif defined(__APPLE__) + #define GLFW_EXPOSE_NATIVE_COCOA #endif #include +#ifdef __APPLE__ +#include +#include +#include +#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(objc_msgSend); + auto msgSendVoidObj = reinterpret_cast(objc_msgSend); + auto msgSendVoidBool = reinterpret_cast(objc_msgSend); + id contentView = msgSendObj(static_cast(cocoaWindow), sel_registerName("contentView")); + ASSERT_NE(contentView, nullptr); + msgSendVoidBool(contentView, sel_registerName("setWantsLayer:"), true); + + id metalLayerClass = reinterpret_cast(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(metalLayer); #endif EGLSurface surface = eglCreateWindowSurface(display, config, nativewindow, nullptr); eglMakeCurrent(display, surface, surface, context); diff --git a/MobileGL/MG_Test/Backend/DirectVulkan/TestExec.cpp b/MobileGL/MG_Test/Backend/DirectVulkan/TestExec.cpp index d3e789e9..06cc5472 100644 --- a/MobileGL/MG_Test/Backend/DirectVulkan/TestExec.cpp +++ b/MobileGL/MG_Test/Backend/DirectVulkan/TestExec.cpp @@ -16,11 +16,18 @@ #include #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 +#ifdef __APPLE__ +#include +#include +#include +#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(objc_msgSend); + auto msgSendVoidObj = reinterpret_cast(objc_msgSend); + auto msgSendVoidBool = reinterpret_cast(objc_msgSend); + id contentView = msgSendObj(static_cast(cocoaWindow), sel_registerName("contentView")); + MOBILEGL_ASSERT(contentView, "Failed to query NSWindow.contentView"); + msgSendVoidBool(contentView, sel_registerName("setWantsLayer:"), true); + + id metalLayerClass = reinterpret_cast(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(metalLayer); #endif EGLSurface surface = eglCreateWindowSurface(display, config, nativewindow, nullptr); eglMakeCurrent(display, surface, surface, context);