metal: Fix high dpi and resizing on macOS, and clean up iOS code. Fixes bug #4250.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
diff --git a/src/render/metal/SDL_render_metal.m b/src/render/metal/SDL_render_metal.m
index 10c585b..1fc0a4f 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 c0a582f..185d45d 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 8b7a697..9447fb8 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;
-
- 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];
+ BOOL highDPI = (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) != 0;
+ SDL_cocoametalview *metalview;
+
+ 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 fd94300..436e742 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