Skip to content

Commit

Permalink
Fix high-dpi support on macOS and simplify it and iOS variant.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Mark Callow committed Feb 21, 2018
1 parent a0687a9 commit 6995844
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 44 deletions.
4 changes: 3 additions & 1 deletion include/SDL_video.h
Expand Up @@ -110,7 +110,9 @@ typedef enum
SDL_WINDOW_MOUSE_FOCUS = 0x00000400, /**< window has mouse focus */
SDL_WINDOW_FULLSCREEN_DESKTOP = ( SDL_WINDOW_FULLSCREEN | 0x00001000 ),
SDL_WINDOW_FOREIGN = 0x00000800, /**< window not created by SDL */
SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000, /**< window should be created in high-DPI mode if supported */
SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000, /**< window should be created in high-DPI mode if supported.
On macOS NSHighResolutionCapable must be set true in the
application's Info.plist for this to have any effect. */
SDL_WINDOW_MOUSE_CAPTURE = 0x00004000, /**< window has mouse captured (unrelated to INPUT_GRABBED) */
SDL_WINDOW_ALWAYS_ON_TOP = 0x00008000, /**< window should always be above others */
SDL_WINDOW_SKIP_TASKBAR = 0x00010000, /**< window should not be added to the taskbar */
Expand Down
3 changes: 3 additions & 0 deletions include/SDL_vulkan.h
Expand Up @@ -240,6 +240,9 @@ extern DECLSPEC SDL_bool SDLCALL SDL_Vulkan_CreateSurface(
* platform with high-DPI support (Apple calls this "Retina"), and not disabled
* by the \c SDL_HINT_VIDEO_HIGHDPI_DISABLED hint.
*
* \note On macOS high-DPI support must be enabled for an application by
* setting NSHighResolutionCapable to true in its Info.plist.
*
* \sa SDL_GetWindowSize()
* \sa SDL_CreateWindow()
*/
Expand Down
3 changes: 1 addition & 2 deletions src/video/cocoa/SDL_cocoametalview.h
Expand Up @@ -41,11 +41,10 @@

@interface SDL_cocoametalview : NSView {
NSInteger _tag;
bool _useHighDPI;
}

- (instancetype)initWithFrame:(NSRect)frame
useHighDPI:(bool)useHighDPI;
scale:(CGFloat)scale;

/* Override superclass tag so this class can set it. */
@property (assign, readonly) NSInteger tag;
Expand Down
44 changes: 26 additions & 18 deletions src/video/cocoa/SDL_cocoametalview.m
Expand Up @@ -57,17 +57,19 @@ - (CALayer*)makeBackingLayer
}

- (instancetype)initWithFrame:(NSRect)frame
useHighDPI:(bool)useHighDPI
scale:(CGFloat)scale
{
if ((self = [super initWithFrame:frame])) {
_tag = METALVIEW_TAG;
self.wantsLayer = YES;

/* Allow resize. */
self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
_tag = METALVIEW_TAG;

_useHighDPI = useHighDPI;
[self updateDrawableSize];
/* Set the desired scale. The default drawableSize of a CAMetalLayer
* is its bounds x its scale so nothing further needs to be done.
*/
self.layer.contentsScale = scale;
}

return self;
Expand All @@ -77,29 +79,33 @@ - (instancetype)initWithFrame:(NSRect)frame
- (void)resizeWithOldSuperviewSize:(NSSize)oldSize
{
[super resizeWithOldSuperviewSize:oldSize];
[self updateDrawableSize];
}

- (void)updateDrawableSize
{
NSRect bounds = [self bounds];
if (_useHighDPI) {
bounds = [self convertRectToBacking:bounds];
}
((CAMetalLayer *) self.layer).drawableSize = NSSizeToCGSize(bounds.size);
}

@end

SDL_cocoametalview*
Cocoa_Mtl_AddMetalView(SDL_Window* window)
{
SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
SDL_WindowData* data = (__bridge SDL_WindowData *)window->driverdata;
NSView *view = data->nswindow.contentView;

CGFloat scale = 1.0;

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
useHighDPI:(window->flags & SDL_WINDOW_ALLOW_HIGHDPI)];
= [[SDL_cocoametalview alloc] initWithFrame:view.frame scale:scale];
[view addSubview:metalview];
return metalview;
}
Expand All @@ -119,6 +125,8 @@ - (void)updateDrawableSize
if (h) {
*h = layer.drawableSize.height;
}
} else {
SDL_GetWindowSize(window, w, h);
}
}

Expand Down
3 changes: 1 addition & 2 deletions src/video/uikit/SDL_uikitmetalview.h
Expand Up @@ -43,8 +43,7 @@
@interface SDL_uikitmetalview : SDL_uikitview

- (instancetype)initWithFrame:(CGRect)frame
scale:(CGFloat)scale
tag:(int)tag;
scale:(CGFloat)scale;

@end

Expand Down
30 changes: 9 additions & 21 deletions src/video/uikit/SDL_uikitmetalview.m
Expand Up @@ -46,14 +46,12 @@ + (Class)layerClass

- (instancetype)initWithFrame:(CGRect)frame
scale:(CGFloat)scale
tag:(int)tag
{
if ((self = [super initWithFrame:frame])) {
/* Set the appropriate scale (for retina display support) */
self.contentScaleFactor = scale;
self.tag = tag;

[self updateDrawableSize];
self.tag = METALVIEW_TAG;
/* Set the desired scale. The default drawableSize of a CAMetalLayer
* is its bounds x its scale so nothing further needs to be done. */
self.layer.contentsScale = scale;
}

return self;
Expand All @@ -63,16 +61,6 @@ - (instancetype)initWithFrame:(CGRect)frame
- (void)layoutSubviews
{
[super layoutSubviews];
[self updateDrawableSize];
}

- (void)updateDrawableSize
{
CGSize size = self.bounds.size;
size.width *= self.contentScaleFactor;
size.height *= self.contentScaleFactor;

((CAMetalLayer *) self.layer).drawableSize = size;
}

@end
Expand All @@ -89,9 +77,10 @@ - (void)updateDrawableSize
}

if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
/* Set the scale to the natural scale factor of the screen - the
* backing dimensions of the Metal view will match the pixel
* dimensions of the screen rather than the dimensions in points.
/* 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.
*/
#ifdef __IPHONE_8_0
if ([data.uiwindow.screen respondsToSelector:@selector(nativeScale)]) {
Expand All @@ -104,8 +93,7 @@ - (void)updateDrawableSize
}
SDL_uikitmetalview *metalview
= [[SDL_uikitmetalview alloc] initWithFrame:view.frame
scale:scale
tag:METALVIEW_TAG];
scale:scale];
[metalview setSDLWindow:window];

return metalview;
Expand Down

0 comments on commit 6995844

Please sign in to comment.