metal: Fix high dpi and resizing on macOS, and clean up iOS code. Fixes bug #4250.

This commit is contained in:
Alex Szpakowski 2018-10-12 17:55:42 -03:00
parent 9a98e4b647
commit d9094421e1
4 changed files with 51 additions and 43 deletions

View File

@ -752,11 +752,6 @@ METAL_ActivateRenderCommandEncoder(SDL_Renderer * renderer, MTLLoadAction load)
static void static void
METAL_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) 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 || if (event->event == SDL_WINDOWEVENT_SHOWN ||
event->event == SDL_WINDOWEVENT_HIDDEN) { event->event == SDL_WINDOWEVENT_HIDDEN) {
// !!! FIXME: write me // !!! FIXME: write me
@ -848,12 +843,20 @@ METAL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
mtltexdesc.height = (texture->h + 1) / 2; mtltexdesc.height = (texture->h + 1) / 2;
mtltexdesc.textureType = MTLTextureType2DArray; mtltexdesc.textureType = MTLTextureType2DArray;
mtltexdesc.arrayLength = 2; mtltexdesc.arrayLength = 2;
mtltexture_uv = [data.mtldevice newTextureWithDescriptor:mtltexdesc];
} else if (nv12) { } else if (nv12) {
mtltexdesc.pixelFormat = MTLPixelFormatRG8Unorm; mtltexdesc.pixelFormat = MTLPixelFormatRG8Unorm;
mtltexdesc.width = (texture->w + 1) / 2; mtltexdesc.width = (texture->w + 1) / 2;
mtltexdesc.height = (texture->h + 1) / 2; mtltexdesc.height = (texture->h + 1) / 2;
}
if (yuv || nv12) {
mtltexture_uv = [data.mtldevice newTextureWithDescriptor:mtltexdesc]; 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]; METAL_TextureData *texturedata = [[METAL_TextureData alloc] init];

View File

@ -39,16 +39,16 @@
#define METALVIEW_TAG 255 #define METALVIEW_TAG 255
@interface SDL_cocoametalview : NSView { @interface SDL_cocoametalview : NSView
NSInteger _tag;
}
- (instancetype)initWithFrame:(NSRect)frame - (instancetype)initWithFrame:(NSRect)frame
scale:(CGFloat)scale; highDPI:(BOOL)highDPI;
/* Override superclass tag so this class can set it. */ /* Override superclass tag so this class can set it. */
@property (assign, readonly) NSInteger tag; @property (assign, readonly) NSInteger tag;
@property (nonatomic) BOOL highDPI;
@end @end
SDL_cocoametalview* Cocoa_Mtl_AddMetalView(SDL_Window* window); SDL_cocoametalview* Cocoa_Mtl_AddMetalView(SDL_Window* window);

View File

@ -33,9 +33,6 @@
@implementation SDL_cocoametalview @implementation SDL_cocoametalview
/* The synthesized getter should be called by super's viewWithTag. */
@synthesize tag = _tag;
/* Return a Metal-compatible layer. */ /* Return a Metal-compatible layer. */
+ (Class)layerClass + (Class)layerClass
{ {
@ -57,27 +54,48 @@
} }
- (instancetype)initWithFrame:(NSRect)frame - (instancetype)initWithFrame:(NSRect)frame
scale:(CGFloat)scale highDPI:(BOOL)highDPI
{ {
if ((self = [super initWithFrame:frame])) { if ((self = [super initWithFrame:frame])) {
_tag = METALVIEW_TAG; self.highDPI = highDPI;
self.wantsLayer = YES; self.wantsLayer = YES;
/* Allow resize. */ /* Allow resize. */
self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
/* Set the desired scale. */ [self updateDrawableSize];
((CAMetalLayer *) self.layer).drawableSize = NSSizeToCGSize([self bounds].size);
self.layer.contentsScale = scale;
} }
return self; 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. */ /* Set the size of the metal drawables when the view is resized. */
- (void)resizeWithOldSuperviewSize:(NSSize)oldSize - (void)resizeWithOldSuperviewSize:(NSSize)oldSize
{ {
[super resizeWithOldSuperviewSize:oldSize]; [super resizeWithOldSuperviewSize:oldSize];
[self updateDrawableSize];
} }
@end @end
@ -87,24 +105,10 @@ Cocoa_Mtl_AddMetalView(SDL_Window* window)
{ {
SDL_WindowData* data = (__bridge SDL_WindowData *)window->driverdata; SDL_WindowData* data = (__bridge SDL_WindowData *)window->driverdata;
NSView *view = data->nswindow.contentView; 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) { metalview = [[SDL_cocoametalview alloc] initWithFrame:view.frame highDPI: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];
[view addSubview:metalview]; [view addSubview:metalview];
return metalview; return metalview;
} }

View File

@ -49,9 +49,8 @@
{ {
if ((self = [super initWithFrame:frame])) { if ((self = [super initWithFrame:frame])) {
self.tag = METALVIEW_TAG; self.tag = METALVIEW_TAG;
/* Set the desired scale. */
((CAMetalLayer *) self.layer).drawableSize = self.bounds.size;
self.layer.contentsScale = scale; self.layer.contentsScale = scale;
[self updateDrawableSize];
} }
return self; return self;
@ -60,14 +59,16 @@
/* Set the size of the metal drawables when the view is resized. */ /* Set the size of the metal drawables when the view is resized. */
- (void)layoutSubviews - (void)layoutSubviews
{ {
CGSize bounds;
[super layoutSubviews]; [super layoutSubviews];
[self updateDrawableSize];
}
bounds = [self bounds].size; - (void)updateDrawableSize
bounds.width *= self.layer.contentsScale; {
bounds.height *= self.layer.contentsScale; CGSize size = self.bounds.size;
((CAMetalLayer *) self.layer).drawableSize = bounds; size.width *= self.layer.contentsScale;
size.height *= self.layer.contentsScale;
((CAMetalLayer *)self.layer).drawableSize = size;
} }
@end @end