summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoametalview.m
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoametalview.m')
-rw-r--r--contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoametalview.m182
1 files changed, 182 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoametalview.m b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoametalview.m
new file mode 100644
index 0000000..af84e93
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoametalview.m
@@ -0,0 +1,182 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21/*
22 * @author Mark Callow, www.edgewise-consulting.com.
23 *
24 * Thanks to @slime73 on GitHub for their gist showing how to add a CAMetalLayer
25 * backed view.
26 */
27#include "SDL_internal.h"
28
29#include "../../events/SDL_windowevents_c.h"
30
31#import "SDL_cocoametalview.h"
32
33#if defined(SDL_VIDEO_DRIVER_COCOA) && (defined(SDL_VIDEO_VULKAN) || defined(SDL_VIDEO_METAL))
34
35static bool SDLCALL SDL_MetalViewEventWatch(void *userdata, SDL_Event *event)
36{
37 /* Update the drawable size when SDL receives a size changed event for
38 * the window that contains the metal view. It would be nice to use
39 * - (void)resizeWithOldSuperviewSize:(NSSize)oldSize and
40 * - (void)viewDidChangeBackingProperties instead, but SDL's size change
41 * events don't always happen in the same frame (for example when a
42 * resizable window exits a fullscreen Space via the user pressing the OS
43 * exit-space button). */
44 if (event->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED) {
45 @autoreleasepool {
46 SDL3_cocoametalview *view = (__bridge SDL3_cocoametalview *)userdata;
47 if (view.sdlWindowID == event->window.windowID) {
48 [view updateDrawableSize];
49 }
50 }
51 }
52 return false;
53}
54
55@implementation SDL3_cocoametalview
56
57// Return a Metal-compatible layer.
58+ (Class)layerClass
59{
60 return NSClassFromString(@"CAMetalLayer");
61}
62
63// Indicate the view wants to draw using a backing layer instead of drawRect.
64- (BOOL)wantsUpdateLayer
65{
66 return YES;
67}
68
69/* When the wantsLayer property is set to YES, this method will be invoked to
70 * return a layer instance.
71 */
72- (CALayer *)makeBackingLayer
73{
74 return [self.class.layerClass layer];
75}
76
77- (instancetype)initWithFrame:(NSRect)frame
78 highDPI:(BOOL)highDPI
79 windowID:(Uint32)windowID
80 opaque:(BOOL)opaque
81{
82 self = [super initWithFrame:frame];
83 if (self != nil) {
84 self.highDPI = highDPI;
85 self.sdlWindowID = windowID;
86 self.wantsLayer = YES;
87
88 // Allow resize.
89 self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
90
91 self.layer.opaque = opaque;
92
93 SDL_AddWindowEventWatch(SDL_WINDOW_EVENT_WATCH_EARLY, SDL_MetalViewEventWatch, (__bridge void *)(self));
94
95 [self updateDrawableSize];
96 }
97
98 return self;
99}
100
101- (void)dealloc
102{
103 SDL_RemoveWindowEventWatch(SDL_WINDOW_EVENT_WATCH_EARLY, SDL_MetalViewEventWatch, (__bridge void *)(self));
104}
105
106- (NSInteger)tag
107{
108 return SDL_METALVIEW_TAG;
109}
110
111- (void)updateDrawableSize
112{
113 CAMetalLayer *metalLayer = (CAMetalLayer *)self.layer;
114 NSSize size = self.bounds.size;
115 NSSize backingSize = size;
116
117 if (self.highDPI) {
118 /* Note: NSHighResolutionCapable must be set to true in the app's
119 * Info.plist in order for the backing size to be high res.
120 */
121 backingSize = [self convertSizeToBacking:size];
122 }
123
124 metalLayer.contentsScale = backingSize.height / size.height;
125 metalLayer.drawableSize = NSSizeToCGSize(backingSize);
126}
127
128- (NSView *)hitTest:(NSPoint)point
129{
130 return nil;
131}
132
133@end
134
135SDL_MetalView Cocoa_Metal_CreateView(SDL_VideoDevice *_this, SDL_Window *window)
136{
137 @autoreleasepool {
138 SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal;
139 NSView *view = data.nswindow.contentView;
140 BOOL highDPI = (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) != 0;
141 BOOL opaque = (window->flags & SDL_WINDOW_TRANSPARENT) == 0;
142 Uint32 windowID = SDL_GetWindowID(window);
143 SDL3_cocoametalview *newview;
144 SDL_MetalView metalview;
145
146 newview = [[SDL3_cocoametalview alloc] initWithFrame:view.frame
147 highDPI:highDPI
148 windowID:windowID
149 opaque:opaque];
150 if (newview == nil) {
151 SDL_OutOfMemory();
152 return NULL;
153 }
154
155 [view addSubview:newview];
156
157 // Make sure the drawable size is up to date after attaching the view.
158 [newview updateDrawableSize];
159
160 metalview = (SDL_MetalView)CFBridgingRetain(newview);
161
162 return metalview;
163 }
164}
165
166void Cocoa_Metal_DestroyView(SDL_VideoDevice *_this, SDL_MetalView view)
167{
168 @autoreleasepool {
169 SDL3_cocoametalview *metalview = CFBridgingRelease(view);
170 [metalview removeFromSuperview];
171 }
172}
173
174void *Cocoa_Metal_GetLayer(SDL_VideoDevice *_this, SDL_MetalView view)
175{
176 @autoreleasepool {
177 SDL3_cocoametalview *cocoaview = (__bridge SDL3_cocoametalview *)view;
178 return (__bridge void *)cocoaview.layer;
179 }
180}
181
182#endif // SDL_VIDEO_DRIVER_COCOA && (SDL_VIDEO_VULKAN || SDL_VIDEO_METAL)