From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.ciao.gmane.io!not-for-mail From: Alan Third Newsgroups: gmane.emacs.bugs Subject: bug#32932: 27.0.50; render bugs on macOS Mojave Date: Mon, 10 Feb 2020 21:33:31 +0000 Message-ID: <20200210213331.GA58269@breton.holly.idiocy.org> References: <20200203204408.GA59034@breton.holly.idiocy.org> <20200203213041.GC59034@breton.holly.idiocy.org> <20200207201802.GA7538@breton.holly.idiocy.org> <20200208141335.GA9391@breton.holly.idiocy.org> <20200210074404.GA44470@breton.holly.idiocy.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="1yeeQ81UyVL57Vl7" Content-Transfer-Encoding: 8bit Injection-Info: ciao.gmane.io; posting-host="ciao.gmane.io:159.69.161.202"; logging-data="14843"; mail-complaints-to="usenet@ciao.gmane.io" Cc: Mattias =?UTF-8?Q?Engdeg=C3=A5rd?= , Robert Pluim , 32932@debbugs.gnu.org, Daniel Pittman To: Aaron Jensen Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Mon Feb 10 22:34:20 2020 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1j1Gh9-0003iK-TR for geb-bug-gnu-emacs@m.gmane-mx.org; Mon, 10 Feb 2020 22:34:20 +0100 Original-Received: from localhost ([::1]:39916 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1j1Gh8-00038P-MV for geb-bug-gnu-emacs@m.gmane-mx.org; Mon, 10 Feb 2020 16:34:18 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:50592) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1j1Ggu-00036t-Uw for bug-gnu-emacs@gnu.org; Mon, 10 Feb 2020 16:34:06 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1j1Ggs-000327-Kr for bug-gnu-emacs@gnu.org; Mon, 10 Feb 2020 16:34:04 -0500 Original-Received: from debbugs.gnu.org ([209.51.188.43]:49654) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1j1Ggr-0002xi-Pg for bug-gnu-emacs@gnu.org; Mon, 10 Feb 2020 16:34:02 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1j1Ggr-0004lR-Ku for bug-gnu-emacs@gnu.org; Mon, 10 Feb 2020 16:34:01 -0500 X-Loop: help-debbugs@gnu.org Resent-From: Alan Third Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Mon, 10 Feb 2020 21:34:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 32932 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: fixed Original-Received: via spool by 32932-submit@debbugs.gnu.org id=B32932.158137042318288 (code B ref 32932); Mon, 10 Feb 2020 21:34:01 +0000 Original-Received: (at 32932) by debbugs.gnu.org; 10 Feb 2020 21:33:43 +0000 Original-Received: from localhost ([127.0.0.1]:55627 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1j1GgY-0004kr-Um for submit@debbugs.gnu.org; Mon, 10 Feb 2020 16:33:43 -0500 Original-Received: from mail-wm1-f50.google.com ([209.85.128.50]:32927) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1j1GgX-0004kb-Aq for 32932@debbugs.gnu.org; Mon, 10 Feb 2020 16:33:42 -0500 Original-Received: by mail-wm1-f50.google.com with SMTP id m10so793916wmc.0 for <32932@debbugs.gnu.org>; Mon, 10 Feb 2020 13:33:41 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20161025; h=sender:date:from:to:cc:subject:message-id:references:mime-version :content-disposition:content-transfer-encoding:in-reply-to; bh=ojjQ3qwdHZQ3Je60qjcSClZPrzy5CQ701d9GPeYJBbs=; b=qT5Oa1E92wYx/gnYAHO16mO8P/PSrGVUGVpn9bjmr1S/d+cSJ0WcNQDLNAsDvmiTeu gcU5RuQwUZzzSCDFDwuBCENAjLy1/MGSCeLAVL5G0bSudauCkglZ9f/Q8R9fNLtew0Ca z8/0eAGJuW4rUGYgEx3r/AxKNvPXsHRCUPz81nshSW1Ro38KxeD5gLwn7rruLwa2+7/G c1nWvH20vmm0xMJdVS2QwH8+UT2YyS/8aeCvXUXTQW3Z4k+AlVRTsimMejZwfJQ84lY0 5Ste6OK4hL73vfElrDkcYa6CX+rTTDILKWD/kG1IIqQz7KUnR5JxdOzjXaMckGMIgCAV IaUg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:from:to:cc:subject:message-id :references:mime-version:content-disposition :content-transfer-encoding:in-reply-to; bh=ojjQ3qwdHZQ3Je60qjcSClZPrzy5CQ701d9GPeYJBbs=; b=BspO5IZYrJJ6MO5WYtwtSbBDgUFlFdYIHbCw8jcJalL1Bq1Jx4VNv/BcTEijPDfL7y m5U/ASrC8ftfeEd8MjGcJrawMpBMrdMOn82l6YWK4vQGlHRiDqjAGlkczur4plCen2JY 34bOXc2qX7alR9+P58HIbHINbg2pnBQSxpkHyMGf/F+5iDHEIWXi/7zq6xntmTXYu7CM X0qDajm5mus3mZqBLUAOiX8sTuwFN5att2H5mSOCk5NYqTR9fuH5TQ1Lax3urFGU7m4k TXD595K4yuNUexEMStpccaJW0W1cLTHQdY5FOIV5ryyTukkMPZwa2U/+ZOgbmJYv0M82 5z8g== X-Gm-Message-State: APjAAAWfJYjTd83/MV5C8Jt7aoYwIfKGUOtBSKFO5l/v+215AW/qFYAK +VFKIyStqvB/jtiFWErbSKI= X-Google-Smtp-Source: APXvYqwdCAk65uiJOyPAqcxOpIR8wRNGFiSuhICler5PW8guZbUz4VXydk3MLaVv6qKDxrgm7UEVpw== X-Received: by 2002:a1c:e007:: with SMTP id x7mr958248wmg.3.1581370414979; Mon, 10 Feb 2020 13:33:34 -0800 (PST) Original-Received: from breton.holly.idiocy.org (ip6-2001-08b0-03f8-8129-d44f-5a06-b616-7005.holly.idiocy.org. [2001:8b0:3f8:8129:d44f:5a06:b616:7005]) by smtp.gmail.com with ESMTPSA id s1sm2227473wro.66.2020.02.10.13.33.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 10 Feb 2020 13:33:33 -0800 (PST) Content-Disposition: inline In-Reply-To: X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.51.188.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.io gmane.emacs.bugs:175911 Archived-At: --1yeeQ81UyVL57Vl7 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit On Mon, Feb 10, 2020 at 07:21:30AM -0800, Aaron Jensen wrote: > On Sun, Feb 9, 2020 at 11:44 PM Alan Third wrote: > > > > Anyway, one last thing to try. I was reading up on how MacVim handled > > this same issue, and while their drawing techniques are quite > > different, they did find performance problems with CGLayers so > > switched to using CGImages. I’ve given that a go and I don’t think > > this patch is quite as fast here as the CGLayer one, but it may be > > faster for you. > > 9.6s, which is around what 26 macport is, twice as slow as 27, but > about 1/4 the time it took with previous versions of 28. It also > doesn't seem to slow down too much (12.8) when I go full width. It's > still usable, for sure. > > No artifacts here as well, so I'd say this is a winner, at least for me. > > Thank you for figuring something out. I’m happy we’ve got to something usable at last! New patch attached, it’s basically the same as the last one but cleaned up and with a proper commit message. It’s not as fast as Emacs 26 and 27, but shouldn’t have any of the visual glitching we’ve seen in that codebase and is hopefully Fast Enough. I don’t think anyone’s likely to complain, but I’ll leave it a few days before I push to master. Thanks everyone for your help. -- Alan Third --1yeeQ81UyVL57Vl7 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v3-0001-Use-CGImage-instead-of-NSBitmapImageRep-bug-32932.patch" >From 97fe485718df20a58a4d48937f78614fc432ced1 Mon Sep 17 00:00:00 2001 From: Alan Third Date: Sat, 1 Feb 2020 21:17:29 +0000 Subject: [PATCH v3] Use CGImage instead of NSBitmapImageRep (bug#32932) * src/nsterm.m (ns_update_end): (ns_clear_frame): Remove forced draws. (ns_draw_fringe_bitmap): (ns_dumpglyphs_image): No longer need to invert images as the context is already flipped. ([EmacsView updateFrameSize:]): ([EmacsView initFrameFromEmacs:]): Use new function. ([EmacsView createDrawingBuffer]): Replaces createDrawingBufferWithRect:. ([EmacsView focusOnDrawingBuffer]): Set CGImage context. ([EmacsView windowDidChangeBackingProperties:]): Use new function. ([EmacsView copyRect:to:]): Copy using CGImages. ([EmacsView wantsUpdateLayer]): ([EmacsView updateLayer]): New Functions. ([EmacsView drawRect:]): We no longer do anything special here for Cocoa. ([EmacsView windowDidChangeBackingProperties:]): Fix indentation and add NSTRACE. --- src/nsterm.h | 4 +- src/nsterm.m | 152 +++++++++++++++++++++++++++++---------------------- 2 files changed, 90 insertions(+), 66 deletions(-) diff --git a/src/nsterm.h b/src/nsterm.h index 980ca534cf..7c6197f128 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -418,7 +418,7 @@ #define NSTRACE_UNSILENCE() NSWindow *nonfs_window; BOOL fs_is_native; #ifdef NS_IMPL_COCOA - NSBitmapImageRep *drawingBuffer; + CGContextRef drawingBuffer; #endif @public struct frame *emacsframe; @@ -464,7 +464,7 @@ #define NSTRACE_UNSILENCE() - (void)focusOnDrawingBuffer; #endif - (void)copyRect:(NSRect)srcRect to:(NSRect)dstRect; -- (void)createDrawingBufferWithRect:(NSRect)rect; +- (void)createDrawingBuffer; /* Non-notification versions of NSView methods. Used for direct calls. */ - (void)windowWillEnterFullScreen; diff --git a/src/nsterm.m b/src/nsterm.m index 9d427b9b38..567f3b3794 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -1141,7 +1141,6 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen) #ifdef NS_IMPL_COCOA [NSGraphicsContext setCurrentContext:nil]; - [view display]; #else block_input (); @@ -2853,7 +2852,9 @@ so some key presses (TAB) are swallowed by the system. */ ns_unfocus (f); /* as of 2006/11 or so this is now needed */ - ns_redraw_scroll_bars (f); + /* FIXME: I don't see any reason for this and removing it makes no + difference here. Do we need it for GNUstep? */ + //ns_redraw_scroll_bars (f); unblock_input (); } @@ -3169,18 +3170,6 @@ so some key presses (TAB) are swallowed by the system. */ NSTRACE_RECT ("fromRect", fromRect); - /* Because we're drawing into an offscreen buffer which isn't - flipped, the images come out upside down. To work around it - we need to do some fancy transforms. */ - { - NSAffineTransform *transform = [NSAffineTransform transform]; - [transform translateXBy:0 yBy:NSMaxY(imageRect)]; - [transform scaleXBy:1 yBy:-1]; - [transform concat]; - - imageRect.origin.y = 0; - } - [img drawInRect: imageRect fromRect: fromRect operation: NSCompositingOperationSourceOver @@ -3938,11 +3927,6 @@ Function modeled after x_draw_glyph_string_box (). NSAffineTransform *doTransform = [NSAffineTransform transform]; - /* We have to flip the image around the X axis as the offscreen - bitmap we're drawing to is flipped. */ - [doTransform scaleXBy:1 yBy:-1]; - [doTransform translateXBy:0 yBy:-[img size].height]; - /* ImageMagick images don't have transforms. */ if (img->transform) [doTransform appendTransform:img->transform]; @@ -7104,7 +7088,7 @@ - (void) updateFrameSize: (BOOL) delay from non-native fullscreen, in other circumstances it appears to be a noop. (bug#28872) */ wr = NSMakeRect (0, 0, neww, newh); - [self createDrawingBufferWithRect:wr]; + [self createDrawingBuffer]; [view setFrame: wr]; // To do: consider using [NSNotificationCenter postNotificationName:]. @@ -7444,7 +7428,7 @@ - (instancetype) initFrameFromEmacs: (struct frame *)f maximizing_resize = NO; #endif - [self createDrawingBufferWithRect:r]; + [self createDrawingBuffer]; win = [[EmacsWindow alloc] initWithContentRect: r @@ -8229,52 +8213,65 @@ - (instancetype)toggleToolbar: (id)sender } -- (void)createDrawingBufferWithRect:(NSRect)rect - /* Create and store a new NSBitmapImageRep for Emacs to draw - into. +#ifdef NS_IMPL_COCOA +- (void)createDrawingBuffer + /* Create and store a new CGGraphicsContext for Emacs to draw into. - Drawing to an offscreen bitmap doesn't work in GNUstep as there's - a bug in graphicsContextWithBitmapImageRep - (https://savannah.gnu.org/bugs/?38405). So under GNUstep we - retain the old method of drawing direct to the EmacsView. */ + We can't do this in GNUstep as there's no equivalent, so under + GNUstep we retain the old method of drawing direct to the + EmacsView. */ { -#ifdef NS_IMPL_COCOA + NSTRACE ("EmacsView createDrawingBuffer]"); + + NSGraphicsContext *screen; + CGColorSpaceRef colorSpace = [[[self window] colorSpace] CGColorSpace]; + CGFloat scale = [[self window] backingScaleFactor]; + NSRect frame = [self frame]; + if (drawingBuffer != nil) - [drawingBuffer release]; + CGContextRelease (drawingBuffer); - drawingBuffer = [[self bitmapImageRepForCachingDisplayInRect:rect] retain]; -#endif + drawingBuffer = CGBitmapContextCreate (nil, NSWidth (frame) * scale, NSHeight (frame) * scale, + 8, 0, colorSpace, + kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host); + + /* This fixes the scale to match the backing scale factor, and flips the image. */ + CGContextTranslateCTM(drawingBuffer, 0, NSHeight (frame) * scale); + CGContextScaleCTM(drawingBuffer, scale, -scale); } -#ifdef NS_IMPL_COCOA - (void)focusOnDrawingBuffer { - /* Creating the graphics context each time is very slow, but it - doesn't seem possible to cache and reuse it. */ - [NSGraphicsContext - setCurrentContext: - [NSGraphicsContext graphicsContextWithBitmapImageRep:drawingBuffer]]; + NSTRACE ("EmacsView focusOnDrawingBuffer]"); + + NSGraphicsContext *buf = + [NSGraphicsContext + graphicsContextWithCGContext:drawingBuffer flipped:YES]; + + [NSGraphicsContext setCurrentContext:buf]; } - (void)windowDidChangeBackingProperties:(NSNotification *)notification /* Update the drawing buffer when the backing scale factor changes. */ { - CGFloat old = [[[notification userInfo] + NSTRACE ("EmacsView windowDidChangeBackingProperties:]"); + + CGFloat old = [[[notification userInfo] objectForKey:@"NSBackingPropertyOldScaleFactorKey"] - doubleValue]; - CGFloat new = [[self window] backingScaleFactor]; + doubleValue]; + CGFloat new = [[self window] backingScaleFactor]; - if (old != new) - { - NSRect frame = [self frame]; - [self createDrawingBufferWithRect:frame]; - ns_clear_frame (emacsframe); - expose_frame (emacsframe, 0, 0, NSWidth (frame), NSHeight (frame)); - } + if (old != new) + { + NSRect frame = [self frame]; + [self createDrawingBuffer]; + ns_clear_frame (emacsframe); + expose_frame (emacsframe, 0, 0, NSWidth (frame), NSHeight (frame)); + } } -#endif +#endif /* NS_IMPL_COCOA */ - (void)copyRect:(NSRect)srcRect to:(NSRect)dstRect @@ -8284,13 +8281,31 @@ - (void)copyRect:(NSRect)srcRect to:(NSRect)dstRect NSTRACE_RECT ("Destination", dstRect); #ifdef NS_IMPL_COCOA - [drawingBuffer drawInRect:dstRect - fromRect:srcRect - operation:NSCompositingOperationCopy - fraction:1.0 - respectFlipped:NO - hints:nil]; + CGImageRef copy; + NSRect frame = [self frame]; + NSAffineTransform *setOrigin = [NSAffineTransform transform]; + + [[NSGraphicsContext currentContext] saveGraphicsState]; + + /* Set the clipping before messing with the buffer's + orientation. */ + NSRectClip (dstRect); + + /* Unflip the buffer as the copied image will be unflipped, and + offset the top left so when we draw back into the buffer the + correct part of the image is drawn. */ + CGContextScaleCTM(drawingBuffer, 1, -1); + CGContextTranslateCTM(drawingBuffer, 0, -NSHeight (frame) + - (NSMinY (dstRect) - NSMinY (srcRect))); + + /* Take a copy of the buffer and then draw it back to the buffer, + limited by the clipping rectangle. */ + copy = CGBitmapContextCreateImage (drawingBuffer); + CGContextDrawImage (drawingBuffer, frame, copy); + + CGImageRelease (copy); + [[NSGraphicsContext currentContext] restoreGraphicsState]; [self setNeedsDisplayInRect:dstRect]; #else hide_bell(); // Ensure the bell image isn't scrolled. @@ -8304,6 +8319,24 @@ - (void)copyRect:(NSRect)srcRect to:(NSRect)dstRect } +#ifdef NS_IMPL_COCOA +- (BOOL)wantsUpdateLayer +{ + return YES; +} + + +- (void)updateLayer +{ + NSTRACE ("EmacsView updateLayer]"); + + CGImageRef contentsImage = CGBitmapContextCreateImage(drawingBuffer); + self.layer.contents = (id)contentsImage; + CGImageRelease(contentsImage); +} +#endif + + - (void)drawRect: (NSRect)rect { NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]", @@ -8312,14 +8345,6 @@ - (void)drawRect: (NSRect)rect if (!emacsframe || !emacsframe->output_data.ns) return; -#ifdef NS_IMPL_COCOA - [drawingBuffer drawInRect:rect - fromRect:rect - operation:NSCompositingOperationSourceOver - fraction:1 - respectFlipped:NO - hints:nil]; -#else int x = NSMinX (rect), y = NSMinY (rect); int width = NSWidth (rect), height = NSHeight (rect); @@ -8327,7 +8352,6 @@ - (void)drawRect: (NSRect)rect block_input (); expose_frame (emacsframe, x, y, width, height); unblock_input (); -#endif } -- 2.24.0 --1yeeQ81UyVL57Vl7--