From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Aaron Jensen 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:07:19 -0400 Message-ID: References: <335C856F-41F7-48B8-AF42-B2406065C7A9@gmail.com> Mime-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="28588"; mail-complaints-to="usenet@ciao.gmane.io" To: Alan Third , Aaron Jensen , Kai Ma , 63187@debbugs.gnu.org, Eli Zaretskii , Po Lu Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Sun Jun 25 19:08:23 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 1qDTDq-0007DU-9s for geb-bug-gnu-emacs@m.gmane-mx.org; Sun, 25 Jun 2023 19:08:22 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1qDTDY-0007fA-7D; Sun, 25 Jun 2023 13:08:04 -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 1qDTDW-0007eY-Ph for bug-gnu-emacs@gnu.org; Sun, 25 Jun 2023 13:08:02 -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 1qDTDW-0003ym-H4 for bug-gnu-emacs@gnu.org; Sun, 25 Jun 2023 13:08:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1qDTDW-0006UC-CH for bug-gnu-emacs@gnu.org; Sun, 25 Jun 2023 13:08:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Aaron Jensen Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 25 Jun 2023 17:08:02 +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.168771286024902 (code B ref 63187); Sun, 25 Jun 2023 17:08:02 +0000 Original-Received: (at 63187) by debbugs.gnu.org; 25 Jun 2023 17:07:40 +0000 Original-Received: from localhost ([127.0.0.1]:43618 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1qDTD9-0006Ta-Oa for submit@debbugs.gnu.org; Sun, 25 Jun 2023 13:07:40 -0400 Original-Received: from mail-lf1-f46.google.com ([209.85.167.46]:45265) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1qDTD6-0006TK-VQ for 63187@debbugs.gnu.org; Sun, 25 Jun 2023 13:07:38 -0400 Original-Received: by mail-lf1-f46.google.com with SMTP id 2adb3069b0e04-4f4b2bc1565so3073364e87.2 for <63187@debbugs.gnu.org>; Sun, 25 Jun 2023 10:07:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20221208; t=1687712851; x=1690304851; h=content-transfer-encoding:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=udomo7V4Q23SYoyVqcOqgojrapKn8Ty8JdvG8WjEUjY=; b=SBBUeevJKo7WOZCacM9UPV83HUMOc4NQDs0sF6tIQ/7usJEJwcf26xpOrRmQxciram 3FDm8sbfXUGfcaLXvuqCZx+d9aVhpE9XMClrHdtiAlhyGyDrWv7eknL/kUOFtjWETaAr BwvfCUpiqWuj5xuDNUYTtc9fKNTwm9CgsjoCQIdB1XaoTMQoI0jGeh5OnxpTRckSMd6r oGAp5BKGBNbuR4Ne8K9ENe78ktwbJ460BlGj2odNFbKUWH0tED3l9M+Lx+zjVvG57Y/Y 8lca5mYdmcx3QUzU0dq1jAEoz9sQmuhfWbFEzderpTL3WAbULerAyHvHpceEXcHUniCY tUxQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1687712851; x=1690304851; h=content-transfer-encoding:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=udomo7V4Q23SYoyVqcOqgojrapKn8Ty8JdvG8WjEUjY=; b=jwcP3pI0YLatjjn3gTvz/hcEfVuEKPbd65Dg0sSyGyU17zzHMiZD69rySvoRCN9LEJ XCROeSCju9qqB2a+Ki/QS+op1A7ox/AjDkudMza2u/vIGIl0Wxdrq6yqX30lb/AmLO1z 0jaYhTK5PXxmThi8NfTnoOKGXtbOjQMvXz8/GhfuuaRd6I07/UfgWX5J3MIHk5o2Qyun tjsRsoaZHQ5aiEyo9xaj5XPDLJyOciv6DFNg6bj/waeaLnIXD21pBkKmuqqc5eKhUlx4 ew4uFXVLKNN72Bvw0d8B+L0U/cNXGzXwN+FOnw1C1wbqNCKZXIqer9tMUBbtatbwvgWk W4Ng== X-Gm-Message-State: AC+VfDyWCRaqTL3uZLBWCVYDwJSnIHBnCs1wZ2YOH99djFJgtpGmDAK7 e6z65BXV1rMimySRQrdJSmMZCUGzUR5/6JJZtRw= X-Google-Smtp-Source: ACHHUZ66frLk48Dm5I1fyJIyBGaBFNB3UYJcG6TMV/7NTxIbxAW4Slf7OcSzjVT/gu+Zi+VemeSeoitY3HkljZHAX70= X-Received: by 2002:a05:6512:340f:b0:4f5:1418:e230 with SMTP id i15-20020a056512340f00b004f51418e230mr16919923lfr.52.1687712850552; Sun, 25 Jun 2023 10:07:30 -0700 (PDT) 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:264058 Archived-At: On Sun, Jun 25, 2023 at 8:46=E2=80=AFAM Alan Third wrote: > > On Sat, Jun 24, 2023 at 05:43:04PM -0400, Aaron Jensen wrote: > > On Sat, Jun 24, 2023 at 5:29=E2=80=AFPM Alan Third wr= ote: > > > 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 !=3D [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. Thank you for the continued explanation. I'm doing some additional digging and it's making me wonder if what we are doing is even possible reliably with Cocoa drawing and without any synchronization primitives like MTLCommandBuffer's waitUntilCompleted. If I understand correctly, we do something like this: 1. Draw to Surface 1 (buffer commands) 2. Assign Surface 1 to the view as its layer 3. Copy from Surface 1 to Surface 2 4. Copy rects on Surface 2 to other parts of Surface 2 As I understand, there's no way to ensure that all commands have been flushed all the way to the point that we know that Surface 1 is actually representative of the commands we have sent it. It seems like macOS will ensure that it all eventually gets drawn to the screen, but if we attempt to read from the surface, we don't know if all the drawing is complete. This is in contrast to Metal, where we could waitUntilCompleted before copying Surface 1 to Surface 2. Am I missing something in this or is it just not possible to truly synchronize? I came across some notes from the Chromium team: https://www.chromium.org/developers/design-documents/iosurface-meeting-note= s/ They (as of the notes) decided not to double buffer and just write directly to the one surface. I don't know if that's reasonable/viable for Emacs or not. Lastly, as an aside, if we *could* synchronize, would it be more efficient to not copy the entire surface just to then copy rects again to handle scrolling? I can imagine this would add more complexity than is worth it, I'm mainly asking for my own edification. Thanks, Aaron