From d9094421e16594438f248ac73491b7a75224ad77 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Fri, 12 Oct 2018 17:55:42 -0300 Subject: [PATCH] metal: Fix high dpi and resizing on macOS, and clean up iOS code. Fixes bug #4250. --- src/render/metal/SDL_render_metal.m | 15 ++++---- src/video/cocoa/SDL_cocoametalview.h | 8 ++--- src/video/cocoa/SDL_cocoametalview.m | 54 +++++++++++++++------------- src/video/uikit/SDL_uikitmetalview.m | 17 ++++----- 4 files changed, 51 insertions(+), 43 deletions(-) diff --git a/src/render/metal/SDL_render_metal.m b/src/render/metal/SDL_render_metal.m index 10c585b20..1fc0a4f29 100644 --- a/src/render/metal/SDL_render_metal.m +++ b/src/render/metal/SDL_render_metal.m @@ -752,11 +752,6 @@ METAL_ActivateRenderCommandEncoder(SDL_Renderer * renderer, MTLLoadAction load) static void METAL_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) { - if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) { - METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata; - data.mtllayer.drawableSize = CGSizeMake(event->data1, event->data2); - } - if (event->event == SDL_WINDOWEVENT_SHOWN || event->event == SDL_WINDOWEVENT_HIDDEN) { // !!! FIXME: write me @@ -848,12 +843,20 @@ METAL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) mtltexdesc.height = (texture->h + 1) / 2; mtltexdesc.textureType = MTLTextureType2DArray; mtltexdesc.arrayLength = 2; - mtltexture_uv = [data.mtldevice newTextureWithDescriptor:mtltexdesc]; } else if (nv12) { mtltexdesc.pixelFormat = MTLPixelFormatRG8Unorm; mtltexdesc.width = (texture->w + 1) / 2; mtltexdesc.height = (texture->h + 1) / 2; + } + + if (yuv || nv12) { mtltexture_uv = [data.mtldevice newTextureWithDescriptor:mtltexdesc]; + if (mtltexture_uv == nil) { +#if !__has_feature(objc_arc) + [mtltexture release]; +#endif + return SDL_SetError("Texture allocation failed"); + } } METAL_TextureData *texturedata = [[METAL_TextureData alloc] init]; diff --git a/src/video/cocoa/SDL_cocoametalview.h b/src/video/cocoa/SDL_cocoametalview.h index c0a582ff4..185d45deb 100644 --- a/src/video/cocoa/SDL_cocoametalview.h +++ b/src/video/cocoa/SDL_cocoametalview.h @@ -39,16 +39,16 @@ #define METALVIEW_TAG 255 -@interface SDL_cocoametalview : NSView { - NSInteger _tag; -} +@interface SDL_cocoametalview : NSView - (instancetype)initWithFrame:(NSRect)frame - scale:(CGFloat)scale; + highDPI:(BOOL)highDPI; /* Override superclass tag so this class can set it. */ @property (assign, readonly) NSInteger tag; +@property (nonatomic) BOOL highDPI; + @end SDL_cocoametalview* Cocoa_Mtl_AddMetalView(SDL_Window* window); diff --git a/src/video/cocoa/SDL_cocoametalview.m b/src/video/cocoa/SDL_cocoametalview.m index 8b7a697a4..9447fb8c6 100644 --- a/src/video/cocoa/SDL_cocoametalview.m +++ b/src/video/cocoa/SDL_cocoametalview.m @@ -33,9 +33,6 @@ @implementation SDL_cocoametalview -/* The synthesized getter should be called by super's viewWithTag. */ -@synthesize tag = _tag; - /* Return a Metal-compatible layer. */ + (Class)layerClass { @@ -57,27 +54,48 @@ } - (instancetype)initWithFrame:(NSRect)frame - scale:(CGFloat)scale + highDPI:(BOOL)highDPI { if ((self = [super initWithFrame:frame])) { - _tag = METALVIEW_TAG; + self.highDPI = highDPI; self.wantsLayer = YES; /* Allow resize. */ self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; - /* Set the desired scale. */ - ((CAMetalLayer *) self.layer).drawableSize = NSSizeToCGSize([self bounds].size); - self.layer.contentsScale = scale; + [self updateDrawableSize]; } return self; } +- (NSInteger)tag +{ + return METALVIEW_TAG; +} + +- (void)updateDrawableSize +{ + CAMetalLayer *metalLayer = (CAMetalLayer *)self.layer; + CGSize size = self.bounds.size; + CGSize backingSize = size; + + if (self.highDPI) { + /* Note: NSHighResolutionCapable must be set to true in the app's + * Info.plist in order for the backing size to be high res. + */ + backingSize = [self convertSizeToBacking:size]; + } + + metalLayer.contentsScale = backingSize.height / size.height; + metalLayer.drawableSize = backingSize; +} + /* Set the size of the metal drawables when the view is resized. */ - (void)resizeWithOldSuperviewSize:(NSSize)oldSize { [super resizeWithOldSuperviewSize:oldSize]; + [self updateDrawableSize]; } @end @@ -87,24 +105,10 @@ Cocoa_Mtl_AddMetalView(SDL_Window* window) { SDL_WindowData* data = (__bridge SDL_WindowData *)window->driverdata; NSView *view = data->nswindow.contentView; - CGFloat scale = 1.0; + BOOL highDPI = (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) != 0; + SDL_cocoametalview *metalview; - if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) { - /* Set the scale to the natural scale factor of the screen - then - * the backing dimensions of the Metal view will match the pixel - * dimensions of the screen rather than the dimensions in points - * yielding high resolution on retine displays. - * - * N.B. In order for backingScaleFactor to be > 1, - * NSHighResolutionCapable must be set to true in the app's Info.plist. - */ - NSWindow* nswindow = data->nswindow; - if ([nswindow.screen respondsToSelector:@selector(backingScaleFactor)]) - scale = data->nswindow.screen.backingScaleFactor; - } - - SDL_cocoametalview *metalview - = [[SDL_cocoametalview alloc] initWithFrame:view.frame scale:scale]; + metalview = [[SDL_cocoametalview alloc] initWithFrame:view.frame highDPI:highDPI]; [view addSubview:metalview]; return metalview; } diff --git a/src/video/uikit/SDL_uikitmetalview.m b/src/video/uikit/SDL_uikitmetalview.m index fd94300d0..436e7425a 100644 --- a/src/video/uikit/SDL_uikitmetalview.m +++ b/src/video/uikit/SDL_uikitmetalview.m @@ -49,9 +49,8 @@ { if ((self = [super initWithFrame:frame])) { self.tag = METALVIEW_TAG; - /* Set the desired scale. */ - ((CAMetalLayer *) self.layer).drawableSize = self.bounds.size; self.layer.contentsScale = scale; + [self updateDrawableSize]; } return self; @@ -60,14 +59,16 @@ /* Set the size of the metal drawables when the view is resized. */ - (void)layoutSubviews { - CGSize bounds; - [super layoutSubviews]; + [self updateDrawableSize]; +} - bounds = [self bounds].size; - bounds.width *= self.layer.contentsScale; - bounds.height *= self.layer.contentsScale; - ((CAMetalLayer *) self.layer).drawableSize = bounds; +- (void)updateDrawableSize +{ + CGSize size = self.bounds.size; + size.width *= self.layer.contentsScale; + size.height *= self.layer.contentsScale; + ((CAMetalLayer *)self.layer).drawableSize = size; } @end