aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAlan Third2021-05-21 13:33:56 +0100
committerAlan Third2021-06-01 19:51:21 +0100
commit246e107d73e633c06478eaf021776acedef9dafc (patch)
treecb4ac63a1b3f6168fa7d013a792c427ccb2ec4ae /src
parenta32e65b357ff634a976a24ee5d5c340addc025cd (diff)
downloademacs-246e107d73e633c06478eaf021776acedef9dafc.tar.gz
emacs-246e107d73e633c06478eaf021776acedef9dafc.zip
Improve performance of NS port's display on macOS
* src/nsterm.h: Update EmacsSurface definition. * src/nsterm.m ([EmacsView focusOnDrawingBuffer]): Don't change the CGContext's settings directly. ([EmacsView unfocusDrawingBuffer]): Don't release the context here. (CACHE_MAX_SIZE): Add maximum cache size. ([EmacsView updateLayer]): Send a request for getContext, which will copy the buffer and create the context if it doesn't already exist, to the NS run loop. ([EmacsSurface initWithSize:ColorSpace:Scale:]): Add the scale factor and if there's already a CGContext available, reuse it. ([EmacsSurface dealloc]): No longer need to release lastSurface separately. ([EmacsSurface getContext]): Don't create more surfaces than we have spaces for in the cache. ([EmacsSurface releaseContext]): If there's no context don't try to release it and put currentSurface back on the cache instead of lastSurface. ([EmacsSurface copyContentsTo:]): Don't try to copy if the source and destination are actually the same surface.
Diffstat (limited to 'src')
-rw-r--r--src/nsterm.h3
-rw-r--r--src/nsterm.m121
2 files changed, 72 insertions, 52 deletions
diff --git a/src/nsterm.h b/src/nsterm.h
index 017c2394ef1..0596f3f3c10 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -724,8 +724,9 @@ typedef id instancetype;
724 IOSurfaceRef currentSurface; 724 IOSurfaceRef currentSurface;
725 IOSurfaceRef lastSurface; 725 IOSurfaceRef lastSurface;
726 CGContextRef context; 726 CGContextRef context;
727 CGFloat scale;
727} 728}
728- (id) initWithSize: (NSSize)s ColorSpace: (CGColorSpaceRef)cs; 729- (id) initWithSize: (NSSize)s ColorSpace: (CGColorSpaceRef)cs Scale: (CGFloat)scale;
729- (void) dealloc; 730- (void) dealloc;
730- (NSSize) getSize; 731- (NSSize) getSize;
731- (CGContextRef) getContext; 732- (CGContextRef) getContext;
diff --git a/src/nsterm.m b/src/nsterm.m
index bb20886ab1d..f6168243a49 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -8353,19 +8353,17 @@ not_in_argv (NSString *arg)
8353 8353
8354 surface = [[EmacsSurface alloc] initWithSize:s 8354 surface = [[EmacsSurface alloc] initWithSize:s
8355 ColorSpace:[[[self window] colorSpace] 8355 ColorSpace:[[[self window] colorSpace]
8356 CGColorSpace]]; 8356 CGColorSpace]
8357 Scale:scale];
8357 8358
8358 /* Since we're using NSViewLayerContentsRedrawOnSetNeedsDisplay 8359 /* Since we're using NSViewLayerContentsRedrawOnSetNeedsDisplay
8359 the layer's scale factor is not set automatically, so do it 8360 the layer's scale factor is not set automatically, so do it
8360 now. */ 8361 now. */
8361 [[self layer] setContentsScale:[[self window] backingScaleFactor]]; 8362 [[self layer] setContentsScale:scale];
8362 } 8363 }
8363 8364
8364 CGContextRef context = [surface getContext]; 8365 CGContextRef context = [surface getContext];
8365 8366
8366 CGContextTranslateCTM(context, 0, [surface getSize].height);
8367 CGContextScaleCTM(context, scale, -scale);
8368
8369 [NSGraphicsContext 8367 [NSGraphicsContext
8370 setCurrentContext:[NSGraphicsContext 8368 setCurrentContext:[NSGraphicsContext
8371 graphicsContextWithCGContext:context 8369 graphicsContextWithCGContext:context
@@ -8378,7 +8376,6 @@ not_in_argv (NSString *arg)
8378 NSTRACE ("[EmacsView unfocusDrawingBuffer]"); 8376 NSTRACE ("[EmacsView unfocusDrawingBuffer]");
8379 8377
8380 [NSGraphicsContext setCurrentContext:nil]; 8378 [NSGraphicsContext setCurrentContext:nil];
8381 [surface releaseContext];
8382 [self setNeedsDisplay:YES]; 8379 [self setNeedsDisplay:YES];
8383} 8380}
8384 8381
@@ -8516,7 +8513,11 @@ not_in_argv (NSString *arg)
8516 There's a private method, -[CALayer setContentsChanged], that we 8513 There's a private method, -[CALayer setContentsChanged], that we
8517 could use to force it, but we shouldn't often get the same 8514 could use to force it, but we shouldn't often get the same
8518 surface twice in a row. */ 8515 surface twice in a row. */
8516 [surface releaseContext];
8519 [[self layer] setContents:(id)[surface getSurface]]; 8517 [[self layer] setContents:(id)[surface getSurface]];
8518 [surface performSelectorOnMainThread:@selector (getContext)
8519 withObject:nil
8520 waitUntilDone:NO];
8520} 8521}
8521#endif 8522#endif
8522 8523
@@ -9717,17 +9718,20 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
9717 probably be some sort of pruning job that removes excess 9718 probably be some sort of pruning job that removes excess
9718 surfaces. */ 9719 surfaces. */
9719 9720
9721#define CACHE_MAX_SIZE 2
9720 9722
9721- (id) initWithSize: (NSSize)s 9723- (id) initWithSize: (NSSize)s
9722 ColorSpace: (CGColorSpaceRef)cs 9724 ColorSpace: (CGColorSpaceRef)cs
9725 Scale: (CGFloat)scl
9723{ 9726{
9724 NSTRACE ("[EmacsSurface initWithSize:ColorSpace:]"); 9727 NSTRACE ("[EmacsSurface initWithSize:ColorSpace:]");
9725 9728
9726 [super init]; 9729 [super init];
9727 9730
9728 cache = [[NSMutableArray arrayWithCapacity:3] retain]; 9731 cache = [[NSMutableArray arrayWithCapacity:CACHE_MAX_SIZE] retain];
9729 size = s; 9732 size = s;
9730 colorSpace = cs; 9733 colorSpace = cs;
9734 scale = scl;
9731 9735
9732 return self; 9736 return self;
9733} 9737}
@@ -9740,8 +9744,6 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
9740 9744
9741 if (currentSurface) 9745 if (currentSurface)
9742 CFRelease (currentSurface); 9746 CFRelease (currentSurface);
9743 if (lastSurface)
9744 CFRelease (lastSurface);
9745 9747
9746 for (id object in cache) 9748 for (id object in cache)
9747 CFRelease ((IOSurfaceRef)object); 9749 CFRelease ((IOSurfaceRef)object);
@@ -9764,50 +9766,66 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
9764 calls cannot be nested. */ 9766 calls cannot be nested. */
9765- (CGContextRef) getContext 9767- (CGContextRef) getContext
9766{ 9768{
9767 IOSurfaceRef surface = NULL; 9769 NSTRACE ("[EmacsSurface getContext]");
9768
9769 NSTRACE ("[EmacsSurface getContextWithSize:]");
9770 NSTRACE_MSG ("IOSurface count: %lu", [cache count] + (lastSurface ? 1 : 0));
9771 9770
9772 for (id object in cache) 9771 if (!context)
9773 { 9772 {
9774 if (!IOSurfaceIsInUse ((IOSurfaceRef)object)) 9773 IOSurfaceRef surface = NULL;
9775 {
9776 surface = (IOSurfaceRef)object;
9777 [cache removeObject:object];
9778 break;
9779 }
9780 }
9781 9774
9782 if (!surface) 9775 NSTRACE_MSG ("IOSurface count: %lu", [cache count] + (lastSurface ? 1 : 0));
9783 {
9784 int bytesPerRow = IOSurfaceAlignProperty (kIOSurfaceBytesPerRow,
9785 size.width * 4);
9786 9776
9787 surface = IOSurfaceCreate 9777 for (id object in cache)
9788 ((CFDictionaryRef)@{(id)kIOSurfaceWidth:[NSNumber numberWithInt:size.width], 9778 {
9789 (id)kIOSurfaceHeight:[NSNumber numberWithInt:size.height], 9779 if (!IOSurfaceIsInUse ((IOSurfaceRef)object))
9790 (id)kIOSurfaceBytesPerRow:[NSNumber numberWithInt:bytesPerRow], 9780 {
9791 (id)kIOSurfaceBytesPerElement:[NSNumber numberWithInt:4], 9781 surface = (IOSurfaceRef)object;
9792 (id)kIOSurfacePixelFormat:[NSNumber numberWithUnsignedInt:'BGRA']}); 9782 [cache removeObject:object];
9793 } 9783 break;
9784 }
9785 }
9794 9786
9795 IOReturn lockStatus = IOSurfaceLock (surface, 0, nil); 9787 if (!surface && [cache count] >= CACHE_MAX_SIZE)
9796 if (lockStatus != kIOReturnSuccess) 9788 {
9797 NSLog (@"Failed to lock surface: %x", lockStatus); 9789 /* Just grab the first one off the cache. This may result
9790 in tearing effects. The alternative is to wait for one
9791 of the surfaces to become free. */
9792 surface = (IOSurfaceRef)[cache firstObject];
9793 [cache removeObject:(id)surface];
9794 }
9795 else if (!surface)
9796 {
9797 int bytesPerRow = IOSurfaceAlignProperty (kIOSurfaceBytesPerRow,
9798 size.width * 4);
9799
9800 surface = IOSurfaceCreate
9801 ((CFDictionaryRef)@{(id)kIOSurfaceWidth:[NSNumber numberWithInt:size.width],
9802 (id)kIOSurfaceHeight:[NSNumber numberWithInt:size.height],
9803 (id)kIOSurfaceBytesPerRow:[NSNumber numberWithInt:bytesPerRow],
9804 (id)kIOSurfaceBytesPerElement:[NSNumber numberWithInt:4],
9805 (id)kIOSurfacePixelFormat:[NSNumber numberWithUnsignedInt:'BGRA']});
9806 }
9807
9808 IOReturn lockStatus = IOSurfaceLock (surface, 0, nil);
9809 if (lockStatus != kIOReturnSuccess)
9810 NSLog (@"Failed to lock surface: %x", lockStatus);
9798 9811
9799 [self copyContentsTo:surface]; 9812 [self copyContentsTo:surface];
9800 9813
9801 currentSurface = surface; 9814 currentSurface = surface;
9815
9816 context = CGBitmapContextCreate (IOSurfaceGetBaseAddress (currentSurface),
9817 IOSurfaceGetWidth (currentSurface),
9818 IOSurfaceGetHeight (currentSurface),
9819 8,
9820 IOSurfaceGetBytesPerRow (currentSurface),
9821 colorSpace,
9822 (kCGImageAlphaPremultipliedFirst
9823 | kCGBitmapByteOrder32Host));
9824
9825 CGContextTranslateCTM(context, 0, size.height);
9826 CGContextScaleCTM(context, scale, -scale);
9827 }
9802 9828
9803 context = CGBitmapContextCreate (IOSurfaceGetBaseAddress (currentSurface),
9804 IOSurfaceGetWidth (currentSurface),
9805 IOSurfaceGetHeight (currentSurface),
9806 8,
9807 IOSurfaceGetBytesPerRow (currentSurface),
9808 colorSpace,
9809 (kCGImageAlphaPremultipliedFirst
9810 | kCGBitmapByteOrder32Host));
9811 return context; 9829 return context;
9812} 9830}
9813 9831
@@ -9818,6 +9836,9 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
9818{ 9836{
9819 NSTRACE ("[EmacsSurface releaseContextAndGetSurface]"); 9837 NSTRACE ("[EmacsSurface releaseContextAndGetSurface]");
9820 9838
9839 if (!context)
9840 return;
9841
9821 CGContextRelease (context); 9842 CGContextRelease (context);
9822 context = NULL; 9843 context = NULL;
9823 9844
@@ -9825,11 +9846,8 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
9825 if (lockStatus != kIOReturnSuccess) 9846 if (lockStatus != kIOReturnSuccess)
9826 NSLog (@"Failed to unlock surface: %x", lockStatus); 9847 NSLog (@"Failed to unlock surface: %x", lockStatus);
9827 9848
9828 /* Put lastSurface back on the end of the cache. It may not have 9849 /* Put currentSurface back on the end of the cache. */
9829 been displayed on the screen yet, but we probably want the new 9850 [cache addObject:(id)currentSurface];
9830 data and not some stale data anyway. */
9831 if (lastSurface)
9832 [cache addObject:(id)lastSurface];
9833 lastSurface = currentSurface; 9851 lastSurface = currentSurface;
9834 currentSurface = NULL; 9852 currentSurface = NULL;
9835} 9853}
@@ -9854,7 +9872,7 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
9854 9872
9855 NSTRACE ("[EmacsSurface copyContentsTo:]"); 9873 NSTRACE ("[EmacsSurface copyContentsTo:]");
9856 9874
9857 if (! lastSurface) 9875 if (!lastSurface || lastSurface == destination)
9858 return; 9876 return;
9859 9877
9860 lockStatus = IOSurfaceLock (lastSurface, kIOSurfaceLockReadOnly, nil); 9878 lockStatus = IOSurfaceLock (lastSurface, kIOSurfaceLockReadOnly, nil);
@@ -9874,6 +9892,7 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
9874 NSLog (@"Failed to unlock source surface: %x", lockStatus); 9892 NSLog (@"Failed to unlock source surface: %x", lockStatus);
9875} 9893}
9876 9894
9895#undef CACHE_MAX_SIZE
9877 9896
9878@end /* EmacsSurface */ 9897@end /* EmacsSurface */
9879 9898