src/video/cocoa/SDL_cocoametalview.m
author Ryan C. Gordon <icculus@icculus.org>
Sun, 27 May 2018 20:30:03 -0400
changeset 12002 9116d02d3feb
parent 11886 27d81cb6e6af
child 12201 8bdc4d340419
permissions -rw-r--r--
metal: contrary to documentation, we need to set the drawableSize explicitly.

Fixes Bugzilla #4149.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2018 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 Alex Szpakowski, @slime73 on GitHub, for his gist showing
    25  * how to add a CAMetalLayer backed view.
    26  */
    27 
    28 #import "SDL_cocoametalview.h"
    29 
    30 #if SDL_VIDEO_DRIVER_COCOA && (SDL_VIDEO_VULKAN || SDL_VIDEO_RENDER_METAL)
    31 
    32 #include "SDL_assert.h"
    33 
    34 @implementation SDL_cocoametalview
    35 
    36 /* The synthesized getter should be called by super's viewWithTag. */
    37 @synthesize tag = _tag;
    38 
    39 /* Return a Metal-compatible layer. */
    40 + (Class)layerClass
    41 {
    42 	return NSClassFromString(@"CAMetalLayer");
    43 }
    44 
    45 /* Indicate the view wants to draw using a backing layer instead of drawRect. */
    46 - (BOOL)wantsUpdateLayer
    47 {
    48     return YES;
    49 }
    50 
    51 /* When the wantsLayer property is set to YES, this method will be invoked to
    52  * return a layer instance.
    53  */
    54 - (CALayer*)makeBackingLayer
    55 {
    56     return [self.class.layerClass layer];
    57 }
    58 
    59 - (instancetype)initWithFrame:(NSRect)frame
    60                         scale:(CGFloat)scale
    61 {
    62 	if ((self = [super initWithFrame:frame])) {
    63         _tag = METALVIEW_TAG;
    64         self.wantsLayer = YES;
    65 
    66         /* Allow resize. */
    67         self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
    68 
    69         /* Set the desired scale. */
    70         ((CAMetalLayer *) self.layer).drawableSize = NSSizeToCGSize([self bounds].size);
    71         self.layer.contentsScale = scale;
    72     }
    73   
    74 	return self;
    75 }
    76 
    77 /* Set the size of the metal drawables when the view is resized. */
    78 - (void)resizeWithOldSuperviewSize:(NSSize)oldSize
    79 {
    80     [super resizeWithOldSuperviewSize:oldSize];
    81 }
    82 
    83 @end
    84 
    85 SDL_cocoametalview*
    86 Cocoa_Mtl_AddMetalView(SDL_Window* window)
    87 {
    88     SDL_WindowData* data = (__bridge SDL_WindowData *)window->driverdata;
    89     NSView *view = data->nswindow.contentView;
    90     CGFloat scale = 1.0;
    91 
    92     if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
    93         /* Set the scale to the natural scale factor of the screen - then
    94          * the backing dimensions of the Metal view will match the pixel
    95          * dimensions of the screen rather than the dimensions in points
    96          * yielding high resolution on retine displays.
    97          *
    98          * N.B. In order for backingScaleFactor to be > 1,
    99          * NSHighResolutionCapable must be set to true in the app's Info.plist.
   100          */
   101         NSWindow* nswindow = data->nswindow;
   102         if ([nswindow.screen respondsToSelector:@selector(backingScaleFactor)])
   103             scale = data->nswindow.screen.backingScaleFactor;
   104     }
   105         
   106     SDL_cocoametalview *metalview
   107         = [[SDL_cocoametalview alloc] initWithFrame:view.frame scale:scale];
   108     [view addSubview:metalview];
   109     return metalview;
   110 }
   111 
   112 void
   113 Cocoa_Mtl_GetDrawableSize(SDL_Window * window, int * w, int * h)
   114 {
   115     SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata;
   116     NSView *view = data->nswindow.contentView;
   117     SDL_cocoametalview* metalview = [view viewWithTag:METALVIEW_TAG];
   118     if (metalview) {
   119         CAMetalLayer *layer = (CAMetalLayer*)metalview.layer;
   120         assert(layer != NULL);
   121         if (w) {
   122             *w = layer.drawableSize.width;
   123         }
   124         if (h) {
   125             *h = layer.drawableSize.height;
   126         }
   127     } else {
   128         SDL_GetWindowSize(window, w, h);
   129     }
   130 }
   131 
   132 #endif /* SDL_VIDEO_DRIVER_COCOA && (SDL_VIDEO_VULKAN || SDL_VIDEO_RENDER_METAL) */
   133 
   134 /* vi: set ts=4 sw=4 expandtab: */