summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorskallweitNV <64953474+skallweitNV@users.noreply.github.com>2023-12-19 00:16:14 +0100
committerGitHub <noreply@github.com>2023-12-18 15:16:14 -0800
commit93b8f68b2e9ddc450ce63f1b6e1806960312d803 (patch)
treed5c9c38efe1e7c86637c4be6157595b44a5c4856 /tools
parentb6da04424aff71ddba9629c94401a9a897b152a0 (diff)
macos/vulkan support (#3418)
Diffstat (limited to 'tools')
-rw-r--r--tools/gfx/apple/cocoa-util.h12
-rw-r--r--tools/gfx/apple/cocoa-util.mm15
-rw-r--r--tools/gfx/render.cpp2
-rw-r--r--tools/gfx/vulkan/vk-api.h4
-rw-r--r--tools/gfx/vulkan/vk-device.cpp13
-rw-r--r--tools/gfx/vulkan/vk-module.cpp3
-rw-r--r--tools/gfx/vulkan/vk-module.h2
-rw-r--r--tools/gfx/vulkan/vk-swap-chain.cpp16
-rw-r--r--tools/gfx/vulkan/vk-swap-chain.h17
-rw-r--r--tools/platform/apple/cocoa-window.mm618
-rw-r--r--tools/platform/placeholder/placeholder-window.cpp2
-rw-r--r--tools/platform/window.h8
12 files changed, 691 insertions, 21 deletions
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 <Cocoa/Cocoa.h>
+
+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<const char*, 6> instanceExtensions;
+ Array<const char*, 7> 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<const char*> 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
@@ -23,23 +23,6 @@ public:
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;
VkSemaphore m_nextImageSemaphore; // Semaphore to signal after `acquireNextImage`.
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 <Cocoa/Cocoa.h>
+#import <QuartzCore/CAMetalLayer.h>
+
+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 <NSWindowDelegate>
+{
+ 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 = {};