From 1a0306c50e56cb35b823553715176aad5e898602 Mon Sep 17 00:00:00 2001 From: Richard Knight Date: Sat, 3 Oct 2020 14:09:11 +0100 Subject: [PATCH] Add native API to allow access to Metal surface on Mac --- include/GLFW/glfw3native.h | 14 ++++++ src/cocoa_window.m | 88 ++++++++++++++++++++++++-------------- 2 files changed, 71 insertions(+), 31 deletions(-) diff --git a/include/GLFW/glfw3native.h b/include/GLFW/glfw3native.h index e680c1e3..bc0376cc 100644 --- a/include/GLFW/glfw3native.h +++ b/include/GLFW/glfw3native.h @@ -215,6 +215,20 @@ GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor); * @ingroup native */ GLFWAPI id glfwGetCocoaWindow(GLFWwindow* window); + +/*! @brief Returns the `CAMetalLayer` for the specified window. + * + * @return The `CAMetalLayer` of the specified window, or `nil` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.0. + * + * @ingroup native + */ +GLFWAPI id glfwGetMetalLayer(GLFWwindow* window); #endif #if defined(GLFW_EXPOSE_NATIVE_NSGL) diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 81b22e2f..4e17f622 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -878,6 +878,48 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, return GLFW_TRUE; } +static GLFWbool createMetalLayer(_GLFWwindow* window) +{ +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101100 + + @autoreleasepool { + + // HACK: Dynamically load Core Animation to avoid adding an extra + // dependency for the majority who don't use MoltenVK + NSBundle* bundle = [NSBundle bundleWithPath:@"/System/Library/Frameworks/QuartzCore.framework"]; + if (!bundle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to find QuartzCore.framework"); + return GLFW_FALSE; + } + + // NOTE: Create the layer here as makeBackingLayer should not return nil + window->ns.layer = [[bundle classNamed:@"CAMetalLayer"] layer]; + if (!window->ns.layer) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to create layer for view"); + return GLFW_FALSE; + } + + if (window->ns.retina) + [window->ns.layer setContentsScale:[window->ns.object backingScaleFactor]]; + + [window->ns.view setLayer:window->ns.layer]; + [window->ns.view setWantsLayer:YES]; + + } // autoreleasepool + + return GLFW_TRUE; + +#else + + return GLFW_FALSE; + +#endif +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// @@ -1805,33 +1847,8 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface) { - @autoreleasepool { - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101100 - // HACK: Dynamically load Core Animation to avoid adding an extra - // dependency for the majority who don't use MoltenVK - NSBundle* bundle = [NSBundle bundleWithPath:@"/System/Library/Frameworks/QuartzCore.framework"]; - if (!bundle) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Cocoa: Failed to find QuartzCore.framework"); + if (!createMetalLayer(window)) return VK_ERROR_EXTENSION_NOT_PRESENT; - } - - // NOTE: Create the layer here as makeBackingLayer should not return nil - window->ns.layer = [[bundle classNamed:@"CAMetalLayer"] layer]; - if (!window->ns.layer) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Cocoa: Failed to create layer for view"); - return VK_ERROR_EXTENSION_NOT_PRESENT; - } - - if (window->ns.retina) - [window->ns.layer setContentsScale:[window->ns.object backingScaleFactor]]; - - [window->ns.view setLayer:window->ns.layer]; - [window->ns.view setWantsLayer:YES]; VkResult err; @@ -1884,11 +1901,6 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, } return err; -#else - return VK_ERROR_EXTENSION_NOT_PRESENT; -#endif - - } // autoreleasepool } @@ -1903,3 +1915,17 @@ GLFWAPI id glfwGetCocoaWindow(GLFWwindow* handle) return window->ns.object; } +GLFWAPI id glfwGetMetalLayer(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(nil); + + if (!window->ns.layer) + { + if (!createMetalLayer(window)) + return nil; + } + + return window->ns.layer; +} +