[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
scratch/ns/performance ee1444f 1/5: Improve drawing performance on macOS
From: |
Alan Third |
Subject: |
scratch/ns/performance ee1444f 1/5: Improve drawing performance on macOS |
Date: |
Sun, 27 Dec 2020 12:20:24 -0500 (EST) |
branch: scratch/ns/performance
commit ee1444f6ec719e55e565b34c24a8e57672a401a8
Author: Alan Third <alan@idiocy.org>
Commit: Alan Third <alan@idiocy.org>
Improve drawing performance on macOS
* configure.ac: Require IOSurface framework.
* src/nsterm.h: Add new definitions.
* src/nsterm.m (ns_update_end):
(ns_unfocus): Use new unfocusDrawingBuffer method.
(ns_draw_window_cursor): Move ns_focus to before we set colors.
([EmacsView dealloc]): Release the new IOSurface.
([EmacsView createDrawingBuffer]): Use a new IOSurface to draw to
and point a CGBitmapContext to it.
([EmacsView focusOnDrawingBuffer]): Lock the IOSurface for drawing.
([EmacsView unfocusDrawingBuffer]): New function.
([EmacsView updateLayer]): Use the IOSurface.
---
configure.ac | 2 +-
src/nsterm.h | 13 ++++++++++++
src/nsterm.m | 68 +++++++++++++++++++++++++++++++++++++++++++++++++-----------
3 files changed, 70 insertions(+), 13 deletions(-)
diff --git a/configure.ac b/configure.ac
index bf76844..0aa91ea 100644
--- a/configure.ac
+++ b/configure.ac
@@ -5491,7 +5491,7 @@ case "$opsys" in
if test "$HAVE_NS" = "yes"; then
libs_nsgui="-framework AppKit"
if test "$NS_IMPL_COCOA" = "yes"; then
- libs_nsgui="$libs_nsgui -framework IOKit -framework Carbon"
+ libs_nsgui="$libs_nsgui -framework IOKit -framework Carbon -framework
IOSurface"
fi
else
libs_nsgui=
diff --git a/src/nsterm.h b/src/nsterm.h
index b7b4d3b..59a0bc0 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -435,6 +435,7 @@ typedef id instancetype;
BOOL fs_is_native;
BOOL in_fullscreen_transition;
#ifdef NS_DRAW_TO_BUFFER
+ IOSurfaceRef surface;
CGContextRef drawingBuffer;
#endif
@public
@@ -478,6 +479,7 @@ typedef id instancetype;
#ifdef NS_DRAW_TO_BUFFER
- (void)focusOnDrawingBuffer;
+- (void)unfocusDrawingBuffer;
- (void)createDrawingBuffer;
#endif
- (void)copyRect:(NSRect)srcRect to:(NSRect)dstRect;
@@ -723,6 +725,17 @@ extern EmacsMenu *svcsMenu;
@end
#endif
+/* This is a private API, but it seems we need it to force the CALayer
+ to recognise that the IOSurface has been updated.
+
+ I believe using it will prevent Emacs from ever making it into the
+ Apple App Store. 😎 */
+#ifdef NS_DRAW_TO_BUFFER
+@interface CALayer (Private)
+- (void)setContentsChanged;
+@end
+#endif
+
#endif /* __OBJC__ */
diff --git a/src/nsterm.m b/src/nsterm.m
index 1616774..4b32531 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -72,6 +72,10 @@ GNUstep port and post-20 update by Adrian Robert
(arobert@cogsci.ucsd.edu)
#include <Carbon/Carbon.h>
#endif
+#ifdef NS_DRAW_TO_BUFFER
+#include <IOSurface/IOSurface.h>
+#endif
+
static EmacsMenu *dockMenu;
#ifdef NS_IMPL_COCOA
static EmacsMenu *mainMenu;
@@ -1147,7 +1151,7 @@ ns_update_end (struct frame *f)
if ([FRAME_NS_VIEW (f) wantsUpdateLayer])
{
#endif
- [NSGraphicsContext setCurrentContext:nil];
+ [FRAME_NS_VIEW (f) unfocusDrawingBuffer];
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
}
else
@@ -1255,6 +1259,8 @@ ns_unfocus (struct frame *f)
if ([FRAME_NS_VIEW (f) wantsUpdateLayer])
{
#endif
+ if (! ns_updating_frame)
+ [FRAME_NS_VIEW (f) unfocusDrawingBuffer];
[FRAME_NS_VIEW (f) setNeedsDisplay:YES];
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
}
@@ -3386,6 +3392,8 @@ ns_draw_window_cursor (struct window *w, struct glyph_row
*glyph_row,
/* Prevent the cursor from being drawn outside the text area. */
r = NSIntersectionRect (r, ns_row_rect (w, glyph_row, TEXT_AREA));
+ ns_focus (f, &r, 1);
+
face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id);
if (face && NS_FACE_BACKGROUND (face)
== ns_index_color (FRAME_CURSOR_COLOR (f), f))
@@ -3396,8 +3404,6 @@ ns_draw_window_cursor (struct window *w, struct glyph_row
*glyph_row,
else
[FRAME_CURSOR_COLOR (f) set];
- ns_focus (f, &r, 1);
-
switch (cursor_type)
{
case DEFAULT_CURSOR:
@@ -6267,6 +6273,7 @@ not_in_argv (NSString *arg)
#ifdef NS_DRAW_TO_BUFFER
CGContextRelease (drawingBuffer);
+ CFRelease (surface);
#endif
[toolbar release];
@@ -8324,23 +8331,47 @@ not_in_argv (NSString *arg)
CGColorSpaceRef colorSpace = [[[self window] colorSpace] CGColorSpace];
CGFloat scale = [[self window] backingScaleFactor];
NSRect frame = [self frame];
+ int width, height, bytesPerRow;
if (drawingBuffer != nil)
- CGContextRelease (drawingBuffer);
+ {
+ CGContextRelease (drawingBuffer);
+ CFRelease (surface);
+ }
+
+ width = NSWidth (frame) * scale;
+ height = NSHeight (frame) * scale;
+ bytesPerRow = IOSurfaceAlignProperty (kIOSurfaceBytesPerRow, width * 4);
- drawingBuffer = CGBitmapContextCreate (nil, NSWidth (frame) * scale,
NSHeight (frame) * scale,
- 8, 0, colorSpace,
- kCGImageAlphaPremultipliedFirst |
kCGBitmapByteOrder32Host);
+ surface = IOSurfaceCreate
+ ((CFDictionaryRef)@{(id)kIOSurfaceWidth:[NSNumber numberWithInt:width],
+ (id)kIOSurfaceHeight:[NSNumber numberWithInt:height],
+ (id)kIOSurfaceBytesPerRow:[NSNumber numberWithInt:bytesPerRow],
+ (id)kIOSurfaceBytesPerElement:[NSNumber numberWithInt:4],
+ (id)kIOSurfacePixelFormat:[NSNumber
numberWithInt:kCVPixelFormatType_32RGBA]});
+
+ drawingBuffer = CGBitmapContextCreate (IOSurfaceGetBaseAddress (surface),
+ IOSurfaceGetWidth (surface),
+ IOSurfaceGetHeight (surface),
+ 8,
+ IOSurfaceGetBytesPerRow (surface),
+ colorSpace,
+ IOSurfaceGetPixelFormat (surface));
/* This fixes the scale to match the backing scale factor, and flips the
image. */
- CGContextTranslateCTM(drawingBuffer, 0, NSHeight (frame) * scale);
+ CGContextTranslateCTM(drawingBuffer, 0, IOSurfaceGetHeight (surface));
CGContextScaleCTM(drawingBuffer, scale, -scale);
}
- (void)focusOnDrawingBuffer
{
- NSTRACE ("EmacsView focusOnDrawingBuffer]");
+ IOReturn lockStatus;
+
+ NSTRACE ("[EmacsView focusOnDrawingBuffer]");
+
+ if ((lockStatus = IOSurfaceLock (surface, 0, nil)) != kIOReturnSuccess)
+ NSLog (@"Failed to lock surface: %x", lockStatus);
NSGraphicsContext *buf =
[NSGraphicsContext
@@ -8350,6 +8381,18 @@ not_in_argv (NSString *arg)
}
+- (void)unfocusDrawingBuffer
+{
+ IOReturn lockStatus;
+
+ NSTRACE ("[EmacsView unfocusDrawingBuffer]");
+
+ [NSGraphicsContext setCurrentContext:nil];
+ if ((lockStatus = IOSurfaceUnlock (surface, 0, nil)) != kIOReturnSuccess)
+ NSLog (@"Failed to unlock surface: %x", lockStatus);
+}
+
+
- (void)windowDidChangeBackingProperties:(NSNotification *)notification
/* Update the drawing buffer when the backing properties change. */
{
@@ -8442,11 +8485,12 @@ not_in_argv (NSString *arg)
- (void)updateLayer
{
+ CALayer *layer = [self layer];
+
NSTRACE ("[EmacsView updateLayer]");
- CGImageRef contentsImage = CGBitmapContextCreateImage(drawingBuffer);
- [[self layer] setContents:(id)contentsImage];
- CGImageRelease(contentsImage);
+ [layer setContents:(id)surface];
+ [layer setContentsChanged];
}
#endif