From 93b8f68b2e9ddc450ce63f1b6e1806960312d803 Mon Sep 17 00:00:00 2001 From: skallweitNV <64953474+skallweitNV@users.noreply.github.com> Date: Tue, 19 Dec 2023 00:16:14 +0100 Subject: macos/vulkan support (#3418) --- CMakeLists.txt | 17 +- build/visual-studio/gfx/gfx.vcxproj | 1 + build/visual-studio/gfx/gfx.vcxproj.filters | 3 + cmake/Glob.cmake | 5 +- examples/hello-world/vulkan-api.cpp | 22 +- examples/platform-test/main.cpp | 102 ++++ premake5.lua | 20 +- slang-gfx.h | 8 + slang.sln | 15 + tools/gfx/apple/cocoa-util.h | 12 + tools/gfx/apple/cocoa-util.mm | 15 + tools/gfx/render.cpp | 2 +- tools/gfx/vulkan/vk-api.h | 4 + tools/gfx/vulkan/vk-device.cpp | 13 +- tools/gfx/vulkan/vk-module.cpp | 3 + tools/gfx/vulkan/vk-module.h | 2 + tools/gfx/vulkan/vk-swap-chain.cpp | 16 +- tools/gfx/vulkan/vk-swap-chain.h | 17 - tools/platform/apple/cocoa-window.mm | 618 ++++++++++++++++++++++ tools/platform/placeholder/placeholder-window.cpp | 2 +- tools/platform/window.h | 8 + 21 files changed, 873 insertions(+), 32 deletions(-) create mode 100644 examples/platform-test/main.cpp create mode 100644 tools/gfx/apple/cocoa-util.h create mode 100644 tools/gfx/apple/cocoa-util.mm create mode 100644 tools/platform/apple/cocoa-window.mm diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ea4e1ef8..c2bd54565 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,11 +64,15 @@ auto_option( NVAPI "Enable NVAPI usage (Only available for builds targeting Windows)" ) -auto_option( - SLANG_ENABLE_XLIB - X11 - "Build gfx and platform with Xlib to support windowed apps on Linux" -) +if(CMAKE_SYSTEM_NAME MATCHES "Linux") + auto_option( + SLANG_ENABLE_XLIB + X11 + "Build gfx and platform with Xlib to support windowed apps on Linux" + ) +else() + set(SLANG_ENABLE_XLIB OFF) +endif() auto_option( SLANG_ENABLE_AFTERMATH Aftermath @@ -417,6 +421,8 @@ slang_add_target( core imgui $<$:X11::X11> + $<$:-framework Cocoa> + $<$:-framework QuartzCore> ${CMAKE_DL_LIBS} EXTRA_COMPILE_DEFINITIONS_PRIVATE $<$:SLANG_ENABLE_XLIB> @@ -662,6 +668,7 @@ example(examples/cpu-hello-world ) example(examples/gpu-printing ) example(examples/hello-world LINK_WITH_PRIVATE Vulkan-Headers) example(examples/model-viewer WIN32_EXECUTABLE) +example(examples/platform-test WIN32_EXECUTABLE) example(examples/ray-tracing WIN32_EXECUTABLE) example(examples/ray-tracing-pipeline WIN32_EXECUTABLE) example(examples/shader-object ) diff --git a/build/visual-studio/gfx/gfx.vcxproj b/build/visual-studio/gfx/gfx.vcxproj index f761631f0..20d9ca28e 100644 --- a/build/visual-studio/gfx/gfx.vcxproj +++ b/build/visual-studio/gfx/gfx.vcxproj @@ -315,6 +315,7 @@ IF EXIST "$(SolutionDir)tools\gfx\slang.slang"\ (xcopy /Q /E /Y /I "$(SolutionDi + diff --git a/build/visual-studio/gfx/gfx.vcxproj.filters b/build/visual-studio/gfx/gfx.vcxproj.filters index ad0ef3c35..50baad7e5 100644 --- a/build/visual-studio/gfx/gfx.vcxproj.filters +++ b/build/visual-studio/gfx/gfx.vcxproj.filters @@ -12,6 +12,9 @@ Header Files + + Header Files + Header Files diff --git a/cmake/Glob.cmake b/cmake/Glob.cmake index c960e5011..16ce80dd5 100644 --- a/cmake/Glob.cmake +++ b/cmake/Glob.cmake @@ -22,6 +22,9 @@ function(slang_glob_sources var dir) "*.natstepfilter" "*.natjmc" ) + if (CMAKE_SYSTEM_NAME MATCHES "Darwin") + list(APPEND patterns "*.mm") + endif() list(TRANSFORM patterns PREPEND "${dir}/") file(GLOB_RECURSE files CONFIGURE_DEPENDS ${patterns}) @@ -38,7 +41,7 @@ function(slang_glob_sources var dir) list(FILTER files EXCLUDE REGEX "(^|/)d3d.*/.*") endif() - if(NOT CMAKE_SYSTEM_NAME MATCHES "Windows|Linux") + if(NOT CMAKE_SYSTEM_NAME MATCHES "Windows|Linux|Darwin") list(FILTER files EXCLUDE REGEX "(^|/)vulkan/.*") endif() diff --git a/examples/hello-world/vulkan-api.cpp b/examples/hello-world/vulkan-api.cpp index cc52956ce..3581563d4 100644 --- a/examples/hello-world/vulkan-api.cpp +++ b/examples/hello-world/vulkan-api.cpp @@ -41,6 +41,10 @@ int initializeVulkanDevice(VulkanAPI& api) HMODULE module = ::LoadLibraryA(dynamicLibraryName); api.vulkanLibraryHandle = (void*)module; #define VK_API_GET_GLOBAL_PROC(x) api.x = (PFN_##x)GetProcAddress(module, #x); +#elif SLANG_APPLE_FAMILY + dynamicLibraryName = "libvulkan.dylib"; + api.vulkanLibraryHandle = dlopen(dynamicLibraryName, RTLD_NOW); +#define VK_API_GET_GLOBAL_PROC(x) api.x = (PFN_##x)dlsym(api.vulkanLibraryHandle, #x); #else dynamicLibraryName = "libvulkan.so.1"; api.vulkanLibraryHandle = dlopen(dynamicLibraryName, RTLD_NOW); @@ -78,10 +82,16 @@ int initializeVulkanDevice(VulkanAPI& api) applicationInfo.engineVersion = 1; applicationInfo.applicationVersion = 1; const char* instanceExtensions[] = { +#if SLANG_APPLE_FAMILY + VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, +#endif VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_EXTENSION_NAME, }; VkInstanceCreateInfo instanceCreateInfo = {VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO}; +#if SLANG_APPLE_FAMILY + instanceCreateInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; +#endif instanceCreateInfo.pApplicationInfo = &applicationInfo; instanceCreateInfo.enabledExtensionCount = SLANG_COUNT_OF(instanceExtensions); instanceCreateInfo.ppEnabledExtensionNames = &instanceExtensions[0]; @@ -150,14 +160,22 @@ int initializeVulkanDevice(VulkanAPI& api) if (api.queueFamilyIndex == -1) return -1; +#if SLANG_APPLE_FAMILY + const char* deviceExtensions[] = { + "VK_KHR_portability_subset", + }; +#endif + VkDeviceQueueCreateInfo queueCreateInfo = {VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO}; float queuePriority = 0.0f; queueCreateInfo.queueFamilyIndex = api.queueFamilyIndex; queueCreateInfo.queueCount = 1; queueCreateInfo.pQueuePriorities = &queuePriority; deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo; - deviceCreateInfo.enabledExtensionCount = 0; - deviceCreateInfo.ppEnabledExtensionNames = nullptr; +#if SLANG_APPLE_FAMILY + deviceCreateInfo.enabledExtensionCount = SLANG_COUNT_OF(deviceExtensions); + deviceCreateInfo.ppEnabledExtensionNames = &deviceExtensions[0]; +#endif RETURN_ON_FAIL(api.vkCreateDevice(api.physicalDevice, &deviceCreateInfo, nullptr, &api.device)); // Load device functions. diff --git a/examples/platform-test/main.cpp b/examples/platform-test/main.cpp new file mode 100644 index 000000000..24673db1c --- /dev/null +++ b/examples/platform-test/main.cpp @@ -0,0 +1,102 @@ +#include +#include "tools/platform/window.h" +#include "examples/example-base/example-base.h" + +using namespace gfx; +using namespace Slang; + +struct PlatformTest : public WindowedAppBase +{ + +void onSizeChanged() +{ + printf("onSizeChanged\n"); +} + +void onFocus() +{ + printf("onFocus\n"); +} + +void onLostFocus() +{ + printf("onLostFocus\n"); +} + +void onKeyDown(platform::KeyEventArgs args) +{ + printf("onKeyDown(key=0x%02x, buttons=0x%02x)\n", args.key, args.buttons); +} + +void onKeyUp(platform::KeyEventArgs args) +{ + printf("okKeyUp(key=0x%02x, buttons=0x%02x)\n", args.key, args.buttons); +} + +void onKeyPress(platform::KeyEventArgs args) +{ + printf("onKeyPress(keyChar=0x%02x)\n", args.keyChar); +} + +void onMouseMove(platform::MouseEventArgs args) +{ + printf("onMouseMove(x=%d, y=%d, delta=%d, buttons=0x%02x\n", args.x, args.y, args.delta, args.buttons); +} + +void onMouseDown(platform::MouseEventArgs args) +{ + printf("onMouseDown(x=%d, y=%d, delta=%d, buttons=0x%02x\n", args.x, args.y, args.delta, args.buttons); +} + +void onMouseUp(platform::MouseEventArgs args) +{ + printf("onMouseUp(x=%d, y=%d, delta=%d, buttons=0x%02x\n", args.x, args.y, args.delta, args.buttons); +} + +void onMouseWheel(platform::MouseEventArgs args) +{ + printf("onMouseWheel(x=%d, y=%d, delta=%d, buttons=0x%02x\n", args.x, args.y, args.delta, args.buttons); +} + +Slang::Result initialize() +{ + initializeBase("platform-test", 1024, 768); + + gWindow->events.sizeChanged = [this]() { onSizeChanged(); }; + gWindow->events.focus = [this]() { onFocus(); }; + gWindow->events.lostFocus = [this]() { onLostFocus(); }; + gWindow->events.keyDown = [this](const platform::KeyEventArgs& e) { onKeyDown(e); }; + gWindow->events.keyUp = [this](const platform::KeyEventArgs& e) { onKeyUp(e); }; + gWindow->events.keyPress = [this](const platform::KeyEventArgs& e) { onKeyPress(e); }; + gWindow->events.mouseMove = [this](const platform::MouseEventArgs& e) { onMouseMove(e); }; + gWindow->events.mouseDown = [this](const platform::MouseEventArgs& e) { onMouseDown(e); }; + gWindow->events.mouseUp = [this](const platform::MouseEventArgs& e) { onMouseUp(e); }; + gWindow->events.mouseWheel = [this](const platform::MouseEventArgs& e) { onMouseWheel(e); }; + + return SLANG_OK; +} + +virtual void renderFrame(int frameBufferIndex) override +{ + ComPtr commandBuffer = gTransientHeaps[frameBufferIndex]->createCommandBuffer(); + + auto renderEncoder = commandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameBufferIndex]); + + gfx::Viewport viewport = {}; + viewport.maxZ = 1.0f; + viewport.extentX = (float)windowWidth; + viewport.extentY = (float)windowHeight; + renderEncoder->setViewportAndScissor(viewport); + + renderEncoder->endEncoding(); + commandBuffer->close(); + gQueue->executeCommandBuffer(commandBuffer); + + gSwapchain->present(); +} + +}; + +// This macro instantiates an appropriate main function to +// run the application defined above. +PLATFORM_UI_MAIN(innerMain) diff --git a/premake5.lua b/premake5.lua index 2034d004b..13c6279c6 100644 --- a/premake5.lua +++ b/premake5.lua @@ -509,9 +509,13 @@ function addSourceDir(path) path .. "/*.natvis", -- Visual Studio debugger visualization files path .. "/*.natstepfilter", -- Visual Studio debugger step filter files path .. "/*.natjmc", -- Visual Studio debugger step filter files - - } + if os.target() == "macosx" then + files { path .. "/*.mm" } -- Objective-C++ files + filter { "files:**.mm" } + compileas "Objective-C++" + filter {} + end removefiles { "**/*.meta.slang.h", @@ -846,6 +850,8 @@ example "hello-world" -- -- Let's go ahead and set up the projects for our other example now. +example "platform-test" + example "triangle" example "ray-tracing" @@ -1120,6 +1126,7 @@ tool "gfx" files {"slang-gfx.h"} -- Will compile across targets + addSourceDir "tools/gfx/apple" addSourceDir "tools/gfx/cpu" addSourceDir "tools/gfx/nvapi" addSourceDir "tools/gfx/cuda" @@ -1182,7 +1189,7 @@ tool "gfx" elseif targetInfo.os == "mingw" or targetInfo.os == "cygwin" then -- Don't support any render techs... elseif os.target() == "macosx" then - --addSourceDir "tools/gfx/open-gl" + addSourceDir "tools/gfx/vulkan" else -- Linux like addSourceDir "tools/gfx/vulkan" @@ -1194,6 +1201,10 @@ tool "gfx" --addSourceDir "tools/gfx/open-gl" end + if os.target() == "macosx" then + links { "Cocoa.framework" } + end + if enableXlib then defines { "SLANG_ENABLE_XLIB" } libdirs { "/usr/X11/lib" } @@ -1247,10 +1258,13 @@ tool "platform" addSourceDir "tools/platform" addSourceDir "tools/platform/linux" addSourceDir "tools/platform/windows" + addSourceDir "tools/platform/apple" addSourceDir "tools/platform/placeholder" -- Include windowing support on Windows. if targetInfo.isWindows then systemversion "latest" + elseif os.target() == "macosx" then + links { "Cocoa.framework", "QuartzCore.framework" } else if enableXlib then defines { "SLANG_ENABLE_XLIB" } diff --git a/slang-gfx.h b/slang-gfx.h index c3ca7e2b3..9b45d2397 100644 --- a/slang-gfx.h +++ b/slang-gfx.h @@ -1460,6 +1460,7 @@ struct WindowHandle { Unknown, Win32Handle, + NSViewHandle, XLibHandle, }; Type type; @@ -1471,6 +1472,13 @@ struct WindowHandle handle.handleValues[0] = (intptr_t)(hwnd); return handle; } + static WindowHandle FromNSView(void* nsview) + { + WindowHandle handle = {}; + handle.type = WindowHandle::Type::NSViewHandle; + handle.handleValues[0] = (intptr_t)(nsview); + return handle; + } static WindowHandle FromXWindow(void* xdisplay, uint32_t xwindow) { WindowHandle handle = {}; diff --git a/slang.sln b/slang.sln index 9375165f0..c547b4e67 100644 --- a/slang.sln +++ b/slang.sln @@ -55,6 +55,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hello-world", "build\visual EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "model-viewer", "build\visual-studio\model-viewer\model-viewer.vcxproj", "{2F8724C6-1BC3-2730-84D5-3F277030D04A}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "platform-test", "build\visual-studio\platform-test\platform-test.vcxproj", "{F385D6A7-DF6C-989F-88BD-FEBC74831106}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ray-tracing", "build\visual-studio\ray-tracing\ray-tracing.vcxproj", "{71AC0F50-5DFD-FA91-8661-E95372118EFB}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ray-tracing-pipeline", "build\visual-studio\ray-tracing-pipeline\ray-tracing-pipeline.vcxproj", "{17BA8E32-034E-84DA-6C12-DE8E58C5BECC}" @@ -383,6 +385,18 @@ Global {2F8724C6-1BC3-2730-84D5-3F277030D04A}.Release|Win32.Build.0 = Release|Win32 {2F8724C6-1BC3-2730-84D5-3F277030D04A}.Release|x64.ActiveCfg = Release|x64 {2F8724C6-1BC3-2730-84D5-3F277030D04A}.Release|x64.Build.0 = Release|x64 + {F385D6A7-DF6C-989F-88BD-FEBC74831106}.Debug|aarch64.ActiveCfg = Debug aarch64|ARM64 + {F385D6A7-DF6C-989F-88BD-FEBC74831106}.Debug|aarch64.Build.0 = Debug aarch64|ARM64 + {F385D6A7-DF6C-989F-88BD-FEBC74831106}.Debug|Win32.ActiveCfg = Debug|Win32 + {F385D6A7-DF6C-989F-88BD-FEBC74831106}.Debug|Win32.Build.0 = Debug|Win32 + {F385D6A7-DF6C-989F-88BD-FEBC74831106}.Debug|x64.ActiveCfg = Debug|x64 + {F385D6A7-DF6C-989F-88BD-FEBC74831106}.Debug|x64.Build.0 = Debug|x64 + {F385D6A7-DF6C-989F-88BD-FEBC74831106}.Release|aarch64.ActiveCfg = Release aarch64|ARM64 + {F385D6A7-DF6C-989F-88BD-FEBC74831106}.Release|aarch64.Build.0 = Release aarch64|ARM64 + {F385D6A7-DF6C-989F-88BD-FEBC74831106}.Release|Win32.ActiveCfg = Release|Win32 + {F385D6A7-DF6C-989F-88BD-FEBC74831106}.Release|Win32.Build.0 = Release|Win32 + {F385D6A7-DF6C-989F-88BD-FEBC74831106}.Release|x64.ActiveCfg = Release|x64 + {F385D6A7-DF6C-989F-88BD-FEBC74831106}.Release|x64.Build.0 = Release|x64 {71AC0F50-5DFD-FA91-8661-E95372118EFB}.Debug|aarch64.ActiveCfg = Debug aarch64|ARM64 {71AC0F50-5DFD-FA91-8661-E95372118EFB}.Debug|aarch64.Build.0 = Debug aarch64|ARM64 {71AC0F50-5DFD-FA91-8661-E95372118EFB}.Debug|Win32.ActiveCfg = Debug|Win32 @@ -612,6 +626,7 @@ Global {57C81DD3-4304-213D-AC16-39349871C957} = {EB5FC2C6-D72D-B6CC-C0C1-26F3AC2E9231} {010BE414-ED5B-CF56-16C0-BD18027062C0} = {EB5FC2C6-D72D-B6CC-C0C1-26F3AC2E9231} {2F8724C6-1BC3-2730-84D5-3F277030D04A} = {EB5FC2C6-D72D-B6CC-C0C1-26F3AC2E9231} + {F385D6A7-DF6C-989F-88BD-FEBC74831106} = {EB5FC2C6-D72D-B6CC-C0C1-26F3AC2E9231} {71AC0F50-5DFD-FA91-8661-E95372118EFB} = {EB5FC2C6-D72D-B6CC-C0C1-26F3AC2E9231} {17BA8E32-034E-84DA-6C12-DE8E58C5BECC} = {EB5FC2C6-D72D-B6CC-C0C1-26F3AC2E9231} {25512BFB-1138-EDF2-BA88-5310A64E6659} = {EB5FC2C6-D72D-B6CC-C0C1-26F3AC2E9231} diff --git a/tools/gfx/apple/cocoa-util.h b/tools/gfx/apple/cocoa-util.h new file mode 100644 index 000000000..80467d8a4 --- /dev/null +++ b/tools/gfx/apple/cocoa-util.h @@ -0,0 +1,12 @@ +#pragma once + +namespace gfx { + +// Utility functions for Cocoa +struct CocoaUtil { + + static void getNSViewRectSize(void* nsview, int* widthOut, int* heightOut); + +}; + +} diff --git a/tools/gfx/apple/cocoa-util.mm b/tools/gfx/apple/cocoa-util.mm new file mode 100644 index 000000000..45b1c3df0 --- /dev/null +++ b/tools/gfx/apple/cocoa-util.mm @@ -0,0 +1,15 @@ +#include "cocoa-util.h" + +#import + +namespace gfx { + +void CocoaUtil::getNSViewRectSize(void* nsview, int* widthOut, int* heightOut) +{ + NSView* view = (NSView*)nsview; + NSRect rect = [view frame]; + *widthOut = rect.size.width; + *heightOut = rect.size.height; +} + +} \ No newline at end of file diff --git a/tools/gfx/render.cpp b/tools/gfx/render.cpp index aad544eb4..6dd0c90dd 100644 --- a/tools/gfx/render.cpp +++ b/tools/gfx/render.cpp @@ -324,7 +324,7 @@ extern "C" return SLANG_FAIL; } break; -#elif SLANG_LINUX_FAMILY && !defined(__CYGWIN__) +#elif (SLANG_LINUX_FAMILY || SLANG_APPLE_FAMILY) && !defined(__CYGWIN__) case DeviceType::Default: case DeviceType::Vulkan: { diff --git a/tools/gfx/vulkan/vk-api.h b/tools/gfx/vulkan/vk-api.h index b7cbf13de..213921406 100644 --- a/tools/gfx/vulkan/vk-api.h +++ b/tools/gfx/vulkan/vk-api.h @@ -141,6 +141,10 @@ namespace gfx { # define VK_API_INSTANCE_PLATFORM_KHR_PROCS(x) \ x(vkCreateWin32SurfaceKHR) \ /* */ +#elif SLANG_APPLE_FAMILY +# define VK_API_INSTANCE_PLATFORM_KHR_PROCS(x) \ + x(vkCreateMacOSSurfaceMVK) \ + /* */ #elif SLANG_ENABLE_XLIB # define VK_API_INSTANCE_PLATFORM_KHR_PROCS(x) \ x(vkCreateXlibSurfaceKHR) \ diff --git a/tools/gfx/vulkan/vk-device.cpp b/tools/gfx/vulkan/vk-device.cpp index fe3680eda..66c2c811b 100644 --- a/tools/gfx/vulkan/vk-device.cpp +++ b/tools/gfx/vulkan/vk-device.cpp @@ -171,8 +171,11 @@ Result DeviceImpl::initVulkanInstanceAndDevice( applicationInfo.engineVersion = 1; applicationInfo.applicationVersion = 1; - Array instanceExtensions; + Array instanceExtensions; +#if SLANG_APPLE_FAMILY + instanceExtensions.add(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); +#endif instanceExtensions.add(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); instanceExtensions.add(VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME); @@ -185,6 +188,8 @@ Result DeviceImpl::initVulkanInstanceAndDevice( // instanceExtensions.add("VK_GOOGLE_surfaceless_query"); #if SLANG_WINDOWS_FAMILY instanceExtensions.add(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); +#elif SLANG_APPLE_FAMILY + instanceExtensions.add(VK_MVK_MACOS_SURFACE_EXTENSION_NAME); #elif defined(SLANG_ENABLE_XLIB) instanceExtensions.add(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); @@ -195,6 +200,9 @@ Result DeviceImpl::initVulkanInstanceAndDevice( instanceExtensions.add(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); VkInstanceCreateInfo instanceCreateInfo = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO }; +#if SLANG_APPLE_FAMILY + instanceCreateInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; +#endif instanceCreateInfo.pApplicationInfo = &applicationInfo; instanceCreateInfo.enabledExtensionCount = (uint32_t)instanceExtensions.getCount(); instanceCreateInfo.ppEnabledExtensionNames = &instanceExtensions[0]; @@ -352,6 +360,9 @@ Result DeviceImpl::initVulkanInstanceAndDevice( List deviceExtensions; deviceExtensions.add(VK_KHR_SWAPCHAIN_EXTENSION_NAME); +#if SLANG_APPLE_FAMILY + deviceExtensions.add("VK_KHR_portability_subset"); +#endif VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; deviceCreateInfo.queueCreateInfoCount = 1; diff --git a/tools/gfx/vulkan/vk-module.cpp b/tools/gfx/vulkan/vk-module.cpp index cff75569e..0e4df8e7f 100644 --- a/tools/gfx/vulkan/vk-module.cpp +++ b/tools/gfx/vulkan/vk-module.cpp @@ -32,6 +32,9 @@ Slang::Result VulkanModule::init(bool useSoftwareImpl) dynamicLibraryName = useSoftwareImpl ? "vk_swiftshader.dll" : "vulkan-1.dll"; HMODULE module = ::LoadLibraryA(dynamicLibraryName); m_module = (void*)module; +#elif SLANG_APPLE_FAMILY + dynamicLibraryName = useSoftwareImpl ? "libvk_swiftshader.dylib" : "libvulkan.1.dylib"; + m_module = dlopen(dynamicLibraryName, RTLD_NOW | RTLD_GLOBAL); #else dynamicLibraryName = useSoftwareImpl ? "libvk_swiftshader.so" : "libvulkan.so.1"; if (useSoftwareImpl) diff --git a/tools/gfx/vulkan/vk-module.h b/tools/gfx/vulkan/vk-module.h index 97a0c8aba..9b8fe0ed3 100644 --- a/tools/gfx/vulkan/vk-module.h +++ b/tools/gfx/vulkan/vk-module.h @@ -7,6 +7,8 @@ #if SLANG_WINDOWS_FAMILY # define VK_USE_PLATFORM_WIN32_KHR 1 +#elif SLANG_APPLE_FAMILY +# define VK_USE_PLATFORM_MACOS_MVK 1 #else # define VK_USE_PLATFORM_XLIB_KHR 1 #endif diff --git a/tools/gfx/vulkan/vk-swap-chain.cpp b/tools/gfx/vulkan/vk-swap-chain.cpp index 384ca86ed..856fa2489 100644 --- a/tools/gfx/vulkan/vk-swap-chain.cpp +++ b/tools/gfx/vulkan/vk-swap-chain.cpp @@ -2,6 +2,7 @@ #include "vk-swap-chain.h" #include "vk-util.h" +#include "../apple/cocoa-util.h" namespace gfx { @@ -38,6 +39,8 @@ void SwapchainImpl::getWindowSize(int* widthOut, int* heightOut) const ::GetClientRect((HWND)m_windowHandle.handleValues[0], &rc); *widthOut = rc.right - rc.left; *heightOut = rc.bottom - rc.top; +#elif SLANG_APPLE_FAMILY + CocoaUtil::getNSViewRectSize((void*)m_windowHandle.handleValues[0], widthOut, heightOut); #elif defined(SLANG_ENABLE_XLIB) XWindowAttributes winAttr = {}; XGetWindowAttributes( @@ -221,6 +224,12 @@ Result SwapchainImpl::init(DeviceImpl* renderer, const ISwapchain::Desc& desc, W surfaceCreateInfo.hwnd = (HWND)window.handleValues[0]; SLANG_VK_RETURN_ON_FAIL( m_api->vkCreateWin32SurfaceKHR(m_api->m_instance, &surfaceCreateInfo, nullptr, &m_surface)); +#elif SLANG_APPLE_FAMILY + VkMacOSSurfaceCreateInfoMVK surfaceCreateInfo = {}; + surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; + surfaceCreateInfo.pView = (void*)window.handleValues[0]; + SLANG_VK_RETURN_ON_FAIL( + m_api->vkCreateMacOSSurfaceMVK(m_api->m_instance, &surfaceCreateInfo, nullptr, &m_surface)); #elif SLANG_ENABLE_XLIB VkXlibSurfaceCreateInfoKHR surfaceCreateInfo = {}; surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; @@ -347,7 +356,12 @@ int SwapchainImpl::acquireNextImage() VK_NULL_HANDLE, (uint32_t*)&m_currentImageIndex); - if (result != VK_SUCCESS) + if ( + result != VK_SUCCESS +#if SLANG_APPLE_FAMILY + && result != VK_SUBOPTIMAL_KHR +#endif + ) { m_currentImageIndex = -1; destroySwapchainAndImages(); diff --git a/tools/gfx/vulkan/vk-swap-chain.h b/tools/gfx/vulkan/vk-swap-chain.h index 6a39e2afa..2c0fe62ed 100644 --- a/tools/gfx/vulkan/vk-swap-chain.h +++ b/tools/gfx/vulkan/vk-swap-chain.h @@ -22,23 +22,6 @@ public: SLANG_COM_OBJECT_IUNKNOWN_ALL ISwapchain* getInterface(const Guid& guid); -public: - struct PlatformDesc - {}; - -#if SLANG_WINDOWS_FAMILY - struct WinPlatformDesc : public PlatformDesc - { - HINSTANCE m_hinstance; - HWND m_hwnd; - }; -#else - struct XPlatformDesc : public PlatformDesc - { - Display* m_display; - Window m_window; - }; -#endif public: VkSwapchainKHR m_swapChain; VkSurfaceKHR m_surface; diff --git a/tools/platform/apple/cocoa-window.mm b/tools/platform/apple/cocoa-window.mm new file mode 100644 index 000000000..450087dd2 --- /dev/null +++ b/tools/platform/apple/cocoa-window.mm @@ -0,0 +1,618 @@ +#ifdef __APPLE__ + +#include "../window.h" + +#import +#import + +using namespace Slang; +using namespace platform; + +namespace platform { +class CocoaPlatformWindow; +static KeyCode keyCodes[256]; + +class CocoaAppContext +{ +public: + static Window* mainWindow; + static bool isTerminated; +}; + +Window* CocoaAppContext::mainWindow; +bool CocoaAppContext::isTerminated = false; +} + +@interface WindowDelegate : NSObject +{ + CocoaPlatformWindow* window; +} + +- (instancetype)initWithPlatformWindow:(CocoaPlatformWindow*)platformWindow; + +@end + +@interface ContentView : NSView +{ + CocoaPlatformWindow* window; + NSTrackingArea* trackingArea; + int mouseX, mouseY; +} + +- (instancetype)initWithPlatformWindow:(CocoaPlatformWindow*)platformWindow; + +@end + +namespace platform { + +class CocoaPlatformWindow : public Window +{ +public: + NSWindow* window; + WindowDelegate* delegate; + ContentView* view; + CAMetalLayer* layer; + bool shouldClose = false; + + CocoaPlatformWindow(const WindowDesc& desc); + ~CocoaPlatformWindow(); + + virtual void setClientSize(uint32_t width, uint32_t height) override; + virtual Rect getClientRect() override; + virtual void centerScreen() override; + virtual void close() override; + virtual bool getFocused() override; + virtual bool getVisible() override; + virtual WindowHandle getNativeHandle() override; + virtual void setText(Slang::String text) override; + virtual void show() override; + virtual void hide() override; + virtual int getCurrentDpi() override; +}; + +void getMousePosition(NSEvent* event, NSView* view, int& x, int& y) +{ + const NSRect contentRect = [view frame]; + const NSPoint pos = [event locationInWindow]; + x = (int)pos.x; + y = (int)(contentRect.size.height - pos.y); +} + +ButtonState::Enum _addButtonState(ButtonState::Enum val, ButtonState::Enum newState) +{ + return (ButtonState::Enum)((int)val | (int)newState); +} + +static ButtonState::Enum getModifierState(NSUInteger flags) +{ + ButtonState::Enum result = ButtonState::None; + + if (flags & NSEventModifierFlagShift) + result = _addButtonState(result, ButtonState::Shift); + if (flags & NSEventModifierFlagControl) + result = _addButtonState(result, ButtonState::Control); + if (flags & NSEventModifierFlagOption) + result = _addButtonState(result, ButtonState::Alt); + return result; +} + +static KeyCode getKeyCode(NSUInteger keyCode) +{ + return keyCode < 256 ? keyCodes[keyCode] : KeyCode::None; +} + +} + + +@implementation WindowDelegate + +- (instancetype)initWithPlatformWindow:(CocoaPlatformWindow*)platformWindow +{ + self = [super init]; + if (self) + { + window = platformWindow; + } + return self; +} + +- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender +{ + return YES; +} + +- (BOOL)windowShouldClose:(id)window_ +{ + window->shouldClose = true; + if (CocoaAppContext::mainWindow == window) + CocoaAppContext::isTerminated = true; + return YES; +} + +- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender +{ + printf("applicationShouldTerminate\n"); + return NSTerminateCancel; +} + +- (void)windowDidResize:(NSNotification*)notification +{ + window->events.sizeChanged(); +} + +- (void)windowDidBecomeKey:(NSNotification*)notification +{ + window->events.focus(); +} + +- (void)windowDidResignKey:(NSNotification*)notification +{ + window->events.lostFocus(); +} + +@end + +@implementation ContentView + +- (instancetype)initWithPlatformWindow:(CocoaPlatformWindow*)platformWindow +{ + self = [super init]; + if (self) + { + window = platformWindow; + mouseX = 0; + mouseY = 0; + [self updateTrackingAreas]; + } + return self; +} + +- (void)updateTrackingAreas +{ + if (trackingArea != nil) + { + [self removeTrackingArea:trackingArea]; + [trackingArea release]; + } + + const NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | + NSTrackingMouseMoved | + NSTrackingActiveInKeyWindow | + NSTrackingEnabledDuringMouseDrag | + NSTrackingCursorUpdate | + NSTrackingInVisibleRect | + NSTrackingAssumeInside; + + trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] + options:options + owner:self + userInfo:nil]; + + [self addTrackingArea:trackingArea]; + [super updateTrackingAreas]; +} + +- (BOOL)isOpaque +{ + return YES; +} + +- (BOOL)canBecomeKeyView +{ + return YES; +} + +- (BOOL)acceptsFirstResponder +{ + return YES; +} + +- (BOOL)acceptsFirstMouse:(NSEvent*)event +{ + return YES; +} + +- (BOOL)wantsUpdateLayer +{ + return YES; +} + +- (void)mouseDown:(NSEvent*)event +{ + getMousePosition(event, self, mouseX, mouseY); + ButtonState::Enum buttons = ButtonState::LeftButton; + buttons = _addButtonState(buttons, getModifierState([event modifierFlags])); + window->events.mouseDown(MouseEventArgs{mouseX, mouseY, 0, buttons}); +} + +- (void)mouseUp:(NSEvent*)event +{ + getMousePosition(event, self, mouseX, mouseY); + ButtonState::Enum buttons = ButtonState::LeftButton; + buttons = _addButtonState(buttons, getModifierState([event modifierFlags])); + window->events.mouseUp(MouseEventArgs{mouseX, mouseY, 0, buttons}); +} + +- (void)rightMouseDown:(NSEvent*)event +{ + getMousePosition(event, self, mouseX, mouseY); + ButtonState::Enum buttons = ButtonState::RightButton; + buttons = _addButtonState(buttons, getModifierState([event modifierFlags])); + window->events.mouseDown(MouseEventArgs{mouseX, mouseY, 0, buttons}); +} + +- (void)rightMouseUp:(NSEvent*)event +{ + getMousePosition(event, self, mouseX, mouseY); + ButtonState::Enum buttons = ButtonState::RightButton; + buttons = _addButtonState(buttons, getModifierState([event modifierFlags])); + window->events.mouseUp(MouseEventArgs{mouseX, mouseY, 0, buttons}); +} + +- (void)otherMouseDown:(NSEvent *)event +{ + if ([event buttonNumber] == 2) + { + getMousePosition(event, self, mouseX, mouseY); + ButtonState::Enum buttons = ButtonState::MiddleButton; + buttons = _addButtonState(buttons, getModifierState([event modifierFlags])); + window->events.mouseDown(MouseEventArgs{mouseX, mouseY, 0, buttons}); + } +} + +- (void)otherMouseUp:(NSEvent *)event +{ + if ([event buttonNumber] == 2) + { + getMousePosition(event, self, mouseX, mouseY); + ButtonState::Enum buttons = ButtonState::MiddleButton; + buttons = _addButtonState(buttons, getModifierState([event modifierFlags])); + window->events.mouseUp(MouseEventArgs{mouseX, mouseY, 0, buttons}); + } +} + +- (void)mouseDragged:(NSEvent*)event +{ + [self mouseMoved:event]; +} + +- (void)rightMouseDragged:(NSEvent*)event +{ + [self mouseMoved:event]; +} + +- (void)otherMouseDragged:(NSEvent*)event +{ + [self mouseMoved:event]; +} + +- (void)mouseMoved:(NSEvent*)event +{ + getMousePosition(event, self, mouseX, mouseY); + window->events.mouseMove(MouseEventArgs{mouseX, mouseY, 0, getModifierState([event modifierFlags])}); +} + +- (void)scrollWheel:(NSEvent *)event +{ + double deltaX = [event scrollingDeltaX]; + double deltaY = [event scrollingDeltaY]; + if ([event hasPreciseScrollingDeltas]) + { + deltaX *= 0.1; + deltaY *= 0.1; + } + + int delta = (int)deltaY; + + window->events.mouseWheel(MouseEventArgs{0, 0, delta, getModifierState([event modifierFlags])}); +} + +- (void)keyDown:(NSEvent *)event +{ + KeyCode key = getKeyCode([event keyCode]); + if (key == KeyCode::None) + return; + KeyEventArgs keyEventArgs = {key, 0, getModifierState([event modifierFlags]), false}; + window->events.keyDown(keyEventArgs); + // if (!keyEventArgs.cancelEvent) + // [self interpretKeyEvents:@[event]]; +} + +- (void)keyUp:(NSEvent *)event +{ + KeyCode key = getKeyCode([event keyCode]); + if (key == KeyCode::None) + return; + KeyEventArgs keyEventArgs = {key, 0, getModifierState([event modifierFlags]), false}; + window->events.keyUp(keyEventArgs); + // if (!keyEventArgs.cancelEvent) + // [self interpretKeyEvents:@[event]]; +} + +- (void)flagsChanged:(NSEvent *)event +{ + KeyCode key = getKeyCode([event keyCode]); + ButtonState::Enum buttons = getModifierState([event modifierFlags]); + ButtonState::Enum button = ButtonState::None; + if (key == KeyCode::Shift) + button = ButtonState::Shift; + else if (key == KeyCode::Ctrl) + button = ButtonState::Control; + else if (key == KeyCode::Alt) + button = ButtonState::Alt; + + KeyEventArgs keyEventArgs = {key, 0, buttons, false}; + if (button & buttons) { + window->events.keyDown(keyEventArgs); + } else { + window->events.keyUp(keyEventArgs); + } +} + +@end + + +static NSApplication *_application; + + +namespace platform { + +void Application::init() +{ + _application = [NSApplication sharedApplication]; + [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; + [NSApp activateIgnoringOtherApps:YES]; + + // Setup key translation table. + ::memset(keyCodes, (int)KeyCode::None, sizeof(keyCodes)); + + keyCodes[0x1D] = KeyCode::Key0; + keyCodes[0x12] = KeyCode::Key1; + keyCodes[0x13] = KeyCode::Key2; + keyCodes[0x14] = KeyCode::Key3; + keyCodes[0x15] = KeyCode::Key4; + keyCodes[0x17] = KeyCode::Key5; + keyCodes[0x16] = KeyCode::Key6; + keyCodes[0x1A] = KeyCode::Key7; + keyCodes[0x1C] = KeyCode::Key8; + keyCodes[0x19] = KeyCode::Key9; + keyCodes[0x00] = KeyCode::A; + keyCodes[0x0B] = KeyCode::B; + keyCodes[0x08] = KeyCode::C; + keyCodes[0x02] = KeyCode::D; + keyCodes[0x0E] = KeyCode::E; + keyCodes[0x03] = KeyCode::F; + keyCodes[0x05] = KeyCode::G; + keyCodes[0x04] = KeyCode::H; + keyCodes[0x22] = KeyCode::I; + keyCodes[0x26] = KeyCode::J; + keyCodes[0x28] = KeyCode::K; + keyCodes[0x25] = KeyCode::L; + keyCodes[0x2E] = KeyCode::M; + keyCodes[0x2D] = KeyCode::N; + keyCodes[0x1F] = KeyCode::O; + keyCodes[0x23] = KeyCode::P; + keyCodes[0x0C] = KeyCode::Q; + keyCodes[0x0F] = KeyCode::R; + keyCodes[0x01] = KeyCode::S; + keyCodes[0x11] = KeyCode::T; + keyCodes[0x20] = KeyCode::U; + keyCodes[0x09] = KeyCode::V; + keyCodes[0x0D] = KeyCode::W; + keyCodes[0x07] = KeyCode::X; + keyCodes[0x10] = KeyCode::Y; + keyCodes[0x06] = KeyCode::Z; + + keyCodes[0x27] = KeyCode::Quote; + keyCodes[0x2A] = KeyCode::Backslash; + keyCodes[0x2B] = KeyCode::Comma; + keyCodes[0x18] = KeyCode::Plus; + keyCodes[0x32] = KeyCode::Tilde; + keyCodes[0x21] = KeyCode::LBracket; + keyCodes[0x1B] = KeyCode::Minus; + keyCodes[0x2F] = KeyCode::Dot; + keyCodes[0x1E] = KeyCode::RBracket; + keyCodes[0x29] = KeyCode::Semicolon; + keyCodes[0x2C] = KeyCode::Slash; + + keyCodes[0x33] = KeyCode::Backspace; + keyCodes[0x75] = KeyCode::Delete; + keyCodes[0x7D] = KeyCode::Down; + keyCodes[0x77] = KeyCode::End; + keyCodes[0x24] = KeyCode::Return; + keyCodes[0x35] = KeyCode::Escape; + keyCodes[0x7A] = KeyCode::F1; + keyCodes[0x78] = KeyCode::F2; + keyCodes[0x63] = KeyCode::F3; + keyCodes[0x76] = KeyCode::F4; + keyCodes[0x60] = KeyCode::F5; + keyCodes[0x61] = KeyCode::F6; + keyCodes[0x62] = KeyCode::F7; + keyCodes[0x64] = KeyCode::F8; + keyCodes[0x65] = KeyCode::F9; + keyCodes[0x6D] = KeyCode::F10; + keyCodes[0x67] = KeyCode::F11; + keyCodes[0x6F] = KeyCode::F12; + keyCodes[0x73] = KeyCode::Home; + keyCodes[0x72] = KeyCode::Insert; + keyCodes[0x7B] = KeyCode::Left; + keyCodes[0x79] = KeyCode::PageDown; + keyCodes[0x74] = KeyCode::PageUp; + keyCodes[0x7C] = KeyCode::Right; + keyCodes[0x31] = KeyCode::Space; + keyCodes[0x30] = KeyCode::Tab; + keyCodes[0x7E] = KeyCode::Up; + + keyCodes[0x38] = KeyCode::Shift; + keyCodes[0x3B] = KeyCode::Ctrl; + keyCodes[0x3A] = KeyCode::Alt; +} + +void doEventsImpl(bool waitForEvents) +{ + NSEvent *event; + do { + event = [NSApp nextEventMatchingMask:NSEventMaskAny + untilDate:waitForEvents ? [NSDate distantFuture] : [NSDate distantPast] + inMode:NSDefaultRunLoopMode + dequeue:YES]; + if (event) { + [NSApp sendEvent:event]; + } + } while (!CocoaAppContext::isTerminated && event); +} + +void Application::doEvents() +{ + doEventsImpl(false); +} + +void Application::quit() +{ + CocoaAppContext::isTerminated = true; +} + +void Application::dispose() +{ + CocoaAppContext::mainWindow = nullptr; +} + +void Application::run(Window* mainWindow, bool waitForEvents) +{ + if (mainWindow) + { + CocoaAppContext::mainWindow = mainWindow; + mainWindow->show(); + } + while (!CocoaAppContext::isTerminated) + { + doEventsImpl(waitForEvents); + if (CocoaAppContext::isTerminated) + break; + if (mainWindow) + { + mainWindow->events.mainLoop(); + } + } +} + +CocoaPlatformWindow::CocoaPlatformWindow(const WindowDesc& desc) +{ + // Create a reference rectangle + NSRect rect = NSMakeRect(0.0f, 0.0f, desc.width, desc.height); + + // Allocate window + window = [[NSWindow alloc] initWithContentRect:rect + styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable + backing:NSBackingStoreBuffered + defer:NO]; + + const NSWindowCollectionBehavior behavior + = NSWindowCollectionBehaviorFullScreenPrimary | NSWindowCollectionBehaviorManaged; + [window setCollectionBehavior:behavior]; + + if (desc.style == WindowStyle::Default) + [window setStyleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable]; + else if (desc.style == WindowStyle::FixedSize) + [window setStyleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable]; + + // Allocate view + rect = [window backingAlignedRect:rect options:NSAlignAllEdgesOutward]; + view = [[ContentView alloc] initWithPlatformWindow:this]; + [view setHidden:NO]; + [view setNeedsDisplay:YES]; + [view setWantsLayer:YES]; + + delegate = [[WindowDelegate alloc] initWithPlatformWindow:this]; + [window setDelegate:delegate]; + [window setContentView:view]; + + NSString* title = [NSString stringWithUTF8String:desc.title]; + [window setTitle:title]; + + [window center]; + [window makeKeyAndOrderFront:nil]; + + // Setup layer + layer = [[CAMetalLayer alloc] init]; + [view setLayer:layer]; +} + +CocoaPlatformWindow::~CocoaPlatformWindow() +{ + close(); +} + +void CocoaPlatformWindow::setClientSize(uint32_t width, uint32_t height) +{ + NSSize size = NSMakeSize(width, height); + [window setContentSize:size]; +} + +Rect CocoaPlatformWindow::getClientRect() +{ + NSRect rect = [window contentRectForFrameRect:[window frame]]; + return { (int)rect.origin.x, (int)rect.origin.y, (int)rect.size.width, (int)rect.size.height }; +} + +void CocoaPlatformWindow::centerScreen() +{ + [window center]; +} + +void CocoaPlatformWindow::close() +{ + [window release]; + [delegate release]; + [view release]; + [layer release]; + + window = nil; + delegate = nil; + view = nil; + layer = nil; +} + +bool CocoaPlatformWindow::getFocused() +{ + return [window isKeyWindow]; +} + +bool CocoaPlatformWindow::getVisible() +{ + return [window isVisible]; +} + +WindowHandle CocoaPlatformWindow::getNativeHandle() +{ + return WindowHandle::fromNSView(view); +} + +void CocoaPlatformWindow::setText(Slang::String text) +{ + NSString* title = [NSString stringWithUTF8String:text.begin()]; + [window setTitle:title]; +} + +void CocoaPlatformWindow::show() +{ + [window setIsVisible:YES]; +} + +void CocoaPlatformWindow::hide() +{ + [window setIsVisible:NO]; +} + +int CocoaPlatformWindow::getCurrentDpi() +{ + // There seems to be no API to get the actual DPI of the screen. + return 0; +} + +Window* Application::createWindow(const WindowDesc& desc) { return new CocoaPlatformWindow(desc); } + + +} // namespace platform + +#endif // __APPLE__ diff --git a/tools/platform/placeholder/placeholder-window.cpp b/tools/platform/placeholder/placeholder-window.cpp index a94287d55..ae4f413f8 100644 --- a/tools/platform/placeholder/placeholder-window.cpp +++ b/tools/platform/placeholder/placeholder-window.cpp @@ -1,4 +1,4 @@ -#if !defined(_WIN32) && !defined(SLANG_ENABLE_XLIB) +#if !defined(_WIN32) && !defined(__APPLE__) && !defined(SLANG_ENABLE_XLIB) #include "../window.h" diff --git a/tools/platform/window.h b/tools/platform/window.h index f80e21302..7f78b8af9 100644 --- a/tools/platform/window.h +++ b/tools/platform/window.h @@ -97,6 +97,7 @@ struct WindowHandle { Unknown, Win32Handle, + NSViewHandle, XLibHandle, }; Type type; @@ -108,6 +109,13 @@ struct WindowHandle handle.handleValues[0] = (intptr_t)(hwnd); return handle; } + static WindowHandle fromNSView(void* nsview) + { + WindowHandle handle = {}; + handle.type = WindowHandle::Type::NSViewHandle; + handle.handleValues[0] = (intptr_t)(nsview); + return handle; + } static WindowHandle fromXWindow(void* xdisplay, uint32_t xwindow) { WindowHandle handle = {}; -- cgit v1.2.3