Simplify the EmacsLayer double buffering code (bug#63187)

This commit is contained in:
Alan Third 2023-07-23 12:00:30 +01:00
parent ca95e45f7e
commit fa24bbb631
3 changed files with 67 additions and 26 deletions

View file

@ -799,6 +799,26 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side.
}
}
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 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side.
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 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side.
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);

View 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

View file

@ -2704,11 +2704,10 @@ Hide the window (X11 semantics)
{
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 @@ - (instancetype)toggleToolbar: (id)sender
- (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 @@ - (void)copyRect:(NSRect)srcRect to:(NSPoint)dest
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 @@ @implementation EmacsLayer
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 @@ - (void) setColorSpace: (CGColorSpaceRef)cs
}
- (void) setDoubleBuffered: (bool)db
{
if (doubleBuffered != db)
[self releaseSurfaces];
doubleBuffered = db;
}
- (void) dealloc
{
[self releaseSurfaces];
@ -10538,7 +10547,7 @@ - (CGContextRef) getContext
}
}
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 @@ - (CGContextRef) getContext
return nil;
}
CGContextTranslateCTM(context, 0, IOSurfaceGetHeight (currentSurface));
CGContextTranslateCTM(context, 0, IOSurfaceGetHeight (surface));
CGContextScaleCTM(context, scale, -scale);
}
@ -10608,6 +10617,7 @@ - (void) releaseContext
if (!context)
return;
CGContextFlush (context);
CGContextRelease (context);
context = NULL;
@ -10621,26 +10631,18 @@ - (void) display
{
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];
}
}