]> git.eshelyaron.com Git - emacs.git/commitdiff
Simplify the EmacsLayer double buffering code (bug#63187)
authorAlan Third <alan@idiocy.org>
Sun, 23 Jul 2023 11:00:30 +0000 (12:00 +0100)
committerAlan Third <alan@idiocy.org>
Mon, 11 Sep 2023 16:22:00 +0000 (17:22 +0100)
src/nsfns.m
src/nsterm.h
src/nsterm.m

index a79892f73b667a6d3c637b9f88a6b51ac649393d..082e06698b2ae4f261ca9df2efa4926fa01ee6e7 100644 (file)
@@ -799,6 +799,26 @@ ns_set_child_frame_border_width (struct frame *f, Lisp_Object arg,
     }
 }
 
+static void
+ns_set_inhibit_double_buffering (struct frame *f,
+                                 Lisp_Object new_value,
+                                 Lisp_Object old_value)
+{
+#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MIN_REQUIRED >= 101400
+  if (!EQ (new_value, old_value))
+    {
+      FRAME_DOUBLE_BUFFERED (f) = NILP (new_value);
+
+      /* If the view or layer haven't been created yet this will be a
+         noop.  */
+      [(EmacsLayer *)[FRAME_NS_VIEW (f) layer]
+          setDoubleBuffered:FRAME_DOUBLE_BUFFERED (f)];
+
+      SET_FRAME_GARBAGED (f);
+    }
+#endif
+}
+
 static void
 ns_set_internal_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
 {
@@ -1073,7 +1093,7 @@ frame_parm_handler ns_frame_parm_handlers[] =
   gui_set_alpha,
   0, /* x_set_sticky */
   ns_set_tool_bar_position,
-  0, /* x_set_inhibit_double_buffering */
+  ns_set_inhibit_double_buffering,
   ns_set_undecorated,
   ns_set_parent_frame,
   0, /* x_set_skip_taskbar */
@@ -1461,6 +1481,14 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
   gui_default_parameter (f, parms, Qtitle, Qnil, "title", "Title",
                          RES_TYPE_STRING);
 
+#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MIN_REQUIRED >= 101400
+  tem = gui_display_get_arg (dpyinfo, parms, Qinhibit_double_buffering, NULL, NULL,
+                             RES_TYPE_BOOLEAN);
+  FRAME_DOUBLE_BUFFERED (f) = NILP (tem) || EQ (tem, Qunbound);
+  store_frame_param (f, Qinhibit_double_buffering,
+                     FRAME_DOUBLE_BUFFERED (f) ? Qnil : Qt);
+#endif
+
   parms = get_geometry_from_preferences (dpyinfo, parms);
   window_prompting = gui_figure_window_size (f, parms, false, true);
 
index b6e5a813a6ded21318ff15a90d421f4f84acc9e6..8d6c58290ccf3cf59fa60f27d73cd02ec7277fe7 100644 (file)
@@ -746,9 +746,11 @@ enum ns_return_frame_mode
   CGColorSpaceRef colorSpace;
   IOSurfaceRef currentSurface;
   CGContextRef context;
+  bool doubleBuffered;
 }
-- (id) initWithColorSpace: (CGColorSpaceRef)cs;
+- (id) initWithColorSpace: (CGColorSpaceRef)cs doubleBuffered: (bool)db;
 - (void) setColorSpace: (CGColorSpaceRef)cs;
+- (void) setDoubleBuffered: (bool)db;
 - (CGContextRef) getContext;
 @end
 #endif
@@ -996,6 +998,11 @@ struct ns_output
   /* Non-zero if we are doing an animation, e.g. toggling the tool bar.  */
   int in_animation;
 
+#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MIN_REQUIRED >= 101400
+  /* Is the frame double buffered?  */
+  bool double_buffered;
+#endif
+
 #ifdef NS_IMPL_GNUSTEP
   /* Zero if this is the first time a toolbar has been updated on this
      frame. */
@@ -1030,6 +1037,10 @@ struct x_output
 
 #define FRAME_FONT(f) ((f)->output_data.ns->font)
 
+#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MIN_REQUIRED >= 101400
+#define FRAME_DOUBLE_BUFFERED(f) ((f)->output_data.ns->double_buffered)
+#endif
+
 #ifdef __OBJC__
 #define XNS_SCROLL_BAR(vec) ((id) xmint_pointer (vec))
 #else
