Fix high-dpi support on macOS and simplify it and iOS variant.
authorMark Callow <libsdl.org@callow.im>
Wed, 21 Feb 2018 09:58:21 -0800
changeset 1188627d81cb6e6af
parent 11885 e6fc3ef41ffd
child 11887 1a033404c88b
Fix high-dpi support on macOS and simplify it and iOS variant.

The detault drawableSize for a CAMetalLayer is its bounds x its scale.
So it is sufficient to set the *layer's* scale to the desired value.
include/SDL_video.h
include/SDL_vulkan.h
src/video/cocoa/SDL_cocoametalview.h
src/video/cocoa/SDL_cocoametalview.m
src/video/uikit/SDL_uikitmetalview.h
src/video/uikit/SDL_uikitmetalview.m
     1.1 --- a/include/SDL_video.h	Wed Feb 21 09:40:47 2018 -0800
     1.2 +++ b/include/SDL_video.h	Wed Feb 21 09:58:21 2018 -0800
     1.3 @@ -110,7 +110,9 @@
     1.4      SDL_WINDOW_MOUSE_FOCUS = 0x00000400,        /**< window has mouse focus */
     1.5      SDL_WINDOW_FULLSCREEN_DESKTOP = ( SDL_WINDOW_FULLSCREEN | 0x00001000 ),
     1.6      SDL_WINDOW_FOREIGN = 0x00000800,            /**< window not created by SDL */
     1.7 -    SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000,      /**< window should be created in high-DPI mode if supported */
     1.8 +    SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000,      /**< window should be created in high-DPI mode if supported.
     1.9 +                                                     On macOS NSHighResolutionCapable must be set true in the
    1.10 +                                                     application's Info.plist for this to have any effect. */
    1.11      SDL_WINDOW_MOUSE_CAPTURE = 0x00004000,      /**< window has mouse captured (unrelated to INPUT_GRABBED) */
    1.12      SDL_WINDOW_ALWAYS_ON_TOP = 0x00008000,      /**< window should always be above others */
    1.13      SDL_WINDOW_SKIP_TASKBAR  = 0x00010000,      /**< window should not be added to the taskbar */
     2.1 --- a/include/SDL_vulkan.h	Wed Feb 21 09:40:47 2018 -0800
     2.2 +++ b/include/SDL_vulkan.h	Wed Feb 21 09:58:21 2018 -0800
     2.3 @@ -240,6 +240,9 @@
     2.4   * platform with high-DPI support (Apple calls this "Retina"), and not disabled
     2.5   * by the \c SDL_HINT_VIDEO_HIGHDPI_DISABLED hint.
     2.6   *
     2.7 + *  \note On macOS high-DPI support must be enabled for an application by
     2.8 + *        setting NSHighResolutionCapable to true in its Info.plist.
     2.9 + *
    2.10   *  \sa SDL_GetWindowSize()
    2.11   *  \sa SDL_CreateWindow()
    2.12   */
     3.1 --- a/src/video/cocoa/SDL_cocoametalview.h	Wed Feb 21 09:40:47 2018 -0800
     3.2 +++ b/src/video/cocoa/SDL_cocoametalview.h	Wed Feb 21 09:58:21 2018 -0800
     3.3 @@ -41,11 +41,10 @@
     3.4  
     3.5  @interface SDL_cocoametalview : NSView {
     3.6      NSInteger _tag;
     3.7 -    bool _useHighDPI;
     3.8  }
     3.9  
    3.10  - (instancetype)initWithFrame:(NSRect)frame
    3.11 -                   useHighDPI:(bool)useHighDPI;
    3.12 +                        scale:(CGFloat)scale;
    3.13  
    3.14  /* Override superclass tag so this class can set it. */
    3.15  @property (assign, readonly) NSInteger tag;
     4.1 --- a/src/video/cocoa/SDL_cocoametalview.m	Wed Feb 21 09:40:47 2018 -0800
     4.2 +++ b/src/video/cocoa/SDL_cocoametalview.m	Wed Feb 21 09:58:21 2018 -0800
     4.3 @@ -57,17 +57,19 @@
     4.4  }
     4.5  
     4.6  - (instancetype)initWithFrame:(NSRect)frame
     4.7 -                   useHighDPI:(bool)useHighDPI
     4.8 +                        scale:(CGFloat)scale
     4.9  {
    4.10  	if ((self = [super initWithFrame:frame])) {
    4.11 +        _tag = METALVIEW_TAG;
    4.12          self.wantsLayer = YES;
    4.13  
    4.14          /* Allow resize. */
    4.15          self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
    4.16 -        _tag = METALVIEW_TAG;
    4.17  
    4.18 -        _useHighDPI = useHighDPI;
    4.19 -        [self updateDrawableSize];
    4.20 +        /* Set the desired scale. The default drawableSize of a CAMetalLayer
    4.21 +         * is its bounds x its scale so nothing further needs to be done.
    4.22 +         */
    4.23 +        self.layer.contentsScale = scale;
    4.24  	}
    4.25    
    4.26  	return self;
    4.27 @@ -77,16 +79,6 @@
    4.28  - (void)resizeWithOldSuperviewSize:(NSSize)oldSize
    4.29  {
    4.30      [super resizeWithOldSuperviewSize:oldSize];
    4.31 -    [self updateDrawableSize];
    4.32 -}
    4.33 -
    4.34 -- (void)updateDrawableSize
    4.35 -{
    4.36 -    NSRect bounds = [self bounds];
    4.37 -    if (_useHighDPI) {
    4.38 -        bounds = [self convertRectToBacking:bounds];
    4.39 -    }
    4.40 -    ((CAMetalLayer *) self.layer).drawableSize = NSSizeToCGSize(bounds.size);
    4.41  }
    4.42  
    4.43  @end
    4.44 @@ -94,12 +86,26 @@
    4.45  SDL_cocoametalview*
    4.46  Cocoa_Mtl_AddMetalView(SDL_Window* window)
    4.47  {
    4.48 -    SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
    4.49 +    SDL_WindowData* data = (__bridge SDL_WindowData *)window->driverdata;
    4.50      NSView *view = data->nswindow.contentView;
    4.51 +    CGFloat scale = 1.0;
    4.52  
    4.53 +    if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
    4.54 +        /* Set the scale to the natural scale factor of the screen - then
    4.55 +         * the backing dimensions of the Metal view will match the pixel
    4.56 +         * dimensions of the screen rather than the dimensions in points
    4.57 +         * yielding high resolution on retine displays.
    4.58 +         *
    4.59 +         * N.B. In order for backingScaleFactor to be > 1,
    4.60 +         * NSHighResolutionCapable must be set to true in the app's Info.plist.
    4.61 +         */
    4.62 +        NSWindow* nswindow = data->nswindow;
    4.63 +        if ([nswindow.screen respondsToSelector:@selector(backingScaleFactor)])
    4.64 +            scale = data->nswindow.screen.backingScaleFactor;
    4.65 +    }
    4.66 +        
    4.67      SDL_cocoametalview *metalview
    4.68 -        = [[SDL_cocoametalview alloc] initWithFrame:view.frame
    4.69 -                       useHighDPI:(window->flags & SDL_WINDOW_ALLOW_HIGHDPI)];
    4.70 +        = [[SDL_cocoametalview alloc] initWithFrame:view.frame scale:scale];
    4.71      [view addSubview:metalview];
    4.72      return metalview;
    4.73  }
    4.74 @@ -119,6 +125,8 @@
    4.75          if (h) {
    4.76              *h = layer.drawableSize.height;
    4.77          }
    4.78 +    } else {
    4.79 +        SDL_GetWindowSize(window, w, h);
    4.80      }
    4.81  }
    4.82  
     5.1 --- a/src/video/uikit/SDL_uikitmetalview.h	Wed Feb 21 09:40:47 2018 -0800
     5.2 +++ b/src/video/uikit/SDL_uikitmetalview.h	Wed Feb 21 09:58:21 2018 -0800
     5.3 @@ -43,8 +43,7 @@
     5.4  @interface SDL_uikitmetalview : SDL_uikitview
     5.5  
     5.6  - (instancetype)initWithFrame:(CGRect)frame
     5.7 -                        scale:(CGFloat)scale
     5.8 -                        tag:(int)tag;
     5.9 +                        scale:(CGFloat)scale;
    5.10  
    5.11  @end
    5.12  
     6.1 --- a/src/video/uikit/SDL_uikitmetalview.m	Wed Feb 21 09:40:47 2018 -0800
     6.2 +++ b/src/video/uikit/SDL_uikitmetalview.m	Wed Feb 21 09:58:21 2018 -0800
     6.3 @@ -46,14 +46,12 @@
     6.4  
     6.5  - (instancetype)initWithFrame:(CGRect)frame
     6.6                          scale:(CGFloat)scale
     6.7 -                          tag:(int)tag
     6.8  {
     6.9      if ((self = [super initWithFrame:frame])) {
    6.10 -        /* Set the appropriate scale (for retina display support) */
    6.11 -        self.contentScaleFactor = scale;
    6.12 -        self.tag = tag;
    6.13 -
    6.14 -        [self updateDrawableSize];
    6.15 +        self.tag = METALVIEW_TAG;
    6.16 +        /* Set the desired scale. The default drawableSize of a CAMetalLayer
    6.17 +         * is its bounds x its scale so nothing further needs to be done. */
    6.18 +        self.layer.contentsScale = scale;
    6.19      }
    6.20  
    6.21      return self;
    6.22 @@ -63,16 +61,6 @@
    6.23  - (void)layoutSubviews
    6.24  {
    6.25      [super layoutSubviews];
    6.26 -    [self updateDrawableSize];
    6.27 -}
    6.28 -
    6.29 -- (void)updateDrawableSize
    6.30 -{
    6.31 -    CGSize size  = self.bounds.size;
    6.32 -    size.width  *= self.contentScaleFactor;
    6.33 -    size.height *= self.contentScaleFactor;
    6.34 -
    6.35 -    ((CAMetalLayer *) self.layer).drawableSize = size;
    6.36  }
    6.37  
    6.38  @end
    6.39 @@ -89,9 +77,10 @@
    6.40  	}
    6.41  
    6.42      if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
    6.43 -        /* Set the scale to the natural scale factor of the screen - the
    6.44 -         * backing dimensions of the Metal view will match the pixel
    6.45 -         * dimensions of the screen rather than the dimensions in points.
    6.46 +        /* Set the scale to the natural scale factor of the screen - then
    6.47 +         * the backing dimensions of the Metal view will match the pixel
    6.48 +         * dimensions of the screen rather than the dimensions in points
    6.49 +         * yielding high resolution on retine displays.
    6.50           */
    6.51  #ifdef __IPHONE_8_0
    6.52          if ([data.uiwindow.screen respondsToSelector:@selector(nativeScale)]) {
    6.53 @@ -104,8 +93,7 @@
    6.54      }
    6.55      SDL_uikitmetalview *metalview
    6.56           = [[SDL_uikitmetalview alloc] initWithFrame:view.frame
    6.57 -                                          scale:scale
    6.58 -                                            tag:METALVIEW_TAG];
    6.59 +                                               scale:scale];
    6.60      [metalview setSDLWindow:window];
    6.61  
    6.62      return metalview;