From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Alan Third Newsgroups: gmane.emacs.bugs Subject: bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS Date: Sun, 25 Jun 2023 13:46:03 +0100 Message-ID: References: <335C856F-41F7-48B8-AF42-B2406065C7A9@gmail.com> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="18181"; mail-complaints-to="usenet@ciao.gmane.io" Cc: Po Lu , Kai Ma , Eli Zaretskii , 63187@debbugs.gnu.org To: Aaron Jensen Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Sun Jun 25 14:47:32 2023 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 1qDP9P-0004Tv-Rx for geb-bug-gnu-emacs@m.gmane-mx.org; Sun, 25 Jun 2023 14:47:31 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1qDP90-0000rt-0g; Sun, 25 Jun 2023 08:47:06 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qDP8w-0000rO-JM for bug-gnu-emacs@gnu.org; Sun, 25 Jun 2023 08:47:04 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1qDP8v-0001FW-W7 for bug-gnu-emacs@gnu.org; Sun, 25 Jun 2023 08:47:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1qDP8v-0007Pq-S4 for bug-gnu-emacs@gnu.org; Sun, 25 Jun 2023 08:47:01 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Alan Third Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 25 Jun 2023 12:47:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 63187 X-GNU-PR-Package: emacs Original-Received: via spool by 63187-submit@debbugs.gnu.org id=B63187.168769717428423 (code B ref 63187); Sun, 25 Jun 2023 12:47:01 +0000 Original-Received: (at 63187) by debbugs.gnu.org; 25 Jun 2023 12:46:14 +0000 Original-Received: from localhost ([127.0.0.1]:42144 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1qDP8A-0007OL-5E for submit@debbugs.gnu.org; Sun, 25 Jun 2023 08:46:14 -0400 Original-Received: from dane.soverin.net ([185.233.34.24]:55595) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1qDP87-0007O6-1a for 63187@debbugs.gnu.org; Sun, 25 Jun 2023 08:46:13 -0400 Original-Received: from smtp.soverin.net (c04smtp-lb01.int.sover.in [10.10.4.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by dane.soverin.net (Postfix) with ESMTPS id 4QprLj3WbCzyRs; Sun, 25 Jun 2023 12:46:05 +0000 (UTC) Original-Received: from smtp.soverin.net (smtp.soverin.net [10.10.4.100]) by soverin.net (Postfix) with ESMTPSA id 4QprLh5W4fz9j; Sun, 25 Jun 2023 12:46:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=idiocy.org; s=soverin; t=1687697165; bh=7AFcUGOMLjqF7OnR6A8uo3pqmK1okb1Vz1EbjMIAZM0=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=dvSNxgOLzD5K7EztY4AXouj/RPgqTmT+PaGJ6mdTxt8/DIvVurfIULCfqZe+qGT0+ HIpSx8a58RNDD0xRk4aFzxSQSiopP4uzg1yBDBUQx63vBDyYMGYfD8XcGyGwIpzIlR ImrLBUmHUQEMRpH3hPvQA4qUKybYF38FqsKzNxqakpx/xJLcfRkN19fooeoQWEgk+T b40jvw46FUw21RKaQpcphBQXiqHrR+yzWd7rf1PeSGgFnYODAQA1RNDBMmZqaUiSho 09Via1lYIe2y9gaiIxV/w3aeoMWARYT4sknfOU150Pyu9LKWUAAgfRJfVoHLTcNztv Dn/WdEIwS5Iqg== Original-Received: from alan by faroe.holly.idiocy.org with local (Exim 4.95) (envelope-from ) id 1qDP7z-000YbY-Ha; Sun, 25 Jun 2023 13:46:03 +0100 X-Soverin-Authenticated: true Mail-Followup-To: Alan Third , Aaron Jensen , Kai Ma , 63187@debbugs.gnu.org, Eli Zaretskii , Po Lu Content-Disposition: inline In-Reply-To: X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list 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-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.bugs:264039 Archived-At: On Sat, Jun 24, 2023 at 05:43:04PM -0400, Aaron Jensen wrote: > On Sat, Jun 24, 2023 at 5:29 PM Alan Third wrote: > > My suspicion is that if we try to swap between the buffers too fast, > > something is going wrong between the process of flushing the drawing > > to the pixel buffer and copying the pixel buffer to the next one. > > Do we have any way to know when the flush is done? In other words, can > we only return the surface to the pool after that? Or is that already > done? No. Part of the reason I'm very unsure about this idea is that Apple are very clear that they don't think you should ever have to deal with this sort of thing. The provide functions that allow you to force the flush, but then they say you should never have to use it. How the macOS graphics system works is also pretty much undocumented, so it's hard to get to grips with whether anything *is* going wrong here. A lot of people do seem to have a deep understanding of it, but I don't have the first clue how you go about learning from first principles. > > So, we have two buffers, A and B. We draw to A, but before we're done > > the system calls display. We send off the incomplete buffer A to VRAM, > > and then take a copy of that incomplete buffer for B. At some point > > the system decides to flush the graphics context to the buffer, but > > it's flushing to A, and we've *already* copied A to B. > > Can we avoid sending incomplete buffers? What is "done"? I don't know > much about graphics programming but I imagine we don't want to send > incomplete buffers ever, we want to finish painting the whole buffer, > then send it. I think I'm also missing understanding on what it means > to flush the graphics context to the buffer. Is that the drawing that > we're doing (like rendering text/etc?) I feel like I may need a > whiteboard session or something to get my head around this so that I > can be of any assistance other than asking dumb questions :) When I say "done", I largely mean a call to ns_update_end. So most, but not all iiuc, Emacs drawing is done between a call to ns_update_begin and a call to ns_update_end. Apple recommend you leave the final display to screen to them. At some point, when the system decides it wants to update the screen, it checks if we've marked the view's needsDisplay variable to true, and if so, amongst a lot of other stuff, it calls our display function. Now, I think this, for the most part, only happens within the NS runloop, but it is possible to force it. I think Apple are right, though, and we don't want to force it unless we really need to. As for flushing the context, this is another thing Apple say we shouldn't touch, but they do give you the tools to force it. Imagine you want to draw some text, then a line, then a circle, or whatever. You'd think the system would draw them directly to the buffer as you call the functions, but apparently the system can queue them up and apply them in one go later on. I believe this should happen when we release the context, or in various other situations, so it's not something I really think is likely to be the cause, but it does sort-of match what we see happening. > > Who knows. Maybe all we need to do is make sure we don't try to draw > > to the screen while emacs is drawing to the buffer... Something like > > this: > > > > modified src/nsterm.m @@ -10622,7 +10622,7 @@ - (void) display > > { > > NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "[EmacsLayer display]"); > > > > - if (context) > > + if (context && context != [NSGraphicsContext currentContext]) > > { > > [self releaseContext]; > > > > > > ... > > > > Actually... > > > > That change should probably be made anyway. If the NS run loop kicks > > in between an ns_focus call and an ns_unfocus call, it could call > > display and our display function will happily destroy the existing > > context without creating a new one, so any *subsequent* drawing > > operations, up until ns_unfocus, will be lost. > > OK, I'm adding this to my current build. > > Is this in line with the type of issue I'm seeing where scrolling > works but the ghosting either replicates (or scrolls with it?) In > other words, what would you expect to see in this scenario? Would it > just stop painting entirely? It could be. The more I think about this change, the more I think it might be the solution. If you imagine we call ns_update_begin, which creates the context/buffer/whatever else we need, then somewhere in the midst of drawing display is called and the context is wiped out and the buffer is sent off to the screen. Until ns_update_end is called (or anything else that happens to call getContext, like copyRect) then nothing will be drawn to the buffer, even though Emacs reasonably expects it has. So yes, this might mean some parts of the screen aren't cleared, but it could also mean other drawing actions don't take place, like actually drawing text, or drawing underlines or whatever. HOWEVER, as I said above, copyRect calls getContext, so if we then try to scroll, it *will* draw to the buffer. CopyRect will *always* successfully draw to a buffer, even if some drawing actions will have failed already. All my change above does is make sure that the currently selected context (i.e. the one we're drawing to right this moment) isn't the same one we're trying to display. unlockFocus always clears the current context so if the current view is focused, the new check should catch it, and if it's not, say we're drawing to another frame or not drawing at all, then it should let it be displayed. The biggest risk is we start missing our chance to display the buffer to the screen, because it just skips sending the buffer. If you start seeing delays in the screen updating then we may have to consider forcing updates in ns_update_end or something. I hope this fixes it. It looks like a legitimate mistake in my logic whereas practically every other thing I can think of requires some weird behaviour in AppKit. Kai, it might be worth trying just that change above, while keeping the call to performSelectorInMainThread and see if it fixes anything for you. -- Alan Third