index 78089906752e0a0dd717f733abb677846fcfc512..28502ad1a2a29964c1c493aea82136e6eb6d876d 100644 (file)
@@ -2704,11 +2704,10 @@ ns_scroll_run (struct window *w, struct run *run)
   {
     NSRect srcRect = NSMakeRect (x, from_y, width, height);
     NSPoint dest = NSMakePoint (x, to_y);
-    NSRect destRect = NSMakeRect (x, from_y, width, height);
     EmacsView *view = FRAME_NS_VIEW (f);
 
     [view copyRect:srcRect to:dest];
-#ifdef NS_IMPL_COCOA
+#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED < 101400
     [view setNeedsDisplayInRect:destRect];
 #endif
   }
@@ -8607,7 +8606,8 @@ ns_in_echo_area (void)
 - (CALayer *)makeBackingLayer
 {
   EmacsLayer *l = [[EmacsLayer alloc]
-                    initWithColorSpace:[[[self window] colorSpace] CGColorSpace]];
+                    initWithColorSpace:[[[self window] colorSpace] CGColorSpace]
+                        doubleBuffered:FRAME_DOUBLE_BUFFERED (emacsframe)];
   [l setDelegate:(id)self];
   [l setContentsScale:[[self window] backingScaleFactor]];
 
@@ -8664,8 +8664,10 @@ ns_in_echo_area (void)
                                NSHeight (srcRect));
 
 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MIN_REQUIRED >= 101400
-  double scale = [[self window] backingScaleFactor];
   CGContextRef context = [(EmacsLayer *)[self layer] getContext];
+  CGContextFlush (context);
+
+  double scale = [[self window] backingScaleFactor];
   int bpp = CGBitmapContextGetBitsPerPixel (context) / 8;
   void *pixels = CGBitmapContextGetData (context);
   int rowSize = CGBitmapContextGetBytesPerRow (context);
@@ -10435,22 +10437,20 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
    cache.  If no free surfaces are found in the cache then a new one
    is created.  */
 
-#define CACHE_MAX_SIZE 2
-
 - (id) initWithColorSpace: (CGColorSpaceRef)cs
+           doubleBuffered: (bool)db
 {
-  NSTRACE ("[EmacsLayer initWithColorSpace:]");
+  NSTRACE ("[EmacsLayer initWithColorSpace:doubleBuffered:]");
 
   self = [super init];
   if (self)
     {
-      cache = [[NSMutableArray arrayWithCapacity:CACHE_MAX_SIZE] retain];
       [self setColorSpace:cs];
+      [self setDoubleBuffered:db];
+      cache = [[NSMutableArray arrayWithCapacity:(doubleBuffered ? 2 : 1)] retain];
     }
   else
-    {
-      return nil;
-    }
+    return nil;
 
   return self;
 }
@@ -10467,6 +10467,15 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
 }
 
 
+- (void) setDoubleBuffered: (bool)db
+{
+  if (doubleBuffered != db)
+    [self releaseSurfaces];
+
+  doubleBuffered = db;
+}
+
+
 - (void) dealloc
 {
   [self releaseSurfaces];
@@ -10538,7 +10547,7 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
             }
         }
 
-      if (!surface && [cache count] >= CACHE_MAX_SIZE)
+      if (!surface && [cache count] >= (doubleBuffered ? 2 : 1))
         {
           /* Just grab the first one off the cache.  This may result
              in tearing effects.  The alternative is to wait for one
@@ -10591,7 +10600,7 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
           return nil;
         }
 
-      CGContextTranslateCTM(context, 0, IOSurfaceGetHeight (currentSurface));
+      CGContextTranslateCTM(context, 0, IOSurfaceGetHeight (surface));
       CGContextScaleCTM(context, scale, -scale);
     }
 
@@ -10608,6 +10617,7 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
   if (!context)
     return;
 
+  CGContextFlush (context);
   CGContextRelease (context);
   context = NULL;
 
@@ -10621,26 +10631,18 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
 {
   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "[EmacsLayer display]");
 
-  if (context)
+  if (context && context != [[NSGraphicsContext currentContext] CGContext])
     {
       [self releaseContext];
 
-#if CACHE_MAX_SIZE == 1
-      /* This forces the layer to see the surface as updated.  */
+      /* This forces the layer to see the surface as updated even if
+         we replace it with itself.  */
       [self setContents:nil];
-#endif
-
       [self setContents:(id)currentSurface];
 
       /* Put currentSurface back on the end of the cache.  */
       [cache addObject:(id)currentSurface];
       currentSurface = NULL;
-
-      /* Schedule a run of getContext so that if Emacs is idle it will
-         perform the buffer copy, etc.  */
-      [self performSelectorOnMainThread:@selector (getContext)
-                             withObject:nil
-                          waitUntilDone:NO];
     }
 }