summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Lutz <michi@icosahedron.de>2021-02-06 22:58:51 +0100
committerMichael Lutz <michi@icosahedron.de>2021-02-13 22:21:17 +0100
commit43326d11d8861721c9db45922bc7d42cf99dccba (patch)
tree6dad3b348bdb1f54449702adaf1b7b36d0b92971
parent2a8c3a2cf6460f8abb6032a449bf4cd4be01e847 (diff)
downloadopenttd-43326d11d8861721c9db45922bc7d42cf99dccba.tar.xz
Change: [OSX] Use a layer-backed view to speed up drawing.
-rw-r--r--CMakeLists.txt5
-rw-r--r--src/video/cocoa/cocoa_v.mm86
2 files changed, 19 insertions, 72 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c5d7ac113..2af3d30da 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -131,6 +131,7 @@ if(NOT WIN32)
find_library(AUDIOTOOLBOX_LIBRARY AudioToolbox)
find_library(AUDIOUNIT_LIBRARY AudioUnit)
find_library(COCOA_LIBRARY Cocoa)
+ find_library(QUARTZCORE_LIBRARY QuartzCore)
endif()
endif()
@@ -163,6 +164,9 @@ if(APPLE)
if(NOT COCOA_LIBRARY)
message(FATAL_ERROR "Cocoa is required for this platform")
endif()
+ if(NOT QUARTZCORE_LIBRARY)
+ message(FATAL_ERROR "QuartzCore is required for this platform")
+ endif()
endif()
if(OPTION_PACKAGE_DEPENDENCIES)
@@ -250,6 +254,7 @@ if(APPLE)
${AUDIOTOOLBOX_LIBRARY}
${AUDIOUNIT_LIBRARY}
${COCOA_LIBRARY}
+ ${QUARTZCORE_LIBRARY}
)
add_definitions(
diff --git a/src/video/cocoa/cocoa_v.mm b/src/video/cocoa/cocoa_v.mm
index f74c17c81..dea64e60d 100644
--- a/src/video/cocoa/cocoa_v.mm
+++ b/src/video/cocoa/cocoa_v.mm
@@ -100,8 +100,6 @@ static uint32 GetTick()
VideoDriver_Cocoa *driver;
}
- (instancetype)initWithFrame:(NSRect)frameRect andDriver:(VideoDriver_Cocoa *)drv;
-
-- (void)drawRect:(NSRect)invalidRect;
@end
@@ -708,6 +706,12 @@ void VideoDriver_Cocoa::GameLoop()
{
if (self = [ super initWithFrame:frameRect ]) {
self->driver = drv;
+
+ /* We manage our content updates ourselves. */
+ self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawOnSetNeedsDisplay;
+ self.wantsLayer = YES;
+
+ self.layer.magnificationFilter = kCAFilterNearest;
}
return self;
}
@@ -722,80 +726,18 @@ void VideoDriver_Cocoa::GameLoop()
return YES;
}
-- (void)drawRect:(NSRect)invalidRect
+- (BOOL)wantsUpdateLayer
{
- if (driver->cgcontext == nullptr) return;
-
- NSGraphicsContext *ctx = [ NSGraphicsContext currentContext ];
- CGContextRef viewContext = [ ctx respondsToSelector:@selector(CGContext) ] ? [ ctx CGContext ] : (CGContextRef)[ ctx graphicsPort ];
- CGContextSetShouldAntialias(viewContext, FALSE);
- CGContextSetInterpolationQuality(viewContext, kCGInterpolationNone);
+ return YES;
+}
- /* The obtained 'rect' is actually a union of all dirty rects, let's ask for an explicit list of rects instead */
- const NSRect *dirtyRects;
- NSInteger dirtyRectCount;
- [ self getRectsBeingDrawn:&dirtyRects count:&dirtyRectCount ];
+- (void)updateLayer
+{
+ if (driver->cgcontext == nullptr) return;
- /* We need an Image in order to do blitting, but as we don't touch the context between this call and drawing no copying will actually be done here */
+ /* Set layer contents to our backing buffer, which avoids needless copying. */
CGImageRef fullImage = CGBitmapContextCreateImage(driver->cgcontext);
-
- /* Calculate total area we are blitting */
- uint32 blitArea = 0;
- for (int n = 0; n < dirtyRectCount; n++) {
- blitArea += (uint32)(dirtyRects[n].size.width * dirtyRects[n].size.height);
- }
-
- /*
- * This might be completely stupid, but in my extremely subjective opinion it feels faster
- * The point is, if we're blitting less than 50% of the dirty rect union then it's still a good idea to blit each dirty
- * rect separately but if we blit more than that, it's just cheaper to blit the entire union in one pass.
- * Feel free to remove or find an even better value than 50% ... / blackis
- */
- NSRect frameRect = [ self frame ];
- if (blitArea / (float)(invalidRect.size.width * invalidRect.size.height) > 0.5f) {
- NSRect rect = invalidRect;
- CGRect clipRect;
- CGRect blitRect;
-
- blitRect.origin.x = rect.origin.x;
- blitRect.origin.y = rect.origin.y;
- blitRect.size.width = rect.size.width;
- blitRect.size.height = rect.size.height;
-
- clipRect.origin.x = rect.origin.x;
- clipRect.origin.y = frameRect.size.height - rect.origin.y - rect.size.height;
-
- clipRect.size.width = rect.size.width;
- clipRect.size.height = rect.size.height;
-
- /* Blit dirty part of image */
- CGImageRef clippedImage = CGImageCreateWithImageInRect(fullImage, clipRect);
- CGContextDrawImage(viewContext, blitRect, clippedImage);
- CGImageRelease(clippedImage);
- } else {
- for (int n = 0; n < dirtyRectCount; n++) {
- NSRect rect = dirtyRects[n];
- CGRect clipRect;
- CGRect blitRect;
-
- blitRect.origin.x = rect.origin.x;
- blitRect.origin.y = rect.origin.y;
- blitRect.size.width = rect.size.width;
- blitRect.size.height = rect.size.height;
-
- clipRect.origin.x = rect.origin.x;
- clipRect.origin.y = frameRect.size.height - rect.origin.y - rect.size.height;
-
- clipRect.size.width = rect.size.width;
- clipRect.size.height = rect.size.height;
-
- /* Blit dirty part of image */
- CGImageRef clippedImage = CGImageCreateWithImageInRect(fullImage, clipRect);
- CGContextDrawImage(viewContext, blitRect, clippedImage);
- CGImageRelease(clippedImage);
- }
- }
-
+ self.layer.contents = (__bridge id)fullImage;
CGImageRelease(fullImage);
}