Atlas - SDL_cocoametalview.m

Home / ext / SDL / src / video / cocoa Lines: 1 | Size: 5813 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 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 if (SDL_GetHintBoolean(SDL_HINT_VIDEO_METAL_AUTO_RESIZE_DRAWABLE, true)) { 94 SDL_AddWindowEventWatch(SDL_WINDOW_EVENT_WATCH_EARLY, SDL_MetalViewEventWatch, (__bridge void *)(self)); 95 } 96 97 [self updateDrawableSize]; 98 } 99 100 return self; 101} 102 103- (void)dealloc 104{ 105 SDL_RemoveWindowEventWatch(SDL_WINDOW_EVENT_WATCH_EARLY, SDL_MetalViewEventWatch, (__bridge void *)(self)); 106} 107 108- (NSInteger)tag 109{ 110 return SDL_METALVIEW_TAG; 111} 112 113- (void)updateDrawableSize 114{ 115 CAMetalLayer *metalLayer = (CAMetalLayer *)self.layer; 116 NSSize size = self.bounds.size; 117 NSSize backingSize = size; 118 119 if (self.highDPI) { 120 /* Note: NSHighResolutionCapable must be set to true in the app's 121 * Info.plist in order for the backing size to be high res. 122 */ 123 backingSize = [self convertSizeToBacking:size]; 124 } 125 126 metalLayer.contentsScale = backingSize.height / size.height; 127 metalLayer.drawableSize = NSSizeToCGSize(backingSize); 128} 129 130- (NSView *)hitTest:(NSPoint)point 131{ 132 return nil; 133} 134 135@end 136 137SDL_MetalView Cocoa_Metal_CreateView(SDL_VideoDevice *_this, SDL_Window *window) 138{ 139 @autoreleasepool { 140 SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; 141 NSView *view = data.nswindow.contentView; 142 BOOL highDPI = (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) != 0; 143 BOOL opaque = (window->flags & SDL_WINDOW_TRANSPARENT) == 0; 144 Uint32 windowID = SDL_GetWindowID(window); 145 SDL3_cocoametalview *newview; 146 SDL_MetalView metalview; 147 148 newview = [[SDL3_cocoametalview alloc] initWithFrame:view.frame 149 highDPI:highDPI 150 windowID:windowID 151 opaque:opaque]; 152 if (newview == nil) { 153 SDL_OutOfMemory(); 154 return NULL; 155 } 156 157 [view addSubview:newview]; 158 159 // Make sure the drawable size is up to date after attaching the view. 160 [newview updateDrawableSize]; 161 162 metalview = (SDL_MetalView)CFBridgingRetain(newview); 163 164 return metalview; 165 } 166} 167 168void Cocoa_Metal_DestroyView(SDL_VideoDevice *_this, SDL_MetalView view) 169{ 170 @autoreleasepool { 171 SDL3_cocoametalview *metalview = CFBridgingRelease(view); 172 [metalview removeFromSuperview]; 173 } 174} 175 176void *Cocoa_Metal_GetLayer(SDL_VideoDevice *_this, SDL_MetalView view) 177{ 178 @autoreleasepool { 179 SDL3_cocoametalview *cocoaview = (__bridge SDL3_cocoametalview *)view; 180 return (__bridge void *)cocoaview.layer; 181 } 182} 183 184#endif // SDL_VIDEO_DRIVER_COCOA && (SDL_VIDEO_VULKAN || SDL_VIDEO_METAL) 185
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.