metal: Fix high dpi and resizing on macOS, and clean up iOS code. Fixes bug #4250.
authorAlex Szpakowski <slime73@gmail.com>
Fri, 12 Oct 2018 17:55:42 -0300
changeset 12320758d4e1222a7
parent 12319 06e89f1159f9
child 12321 4216eccf4ea2
metal: Fix high dpi and resizing on macOS, and clean up iOS code. Fixes bug #4250.
src/render/metal/SDL_render_metal.m
src/video/cocoa/SDL_cocoametalview.h
src/video/cocoa/SDL_cocoametalview.m
src/video/uikit/SDL_uikitmetalview.m
     1.1 --- a/src/render/metal/SDL_render_metal.m	Thu Oct 11 15:14:48 2018 -0700
     1.2 +++ b/src/render/metal/SDL_render_metal.m	Fri Oct 12 17:55:42 2018 -0300
     1.3 @@ -752,11 +752,6 @@
     1.4  static void
     1.5  METAL_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
     1.6  {
     1.7 -    if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
     1.8 -        METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
     1.9 -        data.mtllayer.drawableSize = CGSizeMake(event->data1, event->data2);
    1.10 -    }
    1.11 -
    1.12      if (event->event == SDL_WINDOWEVENT_SHOWN ||
    1.13          event->event == SDL_WINDOWEVENT_HIDDEN) {
    1.14          // !!! FIXME: write me
    1.15 @@ -848,12 +843,20 @@
    1.16          mtltexdesc.height = (texture->h + 1) / 2;
    1.17          mtltexdesc.textureType = MTLTextureType2DArray;
    1.18          mtltexdesc.arrayLength = 2;
    1.19 -        mtltexture_uv = [data.mtldevice newTextureWithDescriptor:mtltexdesc];
    1.20      } else if (nv12) {
    1.21          mtltexdesc.pixelFormat = MTLPixelFormatRG8Unorm;
    1.22          mtltexdesc.width = (texture->w + 1) / 2;
    1.23          mtltexdesc.height = (texture->h + 1) / 2;
    1.24 +    }
    1.25 +
    1.26 +    if (yuv || nv12) {
    1.27          mtltexture_uv = [data.mtldevice newTextureWithDescriptor:mtltexdesc];
    1.28 +        if (mtltexture_uv == nil) {
    1.29 +#if !__has_feature(objc_arc)
    1.30 +            [mtltexture release];
    1.31 +#endif
    1.32 +            return SDL_SetError("Texture allocation failed");
    1.33 +        }
    1.34      }
    1.35  
    1.36      METAL_TextureData *texturedata = [[METAL_TextureData alloc] init];
     2.1 --- a/src/video/cocoa/SDL_cocoametalview.h	Thu Oct 11 15:14:48 2018 -0700
     2.2 +++ b/src/video/cocoa/SDL_cocoametalview.h	Fri Oct 12 17:55:42 2018 -0300
     2.3 @@ -39,16 +39,16 @@
     2.4  
     2.5  #define METALVIEW_TAG 255
     2.6  
     2.7 -@interface SDL_cocoametalview : NSView {
     2.8 -    NSInteger _tag;
     2.9 -}
    2.10 +@interface SDL_cocoametalview : NSView
    2.11  
    2.12  - (instancetype)initWithFrame:(NSRect)frame
    2.13 -                        scale:(CGFloat)scale;
    2.14 +                      highDPI:(BOOL)highDPI;
    2.15  
    2.16  /* Override superclass tag so this class can set it. */
    2.17  @property (assign, readonly) NSInteger tag;
    2.18  
    2.19 +@property (nonatomic) BOOL highDPI;
    2.20 +
    2.21  @end
    2.22  
    2.23  SDL_cocoametalview* Cocoa_Mtl_AddMetalView(SDL_Window* window);
     3.1 --- a/src/video/cocoa/SDL_cocoametalview.m	Thu Oct 11 15:14:48 2018 -0700
     3.2 +++ b/src/video/cocoa/SDL_cocoametalview.m	Fri Oct 12 17:55:42 2018 -0300
     3.3 @@ -33,9 +33,6 @@
     3.4  
     3.5  @implementation SDL_cocoametalview
     3.6  
     3.7 -/* The synthesized getter should be called by super's viewWithTag. */
     3.8 -@synthesize tag = _tag;
     3.9 -
    3.10  /* Return a Metal-compatible layer. */
    3.11  + (Class)layerClass
    3.12  {
    3.13 @@ -57,27 +54,48 @@
    3.14  }
    3.15  
    3.16  - (instancetype)initWithFrame:(NSRect)frame
    3.17 -                        scale:(CGFloat)scale
    3.18 +                      highDPI:(BOOL)highDPI
    3.19  {
    3.20      if ((self = [super initWithFrame:frame])) {
    3.21 -        _tag = METALVIEW_TAG;
    3.22 +        self.highDPI = highDPI;
    3.23          self.wantsLayer = YES;
    3.24  
    3.25          /* Allow resize. */
    3.26          self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
    3.27  
    3.28 -        /* Set the desired scale. */
    3.29 -        ((CAMetalLayer *) self.layer).drawableSize = NSSizeToCGSize([self bounds].size);
    3.30 -        self.layer.contentsScale = scale;
    3.31 +        [self updateDrawableSize];
    3.32      }
    3.33    
    3.34      return self;
    3.35  }
    3.36  
    3.37 +- (NSInteger)tag
    3.38 +{
    3.39 +    return METALVIEW_TAG;
    3.40 +}
    3.41 +
    3.42 +- (void)updateDrawableSize
    3.43 +{
    3.44 +    CAMetalLayer *metalLayer = (CAMetalLayer *)self.layer;
    3.45 +    CGSize size = self.bounds.size;
    3.46 +    CGSize backingSize = size;
    3.47 +
    3.48 +    if (self.highDPI) {
    3.49 +        /* Note: NSHighResolutionCapable must be set to true in the app's
    3.50 +         * Info.plist in order for the backing size to be high res.
    3.51 +         */
    3.52 +        backingSize = [self convertSizeToBacking:size];
    3.53 +    }
    3.54 +
    3.55 +    metalLayer.contentsScale = backingSize.height / size.height;
    3.56 +    metalLayer.drawableSize = backingSize;
    3.57 +}
    3.58 +
    3.59  /* Set the size of the metal drawables when the view is resized. */
    3.60  - (void)resizeWithOldSuperviewSize:(NSSize)oldSize
    3.61  {
    3.62      [super resizeWithOldSuperviewSize:oldSize];
    3.63 +    [self updateDrawableSize];
    3.64  }
    3.65  
    3.66  @end
    3.67 @@ -87,24 +105,10 @@
    3.68  {
    3.69      SDL_WindowData* data = (__bridge SDL_WindowData *)window->driverdata;
    3.70      NSView *view = data->nswindow.contentView;
    3.71 -    CGFloat scale = 1.0;
    3.72 +    BOOL highDPI = (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) != 0;
    3.73 +    SDL_cocoametalview *metalview;
    3.74  
    3.75 -    if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
    3.76 -        /* Set the scale to the natural scale factor of the screen - then
    3.77 -         * the backing dimensions of the Metal view will match the pixel
    3.78 -         * dimensions of the screen rather than the dimensions in points
    3.79 -         * yielding high resolution on retine displays.
    3.80 -         *
    3.81 -         * N.B. In order for backingScaleFactor to be > 1,
    3.82 -         * NSHighResolutionCapable must be set to true in the app's Info.plist.
    3.83 -         */
    3.84 -        NSWindow* nswindow = data->nswindow;
    3.85 -        if ([nswindow.screen respondsToSelector:@selector(backingScaleFactor)])
    3.86 -            scale = data->nswindow.screen.backingScaleFactor;
    3.87 -    }
    3.88 -        
    3.89 -    SDL_cocoametalview *metalview
    3.90 -        = [[SDL_cocoametalview alloc] initWithFrame:view.frame scale:scale];
    3.91 +    metalview = [[SDL_cocoametalview alloc] initWithFrame:view.frame highDPI:highDPI];
    3.92      [view addSubview:metalview];
    3.93      return metalview;
    3.94  }
     4.1 --- a/src/video/uikit/SDL_uikitmetalview.m	Thu Oct 11 15:14:48 2018 -0700
     4.2 +++ b/src/video/uikit/SDL_uikitmetalview.m	Fri Oct 12 17:55:42 2018 -0300
     4.3 @@ -49,9 +49,8 @@
     4.4  {
     4.5      if ((self = [super initWithFrame:frame])) {
     4.6          self.tag = METALVIEW_TAG;
     4.7 -        /* Set the desired scale. */
     4.8 -        ((CAMetalLayer *) self.layer).drawableSize = self.bounds.size;
     4.9          self.layer.contentsScale = scale;
    4.10 +        [self updateDrawableSize];
    4.11      }
    4.12  
    4.13      return self;
    4.14 @@ -60,14 +59,16 @@
    4.15  /* Set the size of the metal drawables when the view is resized. */
    4.16  - (void)layoutSubviews
    4.17  {
    4.18 -    CGSize bounds;
    4.19 +    [super layoutSubviews];
    4.20 +    [self updateDrawableSize];
    4.21 +}
    4.22  
    4.23 -    [super layoutSubviews];
    4.24 -
    4.25 -    bounds = [self bounds].size;
    4.26 -    bounds.width *= self.layer.contentsScale;
    4.27 -    bounds.height *= self.layer.contentsScale;
    4.28 -    ((CAMetalLayer *) self.layer).drawableSize = bounds;
    4.29 +- (void)updateDrawableSize
    4.30 +{
    4.31 +    CGSize size = self.bounds.size;
    4.32 +    size.width *= self.layer.contentsScale;
    4.33 +    size.height *= self.layer.contentsScale;
    4.34 +    ((CAMetalLayer *)self.layer).drawableSize = size;
    4.35  }
    4.36  
    4.37  @end