emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

scratch/ns/performance a4e21a8 1/4: Improve drawing performance on macOS


From: Alan Third
Subject: scratch/ns/performance a4e21a8 1/4: Improve drawing performance on macOS
Date: Sun, 20 Dec 2020 05:47:51 -0500 (EST)

branch: scratch/ns/performance
commit a4e21a86cb6a51734391a7e3deebb5432f2d369c
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 888b415..88afd73 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 f292993..6c456d3 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;
@@ -729,6 +731,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 7972fa4..d48cf2e 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;
@@ -1165,7 +1169,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
@@ -1273,6 +1277,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
     }
@@ -3404,6 +3410,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))
@@ -3414,8 +3422,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:
@@ -6369,6 +6375,7 @@ not_in_argv (NSString *arg)
 
 #ifdef NS_DRAW_TO_BUFFER
   CGContextRelease (drawingBuffer);
+  CFRelease (surface);
 #endif
 
   [toolbar release];
@@ -8427,23 +8434,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
@@ -8453,6 +8484,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.  */
 {
@@ -8545,11 +8588,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
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]