all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
       [not found] <m2fs8histt.fsf@gmail.com>
@ 2023-04-30 10:33 ` Eli Zaretskii
  2023-04-30 10:46   ` Aaron Jensen
  2023-04-30 13:25 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 1 reply; 71+ messages in thread
From: Eli Zaretskii @ 2023-04-30 10:33 UTC (permalink / raw)
  To: Aaron Jensen; +Cc: 63187

> From: Aaron Jensen <aaronjensen@gmail.com>
> Date: Sun, 30 Apr 2023 06:10:22 -0400
> 
> I don't have a good recipe for this. It has been happening occasionally
> for quite some time (the attached screenshots are from 2021, but the
> same thing is still occurring). Every once in a while, a part of the
> Emacs frame gets into a state where glyphs from nearby lines can be
> painted after the tail end of other lines. This seems to be related to
> scrolling (that is, while scrolling, the glyphs replicate onto nearby
> lines, but when scrolling back they stay. I usually have to force a full
> repaint to get the glyphs to disappear.

Thanks, but this is impossible to handle without some kind of recipe,
even if it only reproduces sometimes.

FWIW, it never happens for me, so maybe it's macOS-specific.





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-04-30 10:33 ` bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS Eli Zaretskii
@ 2023-04-30 10:46   ` Aaron Jensen
  0 siblings, 0 replies; 71+ messages in thread
From: Aaron Jensen @ 2023-04-30 10:46 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 63187

On Sun, Apr 30, 2023 at 6:32 AM Eli Zaretskii <eliz@gnu.org> wrote:
>
> > From: Aaron Jensen <aaronjensen@gmail.com>
> > Date: Sun, 30 Apr 2023 06:10:22 -0400
> >
> > I don't have a good recipe for this. It has been happening occasionally
> > for quite some time (the attached screenshots are from 2021, but the
> > same thing is still occurring). Every once in a while, a part of the
> > Emacs frame gets into a state where glyphs from nearby lines can be
> > painted after the tail end of other lines. This seems to be related to
> > scrolling (that is, while scrolling, the glyphs replicate onto nearby
> > lines, but when scrolling back they stay. I usually have to force a full
> > repaint to get the glyphs to disappear.
>
> Thanks, but this is impossible to handle without some kind of recipe,
> even if it only reproduces sometimes.
>
> FWIW, it never happens for me, so maybe it's macOS-specific.

I'm guessing it is macOS specific. I'm not familiar enough w/ how
rendering works to even start to look at this. I do understand that
it's impossible/difficult to handle without a recipe. The only hope at
the moment is that someone is familiar enough w/ the macOS rendering
that they could spot a potential for something like this to happen.
I'll keep seeing if I can figure out what causes it.

Thanks,

Aaron





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
       [not found] <m2fs8histt.fsf@gmail.com>
  2023-04-30 10:33 ` bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS Eli Zaretskii
@ 2023-04-30 13:25 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-04-30 14:25   ` Aaron Jensen
  1 sibling, 1 reply; 71+ messages in thread
From: Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-04-30 13:25 UTC (permalink / raw)
  To: Aaron Jensen; +Cc: 63187

Aaron Jensen <aaronjensen@gmail.com> writes:

> I don't have a good recipe for this. It has been happening occasionally
> for quite some time (the attached screenshots are from 2021, but the
> same thing is still occurring). Every once in a while, a part of the
> Emacs frame gets into a state where glyphs from nearby lines can be
> painted after the tail end of other lines. This seems to be related to
> scrolling (that is, while scrolling, the glyphs replicate onto nearby
> lines, but when scrolling back they stay. I usually have to force a full
> repaint to get the glyphs to disappear.
>
>
>
>
>
>
> In GNU Emacs 30.0.50 (build 1, aarch64-apple-darwin22.4.0, NS
>  appkit-2299.50 Version 13.3.1 (Build 22E261)) of 2023-04-09 built on
>  Aarons-Laptop.local
> Windowing system distributor 'Apple', version 10.3.2299
> System Description:  macOS 13.3.1
>
> Configured using:
>  'configure --disable-dependency-tracking --disable-silent-rules
>  --enable-locallisppath=/opt/homebrew/share/emacs/site-lisp
>  --infodir=/opt/homebrew/Cellar/emacs-plus@30/30.0.50/share/info/emacs
>  --prefix=/opt/homebrew/Cellar/emacs-plus@30/30.0.50 --with-xml2
>  --with-gnutls --with-native-compilation --without-compress-install
>  --without-dbus --without-imagemagick --with-modules --with-rsvg
>  --with-ns --disable-ns-self-contained 'CFLAGS=-Os -w -pipe
>  -mmacosx-version-min=13
>  -isysroot/Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk
>  -DFD_SETSIZE=10000 -DDARWIN_UNLIMITED_SELECT'
>  'CPPFLAGS=-I/opt/homebrew/opt/zlib/include
>  -I/opt/homebrew/opt/jpeg/include -I/opt/homebrew/opt/icu4c/include
>  -I/opt/homebrew/opt/openssl@1.1/include -isystem/opt/homebrew/include
>  -F/opt/homebrew/Frameworks
>  -isysroot/Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk'
>  'LDFLAGS=-L/opt/homebrew/opt/zlib/lib -L/opt/homebrew/opt/jpeg/lib
>  -L/opt/homebrew/opt/icu4c/lib -L/opt/homebrew/opt/openssl@1.1/lib
>  -L/opt/homebrew/lib -F/opt/homebrew/Frameworks
>  -Wl,-headerpad_max_install_names
>  -isysroot/Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk''
>
> Configured features:
> ACL GIF GLIB GMP GNUTLS JPEG JSON LCMS2 LIBXML2 MODULES NATIVE_COMP
> NOTIFY KQUEUE NS PDUMPER PNG RSVG SQLITE3 THREADS TIFF
> TOOLKIT_SCROLL_BARS TREE_SITTER WEBP XIM ZLIB
>
> Important settings:
>   value of $LANG: en_US.UTF-8
>   locale-coding-system: utf-8-unix
>
> Major mode: ELisp/d
>
> Minor modes in effect:
>   global-evil-mc-mode: t
>   evil-mc-mode: t
>   treemacs-filewatch-mode: t
>   treemacs-follow-mode: t
>   treemacs-git-mode: t
>   treemacs-fringe-indicator-mode: t
>   global-git-commit-mode: t
>   transient-posframe-mode: t
>   windmove-mode: t
>   global-flycheck-mode: t
>   flycheck-mode: t
>   gcmh-mode: t
>   undo-fu-session-global-mode: t
>   undo-fu-session-mode: t
>   ws-butler-global-mode: t
>   ws-butler-mode: t
>   ns-auto-titlebar-mode: t
>   global-anzu-mode: t
>   anzu-mode: t
>   corfu-prescient-mode: t
>   corfu-history-mode: t
>   corfu-mode: t
>   form-feed-mode: t
>   eval-sexp-fu-flash-mode: t
>   eros-mode: t
>   lispyville-mode: t
>   lispy-mode: t
>   elisp-def-mode: t
>   sotlisp-mode: t
>   speed-of-thought-mode: t
>   electric-pair-mode: t
>   envrc-mode: t
>   global-evil-surround-mode: t
>   evil-surround-mode: t
>   evil-matchit-mode: t
>   evil-vimish-fold-mode: t
>   vimish-fold-mode: t
>   dtrt-indent-mode: t
>   tabspaces-mode: t
>   save-place-mode: t
>   winner-mode: t
>   savehist-mode: t
>   delete-selection-mode: t
>   yas-global-mode: t
>   yas-minor-mode: t
>   vertico-prescient-mode: t
>   prescient-persist-mode: t
>   vertico-mouse-mode: t
>   vertico-mode: t
>   mini-frame-mode: t
>   better-jumper-mode: t
>   better-jumper-local-mode: t
>   xterm-mouse-mode: t
>   pixel-scroll-precision-mode: t
>   global-auto-revert-mode: t
>   which-key-posframe-mode: t
>   which-key-mode: t
>   org-roam-db-autosync-mode: t
>   shell-dirtrack-mode: t
>   recentf-mode: t
>   repeat-mode: t
>   +popup-mode: t
>   evil-mode: t
>   evil-local-mode: t
>   nano-modeline-mode: t
>   server-mode: t
>   leader-key-leader-override-mode: t
>   global-leader-key-leader-override-mode: t
>   elpaca-use-package-mode: t
>   override-global-mode: t
>   global-display-line-numbers-mode: t
>   display-line-numbers-mode: t
>   global-eldoc-mode: t
>   eldoc-mode: t
>   show-paren-mode: t
>   electric-indent-mode: t
>   mouse-wheel-mode: t
>   tab-bar-mode: t
>   file-name-shadow-mode: t
>   global-font-lock-mode: t
>   font-lock-mode: t
>   window-divider-mode: t
>   line-number-mode: t
>   auto-fill-function: yas--auto-fill
>   transient-mark-mode: t
>   auto-composition-mode: t
>   auto-encryption-mode: t
>   auto-compression-mode: t
>   abbrev-mode: t

Hmmm, this looks like a scrolling optimization bug.
I can't build the NS port right now, but if you insert:

  return false;

right after

  /* Can't scroll the display of w32 GUI frames when position of point
     is indicated by the system caret, because scrolling the display
     will then "copy" the pixels used by the caret.  */
#ifdef HAVE_NTGUI
  if (w32_use_visible_system_caret)
    return 0;
#endif

in `scrolling_window', in dispnew.c, does the problem go away?





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-04-30 13:25 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-04-30 14:25   ` Aaron Jensen
  2023-04-30 14:42     ` Eli Zaretskii
  2023-04-30 23:58     ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 2 replies; 71+ messages in thread
From: Aaron Jensen @ 2023-04-30 14:25 UTC (permalink / raw)
  To: Po Lu; +Cc: 63187

On Sun, Apr 30, 2023 at 9:25 AM Po Lu <luangruo@yahoo.com> wrote:
>
> Hmmm, this looks like a scrolling optimization bug.
> I can't build the NS port right now, but if you insert:
>
>   return false;
>
> right after
>
>   /* Can't scroll the display of w32 GUI frames when position of point
>      is indicated by the system caret, because scrolling the display
>      will then "copy" the pixels used by the caret.  */
> #ifdef HAVE_NTGUI
>   if (w32_use_visible_system_caret)
>     return 0;
> #endif
>
> in `scrolling_window', in dispnew.c, does the problem go away?

Thanks, I will try this out. Is there any chance that it is related to
the other bug I just reported, bug#63186? I see that Eli's fix
affected the display matrix. It seems unlikely given the fact that
that bug was a regression.

Is there anything specific to macOS that is involved in scrolling optimization?

Thanks,

Aaron





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-04-30 14:25   ` Aaron Jensen
@ 2023-04-30 14:42     ` Eli Zaretskii
  2023-04-30 14:57       ` Aaron Jensen
  2023-04-30 23:58     ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 1 reply; 71+ messages in thread
From: Eli Zaretskii @ 2023-04-30 14:42 UTC (permalink / raw)
  To: Aaron Jensen; +Cc: luangruo, 63187

> Cc: 63187@debbugs.gnu.org
> From: Aaron Jensen <aaronjensen@gmail.com>
> Date: Sun, 30 Apr 2023 10:25:59 -0400
> 
> On Sun, Apr 30, 2023 at 9:25 AM Po Lu <luangruo@yahoo.com> wrote:
> >
> > Hmmm, this looks like a scrolling optimization bug.
> > I can't build the NS port right now, but if you insert:
> >
> >   return false;
> >
> > right after
> >
> >   /* Can't scroll the display of w32 GUI frames when position of point
> >      is indicated by the system caret, because scrolling the display
> >      will then "copy" the pixels used by the caret.  */
> > #ifdef HAVE_NTGUI
> >   if (w32_use_visible_system_caret)
> >     return 0;
> > #endif
> >
> > in `scrolling_window', in dispnew.c, does the problem go away?
> 
> Thanks, I will try this out. Is there any chance that it is related to
> the other bug I just reported, bug#63186?

No, no chance.  That bug was system-independent, while this one is
specific to macOS.  Also, while investigating bug#63186, I've
established that disabling scrolling_window optimization doesn't fix
the problem with redisplaying the mode line after mode-line-format was
nil.

> Is there anything specific to macOS that is involved in scrolling optimization?

Not that I know of, and so if Po Lu's suggestion fixes the problem,
we'd need to understand how come scrolling_window fails on macOS.





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-04-30 14:42     ` Eli Zaretskii
@ 2023-04-30 14:57       ` Aaron Jensen
  2023-04-30 15:26         ` Eli Zaretskii
  0 siblings, 1 reply; 71+ messages in thread
From: Aaron Jensen @ 2023-04-30 14:57 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: luangruo, 63187

On Sun, Apr 30, 2023 at 10:42 AM Eli Zaretskii <eliz@gnu.org> wrote:
>
> > Cc: 63187@debbugs.gnu.org
> > From: Aaron Jensen <aaronjensen@gmail.com>
> > Date: Sun, 30 Apr 2023 10:25:59 -0400
> >
> > On Sun, Apr 30, 2023 at 9:25 AM Po Lu <luangruo@yahoo.com> wrote:
> > >
> > > Hmmm, this looks like a scrolling optimization bug.
> > > I can't build the NS port right now, but if you insert:
> > >
> > >   return false;
> > >
> > > right after
> > >
> > >   /* Can't scroll the display of w32 GUI frames when position of point
> > >      is indicated by the system caret, because scrolling the display
> > >      will then "copy" the pixels used by the caret.  */
> > > #ifdef HAVE_NTGUI
> > >   if (w32_use_visible_system_caret)
> > >     return 0;
> > > #endif
> > >
> > > in `scrolling_window', in dispnew.c, does the problem go away?
> >
> > Thanks, I will try this out. Is there any chance that it is related to
> > the other bug I just reported, bug#63186?
>
> No, no chance.  That bug was system-independent, while this one is
> specific to macOS.  Also, while investigating bug#63186, I've
> established that disabling scrolling_window optimization doesn't fix
> the problem with redisplaying the mode line after mode-line-format was
> nil.

Copy that.

> > Is there anything specific to macOS that is involved in scrolling optimization?
>
> Not that I know of, and so if Po Lu's suggestion fixes the problem,
> we'd need to understand how come scrolling_window fails on macOS.

Ok, it may take me a few days to be sure. It happens intermittently,
though lately it has been at least once in most work days.

For what it's worth, disabling it has had no discernible impact on
scroll performance on my machine (which is an M1)

Aaron





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-04-30 14:57       ` Aaron Jensen
@ 2023-04-30 15:26         ` Eli Zaretskii
  2023-04-30 16:48           ` Aaron Jensen
  0 siblings, 1 reply; 71+ messages in thread
From: Eli Zaretskii @ 2023-04-30 15:26 UTC (permalink / raw)
  To: Aaron Jensen; +Cc: luangruo, 63187

> From: Aaron Jensen <aaronjensen@gmail.com>
> Date: Sun, 30 Apr 2023 10:57:35 -0400
> Cc: luangruo@yahoo.com, 63187@debbugs.gnu.org
> 
> For what it's worth, disabling it has had no discernible impact on
> scroll performance on my machine (which is an M1)

scrolling_window is not about scrolling.  It's a redisplay
optimization that attempts to speed up redrawing a window by scrolling
on display the stuff already shown, when that is deemed less costly
than redrawing every screen line that has changed.





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-04-30 15:26         ` Eli Zaretskii
@ 2023-04-30 16:48           ` Aaron Jensen
  2023-04-30 19:04             ` Eli Zaretskii
  0 siblings, 1 reply; 71+ messages in thread
From: Aaron Jensen @ 2023-04-30 16:48 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: luangruo, 63187

On Sun, Apr 30, 2023 at 11:26 AM Eli Zaretskii <eliz@gnu.org> wrote:
>
> > From: Aaron Jensen <aaronjensen@gmail.com>
> > Date: Sun, 30 Apr 2023 10:57:35 -0400
> > Cc: luangruo@yahoo.com, 63187@debbugs.gnu.org
> >
> > For what it's worth, disabling it has had no discernible impact on
> > scroll performance on my machine (which is an M1)
>
> scrolling_window is not about scrolling.  It's a redisplay
> optimization that attempts to speed up redrawing a window by scrolling
> on display the stuff already shown, when that is deemed less costly
> than redrawing every screen line that has changed.

Ah, so is it used (for example) when you insert a newline in part of a
buffer? How might I reproduce a usage of it both so I can benchmark
and play around with it when it is enabled to see if I can trigger the
bug I'm seeing?





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-04-30 16:48           ` Aaron Jensen
@ 2023-04-30 19:04             ` Eli Zaretskii
  0 siblings, 0 replies; 71+ messages in thread
From: Eli Zaretskii @ 2023-04-30 19:04 UTC (permalink / raw)
  To: Aaron Jensen; +Cc: luangruo, 63187

> From: Aaron Jensen <aaronjensen@gmail.com>
> Date: Sun, 30 Apr 2023 12:48:05 -0400
> Cc: luangruo@yahoo.com, 63187@debbugs.gnu.org
> 
> On Sun, Apr 30, 2023 at 11:26 AM Eli Zaretskii <eliz@gnu.org> wrote:
> >
> > scrolling_window is not about scrolling.  It's a redisplay
> > optimization that attempts to speed up redrawing a window by scrolling
> > on display the stuff already shown, when that is deemed less costly
> > than redrawing every screen line that has changed.
> 
> Ah, so is it used (for example) when you insert a newline in part of a
> buffer?

Could be, yes.  But one can never be sure, because the display engine
has many different optimizations, so it could be that this particular
case is handled elsewhere, for example in try_window_id, which also
handles cases like this one.

> How might I reproduce a usage of it both so I can benchmark and play
> around with it when it is enabled to see if I can trigger the bug
> I'm seeing?

The best idea I have is to add a printf right before the mainline of
its algorithm, after this comment:

  /* Reallocate vectors, tables etc. if necessary.  */

and pay attention which edits cause that printf.





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-04-30 14:25   ` Aaron Jensen
  2023-04-30 14:42     ` Eli Zaretskii
@ 2023-04-30 23:58     ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-05-01 12:40       ` Eli Zaretskii
  1 sibling, 1 reply; 71+ messages in thread
From: Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-04-30 23:58 UTC (permalink / raw)
  To: Aaron Jensen; +Cc: 63187

Aaron Jensen <aaronjensen@gmail.com> writes:

> Is there anything specific to macOS that is involved in scrolling optimization?

Yes, Apple deleted the API used to perform bit blits, so Emacs uses a
workaround that I don't really understand, and seems unreliable.





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-04-30 23:58     ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-05-01 12:40       ` Eli Zaretskii
  2023-05-01 13:18         ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 71+ messages in thread
From: Eli Zaretskii @ 2023-05-01 12:40 UTC (permalink / raw)
  To: Po Lu; +Cc: 63187, aaronjensen

> Cc: 63187@debbugs.gnu.org
> Date: Mon, 01 May 2023 07:58:26 +0800
> From:  Po Lu via "Bug reports for GNU Emacs,
>  the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
> 
> Aaron Jensen <aaronjensen@gmail.com> writes:
> 
> > Is there anything specific to macOS that is involved in scrolling optimization?
> 
> Yes, Apple deleted the API used to perform bit blits, so Emacs uses a
> workaround that I don't really understand, and seems unreliable.

You mean, ns_scroll_run in nsterm.m?  Which parts of it do you not
understand?





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-05-01 12:40       ` Eli Zaretskii
@ 2023-05-01 13:18         ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-05-01 13:25           ` Eli Zaretskii
  0 siblings, 1 reply; 71+ messages in thread
From: Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-01 13:18 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 63187, aaronjensen

Eli Zaretskii <eliz@gnu.org> writes:

>> Cc: 63187@debbugs.gnu.org
>> Date: Mon, 01 May 2023 07:58:26 +0800
>> From:  Po Lu via "Bug reports for GNU Emacs,
>>  the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
>> 
>> Aaron Jensen <aaronjensen@gmail.com> writes:
>> 
>> > Is there anything specific to macOS that is involved in scrolling optimization?
>> 
>> Yes, Apple deleted the API used to perform bit blits, so Emacs uses a
>> workaround that I don't really understand, and seems unreliable.
>
> You mean, ns_scroll_run in nsterm.m?  Which parts of it do you not
> understand?

No, I meant the implementation of [EmacsView copyRect:] enabled under
Mac OS; see line 8655 of nsterm.m.  I don't understand how the system
synchronizes its access to the window's backing store with Emacs's.





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-05-01 13:18         ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-05-01 13:25           ` Eli Zaretskii
  2023-05-01 13:47             ` Aaron Jensen
  2023-05-01 17:26             ` Alan Third
  0 siblings, 2 replies; 71+ messages in thread
From: Eli Zaretskii @ 2023-05-01 13:25 UTC (permalink / raw)
  To: Po Lu, Alan Third; +Cc: 63187, aaronjensen

> From: Po Lu <luangruo@yahoo.com>
> Cc: aaronjensen@gmail.com,  63187@debbugs.gnu.org
> Date: Mon, 01 May 2023 21:18:31 +0800
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> >> Cc: 63187@debbugs.gnu.org
> >> Date: Mon, 01 May 2023 07:58:26 +0800
> >> From:  Po Lu via "Bug reports for GNU Emacs,
> >>  the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
> >> 
> >> Aaron Jensen <aaronjensen@gmail.com> writes:
> >> 
> >> > Is there anything specific to macOS that is involved in scrolling optimization?
> >> 
> >> Yes, Apple deleted the API used to perform bit blits, so Emacs uses a
> >> workaround that I don't really understand, and seems unreliable.
> >
> > You mean, ns_scroll_run in nsterm.m?  Which parts of it do you not
> > understand?
> 
> No, I meant the implementation of [EmacsView copyRect:] enabled under
> Mac OS; see line 8655 of nsterm.m.  I don't understand how the system
> synchronizes its access to the window's backing store with Emacs's.

Alan, can you help?

If this is unworkable on macOS, we could simply disable this
optimization there.  But note that scroll_run_hook is also called from
xdisp.c, in several places, so we may need to disable it there as
well.





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-05-01 13:25           ` Eli Zaretskii
@ 2023-05-01 13:47             ` Aaron Jensen
  2023-05-01 13:52               ` Eli Zaretskii
  2023-05-09  3:07               ` Aaron Jensen
  2023-05-01 17:26             ` Alan Third
  1 sibling, 2 replies; 71+ messages in thread
From: Aaron Jensen @ 2023-05-01 13:47 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Po Lu, Alan Third, 63187

On Mon, May 1, 2023 at 9:24 AM Eli Zaretskii <eliz@gnu.org> wrote:
>
> > From: Po Lu <luangruo@yahoo.com>
> > Cc: aaronjensen@gmail.com,  63187@debbugs.gnu.org
> > Date: Mon, 01 May 2023 21:18:31 +0800
> >
> > Eli Zaretskii <eliz@gnu.org> writes:
> >
> > >> Cc: 63187@debbugs.gnu.org
> > >> Date: Mon, 01 May 2023 07:58:26 +0800
> > >> From:  Po Lu via "Bug reports for GNU Emacs,
> > >>  the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
> > >>
> > >> Aaron Jensen <aaronjensen@gmail.com> writes:
> > >>
> > >> > Is there anything specific to macOS that is involved in scrolling optimization?
> > >>
> > >> Yes, Apple deleted the API used to perform bit blits, so Emacs uses a
> > >> workaround that I don't really understand, and seems unreliable.
> > >
> > > You mean, ns_scroll_run in nsterm.m?  Which parts of it do you not
> > > understand?
> >
> > No, I meant the implementation of [EmacsView copyRect:] enabled under
> > Mac OS; see line 8655 of nsterm.m.  I don't understand how the system
> > synchronizes its access to the window's backing store with Emacs's.
>
> Alan, can you help?
>
> If this is unworkable on macOS, we could simply disable this
> optimization there.  But note that scroll_run_hook is also called from
> xdisp.c, in several places, so we may need to disable it there as
> well.

Is this suspect?

  {
    NSRect srcRect = NSMakeRect (x, from_y, width, height);
    NSPoint dest = NSMakePoint (x, to_y);
    EmacsView *view = FRAME_NS_VIEW (f);

    [view copyRect:srcRect to:dest];
#ifdef NS_IMPL_COCOA
    [view setNeedsDisplayInRect:srcRect];
#endif
  }

Why is the source being marked for redisplay? I would expect the
destination to be marked as such, or am I missing something?





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-05-01 13:47             ` Aaron Jensen
@ 2023-05-01 13:52               ` Eli Zaretskii
  2023-05-01 13:55                 ` Aaron Jensen
  2023-05-09  3:07               ` Aaron Jensen
  1 sibling, 1 reply; 71+ messages in thread
From: Eli Zaretskii @ 2023-05-01 13:52 UTC (permalink / raw)
  To: Aaron Jensen; +Cc: luangruo, alan, 63187

> From: Aaron Jensen <aaronjensen@gmail.com>
> Date: Mon, 1 May 2023 09:47:50 -0400
> Cc: Po Lu <luangruo@yahoo.com>, Alan Third <alan@idiocy.org>, 63187@debbugs.gnu.org
> 
>   {
>     NSRect srcRect = NSMakeRect (x, from_y, width, height);
>     NSPoint dest = NSMakePoint (x, to_y);
>     EmacsView *view = FRAME_NS_VIEW (f);
> 
>     [view copyRect:srcRect to:dest];
> #ifdef NS_IMPL_COCOA
>     [view setNeedsDisplayInRect:srcRect];
> #endif
>   }
> 
> Why is the source being marked for redisplay? I would expect the
> destination to be marked as such, or am I missing something?

IMO, both should be marked for redisplay.  Or maybe I don't understand
the significance of marking a rectangle for redisplay.





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-05-01 13:52               ` Eli Zaretskii
@ 2023-05-01 13:55                 ` Aaron Jensen
  2023-05-01 14:06                   ` Aaron Jensen
  0 siblings, 1 reply; 71+ messages in thread
From: Aaron Jensen @ 2023-05-01 13:55 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: luangruo, alan, 63187

On Mon, May 1, 2023 at 9:51 AM Eli Zaretskii <eliz@gnu.org> wrote:
>
> > From: Aaron Jensen <aaronjensen@gmail.com>
> > Date: Mon, 1 May 2023 09:47:50 -0400
> > Cc: Po Lu <luangruo@yahoo.com>, Alan Third <alan@idiocy.org>, 63187@debbugs.gnu.org
> >
> >   {
> >     NSRect srcRect = NSMakeRect (x, from_y, width, height);
> >     NSPoint dest = NSMakePoint (x, to_y);
> >     EmacsView *view = FRAME_NS_VIEW (f);
> >
> >     [view copyRect:srcRect to:dest];
> > #ifdef NS_IMPL_COCOA
> >     [view setNeedsDisplayInRect:srcRect];
> > #endif
> >   }
> >
> > Why is the source being marked for redisplay? I would expect the
> > destination to be marked as such, or am I missing something?
>
> IMO, both should be marked for redisplay.  Or maybe I don't understand
> the significance of marking a rectangle for redisplay.

For reference, this is in `ns_scroll_run'. Only the destination is
changed, right? I imagine the source would be effectively marked when
it's copied into, so marking the source in this code would be
redundant, unless I'm missing something?





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-05-01 13:55                 ` Aaron Jensen
@ 2023-05-01 14:06                   ` Aaron Jensen
  0 siblings, 0 replies; 71+ messages in thread
From: Aaron Jensen @ 2023-05-01 14:06 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: luangruo, alan, 63187

On Mon, May 1, 2023 at 9:55 AM Aaron Jensen <aaronjensen@gmail.com> wrote:
>
> On Mon, May 1, 2023 at 9:51 AM Eli Zaretskii <eliz@gnu.org> wrote:
> >
> > > From: Aaron Jensen <aaronjensen@gmail.com>
> > > Date: Mon, 1 May 2023 09:47:50 -0400
> > > Cc: Po Lu <luangruo@yahoo.com>, Alan Third <alan@idiocy.org>, 63187@debbugs.gnu.org
> > >
> > >   {
> > >     NSRect srcRect = NSMakeRect (x, from_y, width, height);
> > >     NSPoint dest = NSMakePoint (x, to_y);
> > >     EmacsView *view = FRAME_NS_VIEW (f);
> > >
> > >     [view copyRect:srcRect to:dest];
> > > #ifdef NS_IMPL_COCOA
> > >     [view setNeedsDisplayInRect:srcRect];
> > > #endif
> > >   }
> > >
> > > Why is the source being marked for redisplay? I would expect the
> > > destination to be marked as such, or am I missing something?
> >
> > IMO, both should be marked for redisplay.  Or maybe I don't understand
> > the significance of marking a rectangle for redisplay.
>
> For reference, this is in `ns_scroll_run'. Only the destination is
> changed, right? I imagine the source would be effectively marked when
> it's copied into, so marking the source in this code would be
> redundant, unless I'm missing something?

Also, the previous version of `ns_flush_display' was this:

static void
ns_flush_display (struct frame *f)
/* Force the frame to redisplay.  If areas have previously been marked
   dirty by setNeedsDisplayInRect (in ns_clip_to_rect), then this will call
   draw_rect: which will "expose" those areas.  */
{
  block_input ();
  [FRAME_NS_VIEW (f) displayIfNeeded];
  unblock_input ();
}

The displayIfNeeded has been removed and is now ultimately replaced
with stuff I don't understand. After looking at this code, I'm now
wondering if my problem has to do with the fact that I use child
frames for things like completions. I have recollection of the
painting artifacts appearing under areas that child frames are
temporarily covering. Is it possible that somehow those areas aren't
being properly repainted/marked for repainting?





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-05-01 13:25           ` Eli Zaretskii
  2023-05-01 13:47             ` Aaron Jensen
@ 2023-05-01 17:26             ` Alan Third
  2023-05-01 22:40               ` Aaron Jensen
  2023-05-02  0:07               ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 2 replies; 71+ messages in thread
From: Alan Third @ 2023-05-01 17:26 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Po Lu, 63187, aaronjensen

On Mon, May 01, 2023 at 04:25:05PM +0300, Eli Zaretskii wrote:
> > From: Po Lu <luangruo@yahoo.com>
> > Cc: aaronjensen@gmail.com,  63187@debbugs.gnu.org
> > Date: Mon, 01 May 2023 21:18:31 +0800
> > 
> > Eli Zaretskii <eliz@gnu.org> writes:
> > 
> > >> Cc: 63187@debbugs.gnu.org
> > >> Date: Mon, 01 May 2023 07:58:26 +0800
> > >> From:  Po Lu via "Bug reports for GNU Emacs,
> > >>  the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
> > >> 
> > >> Aaron Jensen <aaronjensen@gmail.com> writes:
> > >> 
> > >> > Is there anything specific to macOS that is involved in scrolling optimization?
> > >> 
> > >> Yes, Apple deleted the API used to perform bit blits, so Emacs uses a
> > >> workaround that I don't really understand, and seems unreliable.
> > >
> > > You mean, ns_scroll_run in nsterm.m?  Which parts of it do you not
> > > understand?
> > 
> > No, I meant the implementation of [EmacsView copyRect:] enabled under
> > Mac OS; see line 8655 of nsterm.m.  I don't understand how the system
> > synchronizes its access to the window's backing store with Emacs's.
> 
> Alan, can you help?
> 
> If this is unworkable on macOS, we could simply disable this
> optimization there.  But note that scroll_run_hook is also called from
> xdisp.c, in several places, so we may need to disable it there as
> well.

This is one of the many reasons I walked away from the NS port. ;)

I'm 99% certain that [EmacsView copyRect:] is correct. I went over it
numerous times. It's just doing a simple copy of one rectangle of a
graphics buffer to another, identically sized, rectangle. It handles
overlapping rectangles and there's really not very much logic in it to
go wrong.

Po Lu asks about how it synchronises with the system, and it doesn't
really have to. The system draws into the same buffer that copyRect
accesses. It does make me wonder if there's a rare occasion when
copyRect is called and the system hasn't flushed all it's drawing
instructions to the buffer yet. It's probably possible to force it to
flush by doing something like:

    [[NSGraphicsContext currentContext] flushGraphics];

at the top of copyRect. Preferably only on macOS 10.14 and above, but
it probably makes no difference on other platforms since scrollRect
should force a flush anyway.

My memory of Aaron's previous bug report about this was that it looked
like, in some cases at least, the rectangle being copied was too wide
and copyRect, not being very smart, was just wrapping off the edge of
the buffer onto the next row of pixels, but I couldn't find any reason
for that to happen since afaik all the callers check the Emacs window
size so should never ask to copy a too-wide rectangle.

-- 
Alan Third





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-05-01 17:26             ` Alan Third
@ 2023-05-01 22:40               ` Aaron Jensen
  2023-05-02 10:14                 ` Alan Third
  2023-05-02  0:07               ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 1 reply; 71+ messages in thread
From: Aaron Jensen @ 2023-05-01 22:40 UTC (permalink / raw)
  To: Alan Third, Eli Zaretskii, Po Lu, 63187, aaronjensen

On Mon, May 1, 2023 at 1:26 PM Alan Third <alan@idiocy.org> wrote:
>
> This is one of the many reasons I walked away from the NS port. ;)

You are missed :)

> I'm 99% certain that [EmacsView copyRect:] is correct. I went over it
> numerous times. It's just doing a simple copy of one rectangle of a
> graphics buffer to another, identically sized, rectangle. It handles
> overlapping rectangles and there's really not very much logic in it to
> go wrong.
>
> Po Lu asks about how it synchronises with the system, and it doesn't
> really have to. The system draws into the same buffer that copyRect
> accesses. It does make me wonder if there's a rare occasion when
> copyRect is called and the system hasn't flushed all it's drawing
> instructions to the buffer yet. It's probably possible to force it to
> flush by doing something like:
>
>     [[NSGraphicsContext currentContext] flushGraphics];
>
> at the top of copyRect. Preferably only on macOS 10.14 and above, but
> it probably makes no difference on other platforms since scrollRect
> should force a flush anyway.
>
> My memory of Aaron's previous bug report about this was that it looked
> like, in some cases at least, the rectangle being copied was too wide
> and copyRect, not being very smart, was just wrapping off the edge of
> the buffer onto the next row of pixels, but I couldn't find any reason
> for that to happen since afaik all the callers check the Emacs window
> size so should never ask to copy a too-wide rectangle.

This one seems to be more about longer lines ghosting onto the tail
end of shorter lines. You could imagine that if you had a long line
and a short line, then scrolled such that the short line was where the
long line was but only repainted the area there were glyphs, the new
short line would include the tail end of the long line:

window line 2: xxxxxxxxxxxxxx
window line 3: yyyyyyyyyy
->
window 1: xxxxxxxxxxxxxx
window 2: yyyyyyyyyyxxxx

What do you think about what I mentioned later in the thread about:

[view setNeedsDisplayInRect:srcRect];

Why would that be srcRect and not destRect? Could that cause this somehow?

Thanks,

Aaron





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-05-01 17:26             ` Alan Third
  2023-05-01 22:40               ` Aaron Jensen
@ 2023-05-02  0:07               ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-05-02  0:32                 ` Aaron Jensen
  1 sibling, 1 reply; 71+ messages in thread
From: Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-02  0:07 UTC (permalink / raw)
  To: Alan Third; +Cc: Eli Zaretskii, 63187, aaronjensen

Alan Third <alan@idiocy.org> writes:

> Po Lu asks about how it synchronises with the system, and it doesn't
> really have to. The system draws into the same buffer that copyRect
> accesses. It does make me wonder if there's a rare occasion when
> copyRect is called and the system hasn't flushed all it's drawing
> instructions to the buffer yet. It's probably possible to force it to
> flush by doing something like:
>
>     [[NSGraphicsContext currentContext] flushGraphics];
>
> at the top of copyRect. Preferably only on macOS 10.14 and above, but
> it probably makes no difference on other platforms since scrollRect
> should force a flush anyway.

Hmm... Aaron, could you try that?

BTW, I've just noticed that ns_scroll_run invalidates the source
rectangle, not the destination.  Shouldn't things be the other way
around?  I see Aaron saw that as well.





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-05-02  0:07               ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-05-02  0:32                 ` Aaron Jensen
  0 siblings, 0 replies; 71+ messages in thread
From: Aaron Jensen @ 2023-05-02  0:32 UTC (permalink / raw)
  To: Po Lu; +Cc: Alan Third, 63187, Eli Zaretskii

On Mon, May 1, 2023 at 8:07 PM Po Lu <luangruo@yahoo.com> wrote:
>
> Alan Third <alan@idiocy.org> writes:
>
> > Po Lu asks about how it synchronises with the system, and it doesn't
> > really have to. The system draws into the same buffer that copyRect
> > accesses. It does make me wonder if there's a rare occasion when
> > copyRect is called and the system hasn't flushed all it's drawing
> > instructions to the buffer yet. It's probably possible to force it to
> > flush by doing something like:
> >
> >     [[NSGraphicsContext currentContext] flushGraphics];
> >
> > at the top of copyRect. Preferably only on macOS 10.14 and above, but
> > it probably makes no difference on other platforms since scrollRect
> > should force a flush anyway.
>
> Hmm... Aaron, could you try that?

I'll try it after I try running w/ the invalidate change. I'll report
back if that doesn't fix it and try the flush.

Aaron





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-05-01 22:40               ` Aaron Jensen
@ 2023-05-02 10:14                 ` Alan Third
  2023-05-02 12:21                   ` Eli Zaretskii
  0 siblings, 1 reply; 71+ messages in thread
From: Alan Third @ 2023-05-02 10:14 UTC (permalink / raw)
  To: Aaron Jensen; +Cc: Po Lu, Eli Zaretskii, 63187

On Mon, May 01, 2023 at 06:40:15PM -0400, Aaron Jensen wrote:
> On Mon, May 1, 2023 at 1:26 PM Alan Third <alan@idiocy.org> wrote:
> >
> > My memory of Aaron's previous bug report about this was that it looked
> > like, in some cases at least, the rectangle being copied was too wide
> > and copyRect, not being very smart, was just wrapping off the edge of
> > the buffer onto the next row of pixels, but I couldn't find any reason
> > for that to happen since afaik all the callers check the Emacs window
> > size so should never ask to copy a too-wide rectangle.
> 
> This one seems to be more about longer lines ghosting onto the tail
> end of shorter lines. You could imagine that if you had a long line
> and a short line, then scrolled such that the short line was where the
> long line was but only repainted the area there were glyphs, the new
> short line would include the tail end of the long line:
> 
> window line 2: xxxxxxxxxxxxxx
> window line 3: yyyyyyyyyy
> ->
> window 1: xxxxxxxxxxxxxx
> window 2: yyyyyyyyyyxxxx

Yeah, that's why I'm wondering if there's a timing thing where the
toolkit hasn't completed it's drawing before we copy the pixels. Emacs
might ask to clear the end of a line, then copy those "cleared" pixels
using copyRect before the initial clear has actually been completed.

This is just conjecture, though.

The other option is that it is copying too much and grabbing things it
shouldn't, but even though I think we've seen that before, I don't
know how it would happen.

Although, on reflection, your description sounds more like it's just
not clearing the end of lines correctly, which wouldn't necessarily
have anything to do with scrolling as such...

> What do you think about what I mentioned later in the thread about:
> 
> [view setNeedsDisplayInRect:srcRect];
> 
> Why would that be srcRect and not destRect? Could that cause this somehow?

I suspect that's a hang-over from the old rendering scheme where we
would have had to flag up that the source would need redrawn later.

scrollRect already marks the destination as needing updated on screen,
but iirc for whatever reason the source was never flagged as needing
redrawn, which it almost always did when scrolling.

The 10.14+ drawing scheme doesn't really require individual areas to
be marked as needing redrawn since the entire back buffer is sent to
the screen on update anyway. It could be worth replacing that with a
call to [NSView setNeedsDisplay:], or getting rid of it and making
copyRect do it instead. I don't know if it's even necessary since
I think Emacs will always do other drawing actions as part of a scroll
which will mark the view as needing sent to the screen.
-- 
Alan Third





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-05-02 10:14                 ` Alan Third
@ 2023-05-02 12:21                   ` Eli Zaretskii
  2023-05-02 22:36                     ` Alan Third
  0 siblings, 1 reply; 71+ messages in thread
From: Eli Zaretskii @ 2023-05-02 12:21 UTC (permalink / raw)
  To: Alan Third; +Cc: luangruo, alan, 63187, aaronjensen

> Date: Tue, 2 May 2023 11:14:56 +0100
> From: Alan Third <alan@idiocy.org>
> Cc: Eli Zaretskii <eliz@gnu.org>, Po Lu <luangruo@yahoo.com>,
> 	63187@debbugs.gnu.org
> 
> Although, on reflection, your description sounds more like it's just
> not clearing the end of lines correctly, which wouldn't necessarily
> have anything to do with scrolling as such...

Can that happen in this case?  You will see in the code that (AFAIU)
it copies a rectangle whose width is the total width of the window, so
why would (not) clearing ends of lines be an issue?





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-05-02 12:21                   ` Eli Zaretskii
@ 2023-05-02 22:36                     ` Alan Third
  2023-05-03  8:11                       ` Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-05-03 13:08                       ` Eli Zaretskii
  0 siblings, 2 replies; 71+ messages in thread
From: Alan Third @ 2023-05-02 22:36 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: luangruo, 63187, aaronjensen

On Tue, May 02, 2023 at 03:21:46PM +0300, Eli Zaretskii wrote:
> > Date: Tue, 2 May 2023 11:14:56 +0100
> > From: Alan Third <alan@idiocy.org>
> > Cc: Eli Zaretskii <eliz@gnu.org>, Po Lu <luangruo@yahoo.com>,
> > 	63187@debbugs.gnu.org
> > 
> > Although, on reflection, your description sounds more like it's just
> > not clearing the end of lines correctly, which wouldn't necessarily
> > have anything to do with scrolling as such...
> 
> Can that happen in this case?  You will see in the code that (AFAIU)
> it copies a rectangle whose width is the total width of the window, so
> why would (not) clearing ends of lines be an issue?

It depends where the actual problem is occurring. It's hard to tell
from the screenshots whether the rogue glyphs appear spontaneously in
the middle of the window, or as a new line is scrolled onto the
screen.

If it's the latter then obviously the procedure is to clear the line
that's to be drawn, then draw the new content, however if the clearing
isn't done correctly then you end up with the end of the line that was
there previously still visible to the right of the new content.

As it scrolls further, Emacs no doubt is clever enough to know that it
doesn't need to clear more than it drew for the last line, so the
rogue characters at the end stay for the subsequent line, and so on
until it hits a line that is long enough to wipe it all out.

I hope I'm explaining this well enough.

Either way, I don't know why it would be happening.
-- 
Alan Third





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-05-02 22:36                     ` Alan Third
@ 2023-05-03  8:11                       ` Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-05-03 13:08                       ` Eli Zaretskii
  1 sibling, 0 replies; 71+ messages in thread
From: Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-03  8:11 UTC (permalink / raw)
  To: Alan Third; +Cc: luangruo, Eli Zaretskii, 63187, aaronjensen

Alan Third <alan@idiocy.org> writes:

> On Tue, May 02, 2023 at 03:21:46PM +0300, Eli Zaretskii wrote:
>> > Date: Tue, 2 May 2023 11:14:56 +0100
>> > From: Alan Third <alan@idiocy.org>
>> > Cc: Eli Zaretskii <eliz@gnu.org>, Po Lu <luangruo@yahoo.com>,
>> > 	63187@debbugs.gnu.org
>> > 
>> > Although, on reflection, your description sounds more like it's just
>> > not clearing the end of lines correctly, which wouldn't necessarily
>> > have anything to do with scrolling as such...
>> 
>> Can that happen in this case?  You will see in the code that (AFAIU)
>> it copies a rectangle whose width is the total width of the window, so
>> why would (not) clearing ends of lines be an issue?
>
> It depends where the actual problem is occurring. It's hard to tell
> from the screenshots whether the rogue glyphs appear spontaneously in
> the middle of the window, or as a new line is scrolled onto the
> screen.
>
> If it's the latter then obviously the procedure is to clear the line
> that's to be drawn, then draw the new content, however if the clearing
> isn't done correctly then you end up with the end of the line that was
> there previously still visible to the right of the new content.
>
> As it scrolls further, Emacs no doubt is clever enough to know that it
> doesn't need to clear more than it drew for the last line, so the
> rogue characters at the end stay for the subsequent line, and so on
> until it hits a line that is long enough to wipe it all out.
>
> I hope I'm explaining this well enough.
>
> Either way, I don't know why it would be happening.

Could we add some tracing (or assertions) to the NS port, to help
understand this problem better?  I've also seen some rogue characters
from time to time (not frequently, and my Emacs sessions last long).  I
think it all started since the migration to IOSurface, but I'm not sure.
I don't have clear steps to reproduce yet.





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-05-02 22:36                     ` Alan Third
  2023-05-03  8:11                       ` Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-05-03 13:08                       ` Eli Zaretskii
  1 sibling, 0 replies; 71+ messages in thread
From: Eli Zaretskii @ 2023-05-03 13:08 UTC (permalink / raw)
  To: Alan Third; +Cc: luangruo, 63187, aaronjensen

> Date: Tue, 2 May 2023 23:36:34 +0100
> From: Alan Third <alan@idiocy.org>
> Cc: aaronjensen@gmail.com, luangruo@yahoo.com, 63187@debbugs.gnu.org
> 
> On Tue, May 02, 2023 at 03:21:46PM +0300, Eli Zaretskii wrote:
> > > Date: Tue, 2 May 2023 11:14:56 +0100
> > > From: Alan Third <alan@idiocy.org>
> > > Cc: Eli Zaretskii <eliz@gnu.org>, Po Lu <luangruo@yahoo.com>,
> > > 	63187@debbugs.gnu.org
> > > 
> > > Although, on reflection, your description sounds more like it's just
> > > not clearing the end of lines correctly, which wouldn't necessarily
> > > have anything to do with scrolling as such...
> > 
> > Can that happen in this case?  You will see in the code that (AFAIU)
> > it copies a rectangle whose width is the total width of the window, so
> > why would (not) clearing ends of lines be an issue?
> 
> It depends where the actual problem is occurring. It's hard to tell
> from the screenshots whether the rogue glyphs appear spontaneously in
> the middle of the window, or as a new line is scrolled onto the
> screen.

AFAIU, a new line scrolled into the screen is not handled by
scroll_run_hook.  Such a line is drawn anew, because there's no way we
have it in the glyph matrices and/or on the glass, by definition.

> As it scrolls further, Emacs no doubt is clever enough to know that it
> doesn't need to clear more than it drew for the last line, so the
> rogue characters at the end stay for the subsequent line, and so on
> until it hits a line that is long enough to wipe it all out.

I think you are describing something that happens only on TTY
terminals, if ever.  Emacs doesn't work that way on GUI terminals, and
if scroll_run_hook is indeed the culprit (that remains yet to be
proven, AFAIU), it is used in situations that are not necessarily
"scrolling" from the user POV.  This hook is run when Emacs determines
that some part of the display is exactly what is needed to be
displayed, but it is higher or lower on the screen than where it
should be.  Then (subject to some criteria of whether this
optimization is worth our while), we call this hook, which is supposed
to copy the pixels on the screen in the vertical direction, either up
or down.  It always copies the entire width of the window, so clearing
to EOL should not be the issue here, since the "cleared" pixels are
moved as well.





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-05-01 13:47             ` Aaron Jensen
  2023-05-01 13:52               ` Eli Zaretskii
@ 2023-05-09  3:07               ` Aaron Jensen
  2023-05-09  5:39                 ` Eli Zaretskii
  1 sibling, 1 reply; 71+ messages in thread
From: Aaron Jensen @ 2023-05-09  3:07 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Po Lu, Alan Third, 63187

On Mon, May 1, 2023 at 9:47 AM Aaron Jensen <aaronjensen@gmail.com> wrote:
>
> On Mon, May 1, 2023 at 9:24 AM Eli Zaretskii <eliz@gnu.org> wrote:
> >
> > > From: Po Lu <luangruo@yahoo.com>
> > > Cc: aaronjensen@gmail.com,  63187@debbugs.gnu.org
> > > Date: Mon, 01 May 2023 21:18:31 +0800
> > >
> > > Eli Zaretskii <eliz@gnu.org> writes:
> > >
> > > >> Cc: 63187@debbugs.gnu.org
> > > >> Date: Mon, 01 May 2023 07:58:26 +0800
> > > >> From:  Po Lu via "Bug reports for GNU Emacs,
> > > >>  the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
> > > >>
> > > >> Aaron Jensen <aaronjensen@gmail.com> writes:
> > > >>
> > > >> > Is there anything specific to macOS that is involved in scrolling optimization?
> > > >>
> > > >> Yes, Apple deleted the API used to perform bit blits, so Emacs uses a
> > > >> workaround that I don't really understand, and seems unreliable.
> > > >
> > > > You mean, ns_scroll_run in nsterm.m?  Which parts of it do you not
> > > > understand?
> > >
> > > No, I meant the implementation of [EmacsView copyRect:] enabled under
> > > Mac OS; see line 8655 of nsterm.m.  I don't understand how the system
> > > synchronizes its access to the window's backing store with Emacs's.
> >
> > Alan, can you help?
> >
> > If this is unworkable on macOS, we could simply disable this
> > optimization there.  But note that scroll_run_hook is also called from
> > xdisp.c, in several places, so we may need to disable it there as
> > well.
>
> Is this suspect?
>
>   {
>     NSRect srcRect = NSMakeRect (x, from_y, width, height);
>     NSPoint dest = NSMakePoint (x, to_y);
>     EmacsView *view = FRAME_NS_VIEW (f);
>
>     [view copyRect:srcRect to:dest];
> #ifdef NS_IMPL_COCOA
>     [view setNeedsDisplayInRect:srcRect];
> #endif
>   }
>
> Why is the source being marked for redisplay? I would expect the
> destination to be marked as such, or am I missing something?

It's not definitive, because it's always been intermittent, but I have
not seen the issue once since making this change a week ago. I'll give
it another week or two, but it certainly hasn't caused any problems
and may be worth considering for 29 before it is released.

diff --git a/src/nsterm.m b/src/nsterm.m
index ecbf80ff72d..310d2bd81c7 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -2704,11 +2704,12 @@ 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
-    [view setNeedsDisplayInRect:srcRect];
+    [view setNeedsDisplayInRect:destRect];
 #endif
   }

Aaron





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-05-09  3:07               ` Aaron Jensen
@ 2023-05-09  5:39                 ` Eli Zaretskii
  2023-05-13 13:54                   ` Eli Zaretskii
  0 siblings, 1 reply; 71+ messages in thread
From: Eli Zaretskii @ 2023-05-09  5:39 UTC (permalink / raw)
  To: Aaron Jensen; +Cc: luangruo, alan, 63187

> From: Aaron Jensen <aaronjensen@gmail.com>
> Date: Mon, 8 May 2023 23:07:00 -0400
> Cc: Po Lu <luangruo@yahoo.com>, Alan Third <alan@idiocy.org>, 63187@debbugs.gnu.org
> 
> It's not definitive, because it's always been intermittent, but I have
> not seen the issue once since making this change a week ago. I'll give
> it another week or two, but it certainly hasn't caused any problems
> and may be worth considering for 29 before it is released.

I'm just waiting for you guys to decide that it was tested long
enough, that's all.  I guess you are not yet there, right?





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-05-09  5:39                 ` Eli Zaretskii
@ 2023-05-13 13:54                   ` Eli Zaretskii
  2023-05-13 14:23                     ` Aaron Jensen
  0 siblings, 1 reply; 71+ messages in thread
From: Eli Zaretskii @ 2023-05-13 13:54 UTC (permalink / raw)
  To: aaronjensen, luangruo, alan; +Cc: 63187

Ping!  Should the patch be installed now on the emacs-29 branch?

> Cc: luangruo@yahoo.com, alan@idiocy.org, 63187@debbugs.gnu.org
> Date: Tue, 09 May 2023 08:39:02 +0300
> From: Eli Zaretskii <eliz@gnu.org>
> 
> > From: Aaron Jensen <aaronjensen@gmail.com>
> > Date: Mon, 8 May 2023 23:07:00 -0400
> > Cc: Po Lu <luangruo@yahoo.com>, Alan Third <alan@idiocy.org>, 63187@debbugs.gnu.org
> > 
> > It's not definitive, because it's always been intermittent, but I have
> > not seen the issue once since making this change a week ago. I'll give
> > it another week or two, but it certainly hasn't caused any problems
> > and may be worth considering for 29 before it is released.
> 
> I'm just waiting for you guys to decide that it was tested long
> enough, that's all.  I guess you are not yet there, right?
> 
> 
> 
> 






^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-05-13 13:54                   ` Eli Zaretskii
@ 2023-05-13 14:23                     ` Aaron Jensen
  2023-05-18 11:21                       ` Eli Zaretskii
  0 siblings, 1 reply; 71+ messages in thread
From: Aaron Jensen @ 2023-05-13 14:23 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: luangruo, alan, 63187

On Sat, May 13, 2023 at 9:54 AM Eli Zaretskii <eliz@gnu.org> wrote:
>
> Ping!  Should the patch be installed now on the emacs-29 branch?

I think it's worth it. I may have seen 1 glitch (but it was different
-- it looked like an entire blank line was duplicated. Other than
that, it's been solid, which is quite a bit better than it had been
before.

Aaron





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-05-13 14:23                     ` Aaron Jensen
@ 2023-05-18 11:21                       ` Eli Zaretskii
  2023-05-18 15:59                         ` Aaron Jensen
  0 siblings, 1 reply; 71+ messages in thread
From: Eli Zaretskii @ 2023-05-18 11:21 UTC (permalink / raw)
  To: Aaron Jensen; +Cc: luangruo, alan, 63187-done

> From: Aaron Jensen <aaronjensen@gmail.com>
> Date: Sat, 13 May 2023 10:23:28 -0400
> Cc: luangruo@yahoo.com, alan@idiocy.org, 63187@debbugs.gnu.org
> 
> On Sat, May 13, 2023 at 9:54 AM Eli Zaretskii <eliz@gnu.org> wrote:
> >
> > Ping!  Should the patch be installed now on the emacs-29 branch?
> 
> I think it's worth it. I may have seen 1 glitch (but it was different
> -- it looked like an entire blank line was duplicated. Other than
> that, it's been solid, which is quite a bit better than it had been
> before.

Now installed on the emacs-29 branch, and closing the bug.





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-05-18 11:21                       ` Eli Zaretskii
@ 2023-05-18 15:59                         ` Aaron Jensen
  2023-06-08  5:40                           ` Kai Ma
  0 siblings, 1 reply; 71+ messages in thread
From: Aaron Jensen @ 2023-05-18 15:59 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: luangruo, alan, 63187-done

[-- Attachment #1: Type: text/plain, Size: 755 bytes --]

Thank you. I'll report back if I start seeing it again, but so far so good.


Aaron


On Thu, May 18, 2023 at 7:21 AM, Eli Zaretskii <eliz@gnu.org> wrote:

> From: Aaron Jensen <aaronjensen@gmail.com>
> Date: Sat, 13 May 2023 10:23:28 -0400
> Cc: luangruo@yahoo.com, alan@idiocy.org, 63187@debbugs.gnu.org
>
> On Sat, May 13, 2023 at 9:54 AM Eli Zaretskii <eliz@gnu.org> wrote:
>
> Ping! Should the patch be installed now on the emacs-29 branch?
>
> I think it's worth it. I may have seen 1 glitch (but it was different
> -- it looked like an entire blank line was duplicated. Other than that,
> it's been solid, which is quite a bit better than it had been before.
>
> Now installed on the emacs-29 branch, and closing the bug.
>

[-- Attachment #2: Type: text/html, Size: 2239 bytes --]

^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-05-18 15:59                         ` Aaron Jensen
@ 2023-06-08  5:40                           ` Kai Ma
  2023-06-08  7:33                             ` Kai Ma
  0 siblings, 1 reply; 71+ messages in thread
From: Kai Ma @ 2023-06-08  5:40 UTC (permalink / raw)
  To: Aaron Jensen; +Cc: luangruo, Eli Zaretskii, 63187, 63187-done, alan


Hi everyone, I'm also bothered by this bug recently.  And it is
happening quite frequently for me.

Unfortunately, the proposed patch and putting
  [[NSGraphicsContext currentContext] flushGraphics];
in copyRect didn't work for me.

See the screencast at https://www.youtube.com/watch?v=uLYPqsUFK5A .

I find that this bug happens more frequently if
1) the frame's alpha < 1.0, and
2) the frame is in the full screen mode, and
3) emacs is built with native compilation enabled.

(Not doing one or two of these does not prevent the bug from happening,
but seems to reduce the likelihood.)

FWIW, some version numbers:
- emacs 30.0.50 master branch
- macOS 13.4 (22F66), Intel


Aaron Jensen <aaronjensen@gmail.com> writes:

> Thank you. I'll report back if I start seeing it again, but so far so good.
>
> Aaron
>
> On Thu, May 18, 2023 at 7:21 AM, Eli Zaretskii <eliz@gnu.org> wrote:
>
>  From: Aaron Jensen <aaronjensen@gmail.com> 
>  Date: Sat, 13 May 2023 10:23:28 -0400 
>  Cc: luangruo@yahoo.com, alan@idiocy.org, 63187@debbugs.gnu.org 
>
>  On Sat, May 13, 2023 at 9:54 AM Eli Zaretskii <eliz@gnu.org> wrote: 
>
>  Ping! Should the patch be installed now on the emacs-29 branch? 
>
>  I think it's worth it. I may have seen 1 glitch (but it was different 
>  -- it looked like an entire blank line was duplicated. Other than that, it's been solid, which is quite a bit better than it had been
>  before. 
>
>  Now installed on the emacs-29 branch, and closing the bug.
>





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-08  5:40                           ` Kai Ma
@ 2023-06-08  7:33                             ` Kai Ma
  2023-06-08 12:51                               ` Alan Third
  0 siblings, 1 reply; 71+ messages in thread
From: Kai Ma @ 2023-06-08  7:33 UTC (permalink / raw)
  To: 63187; +Cc: Po Lu, Eli Zaretskii, Aaron Jensen, alan, 63187-done



> On Jun 8, 2023, at 13:40, Kai Ma <justksqsf@gmail.com> wrote:
> 
> 
> Hi everyone, I'm also bothered by this bug recently.  And it is
> happening quite frequently for me.
> 
> Unfortunately, the proposed patch and putting
>  [[NSGraphicsContext currentContext] flushGraphics];
> in copyRect didn't work for me.
> 
> See the screencast at https://www.youtube.com/watch?v=uLYPqsUFK5A .

Upon further debugging, the following change seems to fix the problem for me.

--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -10433,7 +10433,7 @@ @implementation EmacsLayer
    cache.  If no free surfaces are found in the cache then a new one
    is created.  */
 
-#define CACHE_MAX_SIZE 2
+#define CACHE_MAX_SIZE 1
 
 - (id) initWithColorSpace: (CGColorSpaceRef)cs
 {


This probably implies that there is another bug somewhere else in the management of IOSurface caches.


> 
> I find that this bug happens more frequently if
> 1) the frame's alpha < 1.0, and
> 2) the frame is in the full screen mode, and
> 3) emacs is built with native compilation enabled.
> 
> (Not doing one or two of these does not prevent the bug from happening,
> but seems to reduce the likelihood.)
> 
> FWIW, some version numbers:
> - emacs 30.0.50 master branch
> - macOS 13.4 (22F66), Intel
> 
> 
> Aaron Jensen <aaronjensen@gmail.com> writes:
> 
>> Thank you. I'll report back if I start seeing it again, but so far so good.
>> 
>> Aaron
>> 
>> On Thu, May 18, 2023 at 7:21 AM, Eli Zaretskii <eliz@gnu.org> wrote:
>> 
>> From: Aaron Jensen <aaronjensen@gmail.com> 
>> Date: Sat, 13 May 2023 10:23:28 -0400 
>> Cc: luangruo@yahoo.com, alan@idiocy.org, 63187@debbugs.gnu.org 
>> 
>> On Sat, May 13, 2023 at 9:54 AM Eli Zaretskii <eliz@gnu.org> wrote: 
>> 
>> Ping! Should the patch be installed now on the emacs-29 branch? 
>> 
>> I think it's worth it. I may have seen 1 glitch (but it was different 
>> -- it looked like an entire blank line was duplicated. Other than that, it's been solid, which is quite a bit better than it had been
>> before. 
>> 
>> Now installed on the emacs-29 branch, and closing the bug.
>> 






^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-08  7:33                             ` Kai Ma
@ 2023-06-08 12:51                               ` Alan Third
  2023-06-08 13:42                                 ` Kai Ma
  0 siblings, 1 reply; 71+ messages in thread
From: Alan Third @ 2023-06-08 12:51 UTC (permalink / raw)
  To: Kai Ma; +Cc: Po Lu, 63187, Eli Zaretskii, Aaron Jensen

On Thu, Jun 08, 2023 at 03:33:41PM +0800, Kai Ma wrote:
> 
> 
> > On Jun 8, 2023, at 13:40, Kai Ma <justksqsf@gmail.com> wrote:
> > 
> > 
> > Hi everyone, I'm also bothered by this bug recently.  And it is
> > happening quite frequently for me.
> > 
> > Unfortunately, the proposed patch and putting
> >  [[NSGraphicsContext currentContext] flushGraphics];
> > in copyRect didn't work for me.
> > 
> > See the screencast at https://www.youtube.com/watch?v=uLYPqsUFK5A .
> 
> Upon further debugging, the following change seems to fix the problem for me.
> 
> --- a/src/nsterm.m
> +++ b/src/nsterm.m
> @@ -10433,7 +10433,7 @@ @implementation EmacsLayer
>     cache.  If no free surfaces are found in the cache then a new one
>     is created.  */
>  
> -#define CACHE_MAX_SIZE 2
> +#define CACHE_MAX_SIZE 1
>  
>  - (id) initWithColorSpace: (CGColorSpaceRef)cs
>  {
> 
> 
> This probably implies that there is another bug somewhere else in
> the management of IOSurface caches.

I did wonder about this, but I can't see where the failure would be
happening.

I've got two things it could be worth trying to see if they make any
difference.

Change the CACHE_MAX_SIZE to something greater than 2, probably 4 is a
good number. That would rule out some sort of locking problem, as it
would reduce the chance a surface would be re-used before it's been
sent to the screen.

The downside of this is probably going to be an increase in "lag"
because it's possible to have more surfaces "in-flight".

The other option is to remove this call (nsterm.m:10636):

      /* 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];

I think this is harmless, but it's in there as I *assume*, with
absolutely no proof, that it will improve performance and it seems
possible (but I think unlikely) that it may affect the sequencing of
surface operations.
-- 
Alan Third





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-08 12:51                               ` Alan Third
@ 2023-06-08 13:42                                 ` Kai Ma
  2023-06-08 14:57                                   ` Kai Ma
  0 siblings, 1 reply; 71+ messages in thread
From: Kai Ma @ 2023-06-08 13:42 UTC (permalink / raw)
  To: Alan Third; +Cc: Po Lu, 63187, Eli Zaretskii, Aaron Jensen


> On Jun 8, 2023, at 20:51, Alan Third <alan@idiocy.org> wrote:
> 
> I've got two things it could be worth trying to see if they make any
> difference.
> Change the CACHE_MAX_SIZE to something greater than 2, probably 4 is a
> good number. That would rule out some sort of locking problem, as it
> would reduce the chance a surface would be re-used before it's been
> sent to the screen.
> 
> The downside of this is probably going to be an increase in "lag"
> because it's possible to have more surfaces "in-flight".
> 
> The other option is to remove this call (nsterm.m:10636):
> 
>   /* 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];
> 
> I think this is harmless, but it's in there as I *assume*, with
> absolutely no proof, that it will improve performance and it seems
> possible (but I think unlikely) that it may affect the sequencing of
> surface operations.

Tested locally.  I can confirm that removing performSelectorOnMainThread (with CACHE_MAX_SIZE = 2) fixes the problem for me.  I now observe zero glitches or tearings!







^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-08 13:42                                 ` Kai Ma
@ 2023-06-08 14:57                                   ` Kai Ma
  2023-06-08 17:22                                     ` Alan Third
  0 siblings, 1 reply; 71+ messages in thread
From: Kai Ma @ 2023-06-08 14:57 UTC (permalink / raw)
  To: Alan Third; +Cc: Po Lu, 63187, Eli Zaretskii, Aaron Jensen



> On Jun 8, 2023, at 21:42, Kai Ma <justksqsf@gmail.com> wrote:
> 
> 
>> On Jun 8, 2023, at 20:51, Alan Third <alan@idiocy.org> wrote:
>> 
>> I've got two things it could be worth trying to see if they make any
>> difference.
>> Change the CACHE_MAX_SIZE to something greater than 2, probably 4 is a
>> good number. That would rule out some sort of locking problem, as it
>> would reduce the chance a surface would be re-used before it's been
>> sent to the screen.
>> 
>> The downside of this is probably going to be an increase in "lag"
>> because it's possible to have more surfaces "in-flight".
>> 
>> The other option is to remove this call (nsterm.m:10636):
>> 
>>  /* 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];
>> 
>> I think this is harmless, but it's in there as I *assume*, with
>> absolutely no proof, that it will improve performance and it seems
>> possible (but I think unlikely) that it may affect the sequencing of
>> surface operations.
> 
> Tested locally.  I can confirm that removing performSelectorOnMainThread (with CACHE_MAX_SIZE = 2) fixes the problem for me.  I now observe zero glitches or tearings!
> 

Sorry, I concluded too fast. I can still see tearings, though very rarely. So this is still not a real fix.  :-(






^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-08 14:57                                   ` Kai Ma
@ 2023-06-08 17:22                                     ` Alan Third
  2023-06-09  2:42                                       ` Kai Ma
  0 siblings, 1 reply; 71+ messages in thread
From: Alan Third @ 2023-06-08 17:22 UTC (permalink / raw)
  To: Kai Ma; +Cc: Po Lu, 63187, Eli Zaretskii, Aaron Jensen

On Thu, Jun 08, 2023 at 10:57:43PM +0800, Kai Ma wrote:
> 
> 
> > On Jun 8, 2023, at 21:42, Kai Ma <justksqsf@gmail.com> wrote:
> > 
> > 
> >> On Jun 8, 2023, at 20:51, Alan Third <alan@idiocy.org> wrote:
> >> 
> >> I've got two things it could be worth trying to see if they make any
> >> difference.
> >> Change the CACHE_MAX_SIZE to something greater than 2, probably 4 is a
> >> good number. That would rule out some sort of locking problem, as it
> >> would reduce the chance a surface would be re-used before it's been
> >> sent to the screen.
> >> 
> >> The downside of this is probably going to be an increase in "lag"
> >> because it's possible to have more surfaces "in-flight".
> >> 
> >> The other option is to remove this call (nsterm.m:10636):
> >> 
> >>  /* 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];
> >> 
> >> I think this is harmless, but it's in there as I *assume*, with
> >> absolutely no proof, that it will improve performance and it seems
> >> possible (but I think unlikely) that it may affect the sequencing of
> >> surface operations.
> > 
> > Tested locally. I can confirm that removing
> > performSelectorOnMainThread (with CACHE_MAX_SIZE = 2) fixes the
> > problem for me. I now observe zero glitches or tearings!
> > 
> 
> Sorry, I concluded too fast. I can still see tearings, though very
> rarely. So this is still not a real fix. :-(

Try increasing CACHE_MAX_SIZE too. Tearing would, I believe, be
because a surface is being reused while it's still being copied to the
VRAM, so you'll see a partially modified output.

If increasing CACHE_MAX_SIZE fixes it then there are a couple of
possible options we can look at.
-- 
Alan Third





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-08 17:22                                     ` Alan Third
@ 2023-06-09  2:42                                       ` Kai Ma
  2023-06-09  2:47                                         ` Aaron Jensen
  0 siblings, 1 reply; 71+ messages in thread
From: Kai Ma @ 2023-06-09  2:42 UTC (permalink / raw)
  To: Alan Third; +Cc: Po Lu, 63187, Eli Zaretskii, Aaron Jensen

[-- Attachment #1: Type: text/plain, Size: 2437 bytes --]



> On Jun 9, 2023, at 01:22, Alan Third <alan@idiocy.org> wrote:
> 
> On Thu, Jun 08, 2023 at 10:57:43PM +0800, Kai Ma wrote:
>> 
>> 
>>> On Jun 8, 2023, at 21:42, Kai Ma <justksqsf@gmail.com> wrote:
>>> 
>>> 
>>>> On Jun 8, 2023, at 20:51, Alan Third <alan@idiocy.org> wrote:
>>>> 
>>>> I've got two things it could be worth trying to see if they make any
>>>> difference.
>>>> Change the CACHE_MAX_SIZE to something greater than 2, probably 4 is a
>>>> good number. That would rule out some sort of locking problem, as it
>>>> would reduce the chance a surface would be re-used before it's been
>>>> sent to the screen.
>>>> 
>>>> The downside of this is probably going to be an increase in "lag"
>>>> because it's possible to have more surfaces "in-flight".
>>>> 
>>>> The other option is to remove this call (nsterm.m:10636):
>>>> 
>>>> /* 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];
>>>> 
>>>> I think this is harmless, but it's in there as I *assume*, with
>>>> absolutely no proof, that it will improve performance and it seems
>>>> possible (but I think unlikely) that it may affect the sequencing of
>>>> surface operations.
>>> 
>>> Tested locally. I can confirm that removing
>>> performSelectorOnMainThread (with CACHE_MAX_SIZE = 2) fixes the
>>> problem for me. I now observe zero glitches or tearings!
>>> 
>> 
>> Sorry, I concluded too fast. I can still see tearings, though very
>> rarely. So this is still not a real fix. :-(
> 
> Try increasing CACHE_MAX_SIZE too. Tearing would, I believe, be
> because a surface is being reused while it's still being copied to the
> VRAM, so you'll see a partially modified output.
> 
> If increasing CACHE_MAX_SIZE fixes it then there are a couple of
> possible options we can look at.

Increasing CACHE_MAX_SIZE alone doesn’t seem to help much.
(Screencast: https://www.youtube.com/watch?v=9YD9jyP-GKw)

Increasing CACHE_MAX_SIZE + Removing performSelectorOnMainThread seems to be better but I can’t be sure.  Just observed: 

(1) M-< at the mid of a buffer, but only the first line of the view is refreshed, and other parts were still there.

(2) selecting a region doesn’t always clear the hl-line effect.


[-- Attachment #2: hl-line.png --]
[-- Type: image/png, Size: 76619 bytes --]

[-- Attachment #3: Type: text/plain, Size: 3 bytes --]





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-09  2:42                                       ` Kai Ma
@ 2023-06-09  2:47                                         ` Aaron Jensen
  2023-06-09  3:12                                           ` Kai Ma
  0 siblings, 1 reply; 71+ messages in thread
From: Aaron Jensen @ 2023-06-09  2:47 UTC (permalink / raw)
  To: Kai Ma; +Cc: Po Lu, Alan Third, Eli Zaretskii, 63187

On Thu, Jun 8, 2023 at 10:42 PM Kai Ma <justksqsf@gmail.com> wrote:
>
>
>
> > On Jun 9, 2023, at 01:22, Alan Third <alan@idiocy.org> wrote:
> >
> > On Thu, Jun 08, 2023 at 10:57:43PM +0800, Kai Ma wrote:
> >>
> >>
> >>> On Jun 8, 2023, at 21:42, Kai Ma <justksqsf@gmail.com> wrote:
> >>>
> >>>
> >>>> On Jun 8, 2023, at 20:51, Alan Third <alan@idiocy.org> wrote:
> >>>>
> >>>> I've got two things it could be worth trying to see if they make any
> >>>> difference.
> >>>> Change the CACHE_MAX_SIZE to something greater than 2, probably 4 is a
> >>>> good number. That would rule out some sort of locking problem, as it
> >>>> would reduce the chance a surface would be re-used before it's been
> >>>> sent to the screen.
> >>>>
> >>>> The downside of this is probably going to be an increase in "lag"
> >>>> because it's possible to have more surfaces "in-flight".
> >>>>
> >>>> The other option is to remove this call (nsterm.m:10636):
> >>>>
> >>>> /* 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];
> >>>>
> >>>> I think this is harmless, but it's in there as I *assume*, with
> >>>> absolutely no proof, that it will improve performance and it seems
> >>>> possible (but I think unlikely) that it may affect the sequencing of
> >>>> surface operations.
> >>>
> >>> Tested locally. I can confirm that removing
> >>> performSelectorOnMainThread (with CACHE_MAX_SIZE = 2) fixes the
> >>> problem for me. I now observe zero glitches or tearings!
> >>>
> >>
> >> Sorry, I concluded too fast. I can still see tearings, though very
> >> rarely. So this is still not a real fix. :-(
> >
> > Try increasing CACHE_MAX_SIZE too. Tearing would, I believe, be
> > because a surface is being reused while it's still being copied to the
> > VRAM, so you'll see a partially modified output.
> >
> > If increasing CACHE_MAX_SIZE fixes it then there are a couple of
> > possible options we can look at.
>
> Increasing CACHE_MAX_SIZE alone doesn’t seem to help much.
> (Screencast: https://www.youtube.com/watch?v=9YD9jyP-GKw)
>
> Increasing CACHE_MAX_SIZE + Removing performSelectorOnMainThread seems to be better but I can’t be sure.  Just observed:
>
> (1) M-< at the mid of a buffer, but only the first line of the view is refreshed, and other parts were still there.
>
> (2) selecting a region doesn’t always clear the hl-line effect.

What are you doing to make your background translucent? I've never
seen anything nearly as bad as what you have. I've only seen a glitch
maybe once since the last patch (and that may have even been something
else). It makes me wonder if there's something else different/off
about your setup.

Aaron





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-09  2:47                                         ` Aaron Jensen
@ 2023-06-09  3:12                                           ` Kai Ma
  2023-06-09 18:27                                             ` Alan Third
  0 siblings, 1 reply; 71+ messages in thread
From: Kai Ma @ 2023-06-09  3:12 UTC (permalink / raw)
  To: Aaron Jensen; +Cc: Po Lu, Alan Third, Eli Zaretskii, 63187



> On Jun 9, 2023, at 10:47, Aaron Jensen <aaronjensen@gmail.com> wrote:
> 
> On Thu, Jun 8, 2023 at 10:42 PM Kai Ma <justksqsf@gmail.com> wrote:
>> 
>> Increasing CACHE_MAX_SIZE alone doesn’t seem to help much.
>> (Screencast: https://www.youtube.com/watch?v=9YD9jyP-GKw)
>> 
>> Increasing CACHE_MAX_SIZE + Removing performSelectorOnMainThread seems to be better but I can’t be sure.  Just observed:
>> 
>> (1) M-< at the mid of a buffer, but only the first line of the view is refreshed, and other parts were still there.
>> 
>> (2) selecting a region doesn’t always clear the hl-line effect.
> 
> What are you doing to make your background translucent? I've never
> seen anything nearly as bad as what you have. I've only seen a glitch
> maybe once since the last patch (and that may have even been something
> else). It makes me wonder if there's something else different/off
> about your setup.

(set-frame-parameter nil 'alpha 0.95)

Indeed I haven’t been able to reproduce this bug in emacs -q so far. I thought I didn’t do anything unconventional, but, well, polling-period seems to be the culprit.

I had in my config
  (setq polling-period 0.01)
to increase the responsiveness of C-g, and reverting the change to the default value 2.0 is effective.






^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-09  3:12                                           ` Kai Ma
@ 2023-06-09 18:27                                             ` Alan Third
  2023-06-09 18:46                                               ` Aaron Jensen
  0 siblings, 1 reply; 71+ messages in thread
From: Alan Third @ 2023-06-09 18:27 UTC (permalink / raw)
  To: Kai Ma; +Cc: Po Lu, 63187, Eli Zaretskii, Aaron Jensen

On Fri, Jun 09, 2023 at 11:12:47AM +0800, Kai Ma wrote:
> 
> 
> > On Jun 9, 2023, at 10:47, Aaron Jensen <aaronjensen@gmail.com> wrote:
> > 
> > On Thu, Jun 8, 2023 at 10:42 PM Kai Ma <justksqsf@gmail.com> wrote:
> >> 
> >> Increasing CACHE_MAX_SIZE alone doesn’t seem to help much.
> >> (Screencast: https://www.youtube.com/watch?v=9YD9jyP-GKw)
> >> 
> >> Increasing CACHE_MAX_SIZE + Removing performSelectorOnMainThread seems to be better but I can’t be sure.  Just observed:
> >> 
> >> (1) M-< at the mid of a buffer, but only the first line of the view is refreshed, and other parts were still there.
> >> 
> >> (2) selecting a region doesn’t always clear the hl-line effect.
> > 
> > What are you doing to make your background translucent? I've never
> > seen anything nearly as bad as what you have. I've only seen a glitch
> > maybe once since the last patch (and that may have even been something
> > else). It makes me wonder if there's something else different/off
> > about your setup.
> 
> (set-frame-parameter nil 'alpha 0.95)
> 
> Indeed I haven’t been able to reproduce this bug in emacs -q so far.
> I thought I didn’t do anything unconventional, but, well,
> polling-period seems to be the culprit.
> 
> I had in my config
>   (setq polling-period 0.01)
> to increase the responsiveness of C-g, and reverting the change to
> the default value 2.0 is effective.

Well, I have no idea what that actually means in terms of the display.

It seems to me that removing the call to performSelectorOnMainThread
should be done. That may even fix Aaron's original issue too, given
that I don't know why calling setNeedsDisplayInRect twice in a row
should help, especially given it's not actually used anywhere else in
the display code.

(And it should probably be [view setNeedsDisplay:YES] if it's needed
there at all.)

If tearing becomes a wider problem probably the best option would be
to actually wait for a surface to become free before taking it off the
cache, but... I dunno. I don't really know how we do that without just
having a loop polling continuously. Sleep for a few milliseconds each
time round the loop?

-- 
Alan Third





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-09 18:27                                             ` Alan Third
@ 2023-06-09 18:46                                               ` Aaron Jensen
  2023-06-09 20:00                                                 ` Alan Third
  0 siblings, 1 reply; 71+ messages in thread
From: Aaron Jensen @ 2023-06-09 18:46 UTC (permalink / raw)
  To: Alan Third, Kai Ma, Aaron Jensen, 63187, Eli Zaretskii, Po Lu

On Fri, Jun 9, 2023 at 2:27 PM Alan Third <alan@idiocy.org> wrote:
> It seems to me that removing the call to performSelectorOnMainThread
> should be done. That may even fix Aaron's original issue too, given
> that I don't know why calling setNeedsDisplayInRect twice in a row
> should help, especially given it's not actually used anywhere else in
> the display code.

How is it called twice? Does copyRect mark for redisplay?

Aaron





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-09 18:46                                               ` Aaron Jensen
@ 2023-06-09 20:00                                                 ` Alan Third
  2023-06-12 13:04                                                   ` Aaron Jensen
  0 siblings, 1 reply; 71+ messages in thread
From: Alan Third @ 2023-06-09 20:00 UTC (permalink / raw)
  To: Aaron Jensen; +Cc: Po Lu, Kai Ma, Eli Zaretskii, 63187

[-- Attachment #1: Type: text/plain, Size: 1882 bytes --]

On Fri, Jun 09, 2023 at 02:46:29PM -0400, Aaron Jensen wrote:
> On Fri, Jun 9, 2023 at 2:27 PM Alan Third <alan@idiocy.org> wrote:
> > It seems to me that removing the call to performSelectorOnMainThread
> > should be done. That may even fix Aaron's original issue too, given
> > that I don't know why calling setNeedsDisplayInRect twice in a row
> > should help, especially given it's not actually used anywhere else in
> > the display code.
> 
> How is it called twice? Does copyRect mark for redisplay?

Sorry, I had misunderstood your change.

Either way, I don't see how it's made a difference.
setNeedsDisplayInRect is telling the system which parts it needs to
call drawRect on, but we don't use drawRect any more, so I would think
all it can be doing is setting the needsDisplay boolean to true.

copyRect definitely doesn't do anything with the rectangle. It deals
with the bitmap's pixel data directly, so there's no clipping or
anything else affecting it and it's changes don't need to be
committed to some backing store.

Even when it comes to actually displaying the view on the screen, we
pass in the entire bitmap to the graphics subsystem and it
(supposedly) displays it in it's entirety.

So as I understand it the rectangle passed into setNeedsDisplayInRect
doesn't do anything. I think that call in ns_scroll_run was left there
by mistake. It's literally the only call to it in the entire nsterm.m
file.

But you report that it has fixed your problem. I can't explain that
because it runs counter to my understanding of how macOS draws.

But then again, none of this is documented in any in-depth way by
Apple, so who knows what's REALLY going on.

Patch attached, but it's untested. It may even make things worse. I'm
happy to leave it up to you to decide what to do since you're in a
better position to tell if any given change actually helps.
-- 
Alan Third

[-- Attachment #2: 0001-Reduce-graphical-glitches-in-certain-circumstances-o.patch --]
[-- Type: text/x-diff, Size: 1524 bytes --]

From b34cd84c1b070248b396d2ec82018be99b529d31 Mon Sep 17 00:00:00 2001
From: Alan Third <alan@idiocy.org>
Date: Fri, 9 Jun 2023 20:53:31 +0100
Subject: [PATCH] Reduce graphical glitches in certain circumstances on macOS
 (bug#63187)

* src/nsterm.m (ns_scroll_run): Change way we request the frame is
redrawn to the glass-we no longer invalidate regions.
([EmacsLayer display]): Get rid of this asynchronous call, it may be
causing unexpected glitches during rapid updates.
---
 src/nsterm.m | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/src/nsterm.m b/src/nsterm.m
index 3e089cc1ff1..673fdf31531 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -2708,8 +2708,9 @@ Hide the window (X11 semantics)
     EmacsView *view = FRAME_NS_VIEW (f);
 
     [view copyRect:srcRect to:dest];
-#ifdef NS_IMPL_COCOA
-    [view setNeedsDisplayInRect:destRect];
+#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MIN_REQUIRED >= 101400
+    /* I don't know if we even need this...  */
+    [view setNeedsDisplay:YES];
 #endif
   }
 
@@ -10633,12 +10634,6 @@ - (void) display
       /* 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];
     }
 }
 
-- 
2.39.1


^ permalink raw reply related	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-09 20:00                                                 ` Alan Third
@ 2023-06-12 13:04                                                   ` Aaron Jensen
  2023-06-16  2:17                                                     ` Aaron Jensen
  0 siblings, 1 reply; 71+ messages in thread
From: Aaron Jensen @ 2023-06-12 13:04 UTC (permalink / raw)
  To: Alan Third, Aaron Jensen, Kai Ma, 63187, Eli Zaretskii, Po Lu

On Fri, Jun 9, 2023 at 4:00 PM Alan Third <alan@idiocy.org> wrote:
>
> On Fri, Jun 09, 2023 at 02:46:29PM -0400, Aaron Jensen wrote:
> > On Fri, Jun 9, 2023 at 2:27 PM Alan Third <alan@idiocy.org> wrote:
> > > It seems to me that removing the call to performSelectorOnMainThread
> > > should be done. That may even fix Aaron's original issue too, given
> > > that I don't know why calling setNeedsDisplayInRect twice in a row
> > > should help, especially given it's not actually used anywhere else in
> > > the display code.
> >
> > How is it called twice? Does copyRect mark for redisplay?
>
> Sorry, I had misunderstood your change.
>
> Either way, I don't see how it's made a difference.
> setNeedsDisplayInRect is telling the system which parts it needs to
> call drawRect on, but we don't use drawRect any more, so I would think
> all it can be doing is setting the needsDisplay boolean to true.
>
> copyRect definitely doesn't do anything with the rectangle. It deals
> with the bitmap's pixel data directly, so there's no clipping or
> anything else affecting it and it's changes don't need to be
> committed to some backing store.
>
> Even when it comes to actually displaying the view on the screen, we
> pass in the entire bitmap to the graphics subsystem and it
> (supposedly) displays it in it's entirety.
>
> So as I understand it the rectangle passed into setNeedsDisplayInRect
> doesn't do anything. I think that call in ns_scroll_run was left there
> by mistake. It's literally the only call to it in the entire nsterm.m
> file.
>
> But you report that it has fixed your problem. I can't explain that
> because it runs counter to my understanding of how macOS draws.
>
> But then again, none of this is documented in any in-depth way by
> Apple, so who knows what's REALLY going on.
>
> Patch attached, but it's untested. It may even make things worse. I'm
> happy to leave it up to you to decide what to do since you're in a
> better position to tell if any given change actually helps.

Thanks, I'm trying it out now. I'll report back in a bit. If it's fine
I'll try removing the setNeedsDisplay as well and try again.

Aaron





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-12 13:04                                                   ` Aaron Jensen
@ 2023-06-16  2:17                                                     ` Aaron Jensen
  2023-06-19 15:46                                                       ` Aaron Jensen
  2023-06-23  8:48                                                       ` Alan Third
  0 siblings, 2 replies; 71+ messages in thread
From: Aaron Jensen @ 2023-06-16  2:17 UTC (permalink / raw)
  To: Alan Third, Aaron Jensen, Kai Ma, 63187, Eli Zaretskii, Po Lu

[-- Attachment #1: Type: text/plain, Size: 2766 bytes --]

On Mon, Jun 12, 2023 at 9:04 AM Aaron Jensen <aaronjensen@gmail.com> wrote:
>
> On Fri, Jun 9, 2023 at 4:00 PM Alan Third <alan@idiocy.org> wrote:
> >
> > On Fri, Jun 09, 2023 at 02:46:29PM -0400, Aaron Jensen wrote:
> > > On Fri, Jun 9, 2023 at 2:27 PM Alan Third <alan@idiocy.org> wrote:
> > > > It seems to me that removing the call to performSelectorOnMainThread
> > > > should be done. That may even fix Aaron's original issue too, given
> > > > that I don't know why calling setNeedsDisplayInRect twice in a row
> > > > should help, especially given it's not actually used anywhere else in
> > > > the display code.
> > >
> > > How is it called twice? Does copyRect mark for redisplay?
> >
> > Sorry, I had misunderstood your change.
> >
> > Either way, I don't see how it's made a difference.
> > setNeedsDisplayInRect is telling the system which parts it needs to
> > call drawRect on, but we don't use drawRect any more, so I would think
> > all it can be doing is setting the needsDisplay boolean to true.
> >
> > copyRect definitely doesn't do anything with the rectangle. It deals
> > with the bitmap's pixel data directly, so there's no clipping or
> > anything else affecting it and it's changes don't need to be
> > committed to some backing store.
> >
> > Even when it comes to actually displaying the view on the screen, we
> > pass in the entire bitmap to the graphics subsystem and it
> > (supposedly) displays it in it's entirety.
> >
> > So as I understand it the rectangle passed into setNeedsDisplayInRect
> > doesn't do anything. I think that call in ns_scroll_run was left there
> > by mistake. It's literally the only call to it in the entire nsterm.m
> > file.
> >
> > But you report that it has fixed your problem. I can't explain that
> > because it runs counter to my understanding of how macOS draws.
> >
> > But then again, none of this is documented in any in-depth way by
> > Apple, so who knows what's REALLY going on.
> >
> > Patch attached, but it's untested. It may even make things worse. I'm
> > happy to leave it up to you to decide what to do since you're in a
> > better position to tell if any given change actually helps.
>
> Thanks, I'm trying it out now. I'll report back in a bit. If it's fine
> I'll try removing the setNeedsDisplay as well and try again.

I saw a paint issue today. The "<" to the left of the indented (and
redacted) lines 65-68 was an artifact. It kept painting there even
while scrolling until I resized the window, then they all disappeared.
They appeared one at a time while scrolling, as if the painting of one
the one on line 63 was "fixed" in the window position as I was
scrolling (likely it just didn't get cleared as necessary).

[-- Attachment #2: CleanShot 2023-06-15 at 22.14.50@2x.png --]
[-- Type: image/png, Size: 80914 bytes --]

^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-16  2:17                                                     ` Aaron Jensen
@ 2023-06-19 15:46                                                       ` Aaron Jensen
  2023-06-24  4:17                                                         ` Kai Ma
  2023-06-23  8:48                                                       ` Alan Third
  1 sibling, 1 reply; 71+ messages in thread
From: Aaron Jensen @ 2023-06-19 15:46 UTC (permalink / raw)
  To: Alan Third, Aaron Jensen, Kai Ma, 63187, Eli Zaretskii, Po Lu

On Thu, Jun 15, 2023 at 10:17 PM Aaron Jensen <aaronjensen@gmail.com> wrote:
>
> On Mon, Jun 12, 2023 at 9:04 AM Aaron Jensen <aaronjensen@gmail.com> wrote:
> >
> > On Fri, Jun 9, 2023 at 4:00 PM Alan Third <alan@idiocy.org> wrote:
> > >
> > > On Fri, Jun 09, 2023 at 02:46:29PM -0400, Aaron Jensen wrote:
> > > > On Fri, Jun 9, 2023 at 2:27 PM Alan Third <alan@idiocy.org> wrote:
> > > > > It seems to me that removing the call to performSelectorOnMainThread
> > > > > should be done. That may even fix Aaron's original issue too, given
> > > > > that I don't know why calling setNeedsDisplayInRect twice in a row
> > > > > should help, especially given it's not actually used anywhere else in
> > > > > the display code.
> > > >
> > > > How is it called twice? Does copyRect mark for redisplay?
> > >
> > > Sorry, I had misunderstood your change.
> > >
> > > Either way, I don't see how it's made a difference.
> > > setNeedsDisplayInRect is telling the system which parts it needs to
> > > call drawRect on, but we don't use drawRect any more, so I would think
> > > all it can be doing is setting the needsDisplay boolean to true.
> > >
> > > copyRect definitely doesn't do anything with the rectangle. It deals
> > > with the bitmap's pixel data directly, so there's no clipping or
> > > anything else affecting it and it's changes don't need to be
> > > committed to some backing store.
> > >
> > > Even when it comes to actually displaying the view on the screen, we
> > > pass in the entire bitmap to the graphics subsystem and it
> > > (supposedly) displays it in it's entirety.
> > >
> > > So as I understand it the rectangle passed into setNeedsDisplayInRect
> > > doesn't do anything. I think that call in ns_scroll_run was left there
> > > by mistake. It's literally the only call to it in the entire nsterm.m
> > > file.
> > >
> > > But you report that it has fixed your problem. I can't explain that
> > > because it runs counter to my understanding of how macOS draws.
> > >
> > > But then again, none of this is documented in any in-depth way by
> > > Apple, so who knows what's REALLY going on.
> > >
> > > Patch attached, but it's untested. It may even make things worse. I'm
> > > happy to leave it up to you to decide what to do since you're in a
> > > better position to tell if any given change actually helps.
> >
> > Thanks, I'm trying it out now. I'll report back in a bit. If it's fine
> > I'll try removing the setNeedsDisplay as well and try again.
>
> I saw a paint issue today. The "<" to the left of the indented (and
> redacted) lines 65-68 was an artifact. It kept painting there even
> while scrolling until I resized the window, then they all disappeared.
> They appeared one at a time while scrolling, as if the painting of one
> the one on line 63 was "fixed" in the window position as I was
> scrolling (likely it just didn't get cleared as necessary).

Kai, could you try this patch out. It's a total guess, but let me know
if it does any better for you.

diff --git a/src/nsterm.h b/src/nsterm.h
index b6e5a813a6d..4f6c6f7c28b 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -1384,3 +1384,11 @@ #define NSButtonTypeMomentaryPushIn
NSMomentaryPushInButton
 extern void mark_nsterm (void);

 #endif /* HAVE_NS */
+
+#define AJTRACE(...)                                          \
+  do                                                                        \
+    {                                                                       \
+        fprintf (stderr, __VA_ARGS__);                                    \
+        putc ('\n', stderr);     \
+    }                                                                       \
+  while(0)
diff --git a/src/nsterm.m b/src/nsterm.m
index 3e089cc1ff1..5a92f4cda0b 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -2708,9 +2708,9 @@ Hide the window (X11 semantics)
     EmacsView *view = FRAME_NS_VIEW (f);

     [view copyRect:srcRect to:dest];
-#ifdef NS_IMPL_COCOA
-    [view setNeedsDisplayInRect:destRect];
-#endif
+// #ifdef NS_IMPL_COCOA
+//     [view setNeedsDisplayInRect:destRect];
+// #endif
   }

   unblock_input ();
@@ -10636,9 +10636,9 @@ - (void) display

       /* 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];
+      // [self performSelectorOnMainThread:@selector (getContext)
+      //                        withObject:nil
+      //                     waitUntilDone:NO];
     }
 }

@@ -10651,6 +10651,7 @@ - (void) copyContentsTo: (IOSurfaceRef) destination
   IOReturn lockStatus;
   IOSurfaceRef source = (IOSurfaceRef)[self contents];
   void *sourceData, *destinationData;
+  int seed1 = 0, seed2 = 1;
   int numBytes = IOSurfaceGetAllocSize (destination);

   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "[EmacsLayer copyContentsTo:]");
@@ -10662,14 +10663,31 @@ - (void) copyContentsTo: (IOSurfaceRef) destination
   if (lockStatus != kIOReturnSuccess)
     NSLog (@"Failed to lock source surface: %x", lockStatus);

+  lockStatus = IOSurfaceLock (destination, kIOSurfaceLockAvoidSync, nil);
+  if (lockStatus != kIOReturnSuccess)
+    NSLog (@"Failed to lock destination surface: %x", lockStatus);
+
   sourceData = IOSurfaceGetBaseAddress (source);
   destinationData = IOSurfaceGetBaseAddress (destination);

-  /* Since every IOSurface should have the exact same settings, a
-     memcpy seems like the fastest way to copy the data from one to
-     the other.  */
-  memcpy (destinationData, sourceData, numBytes);
+  while (seed1 != seed2)
+    {
+      seed1 = IOSurfaceGetSeed (source);
+
+      /* Since every IOSurface should have the exact same settings, a
+        memcpy seems like the fastest way to copy the data from one to
+        the other.  */
+      memcpy (destinationData, sourceData, numBytes);

+      seed2 = IOSurfaceGetSeed (source);
+      if (seed1 != seed2) {
+        AJTRACE ("SEED DO NOT MATCH");
+      }
+    }
+
+  lockStatus = IOSurfaceUnlock (destination, kIOSurfaceLockAvoidSync, nil);
+  if (lockStatus != kIOReturnSuccess)
+    NSLog (@"Failed to unlock destination surface: %x", lockStatus);
   lockStatus = IOSurfaceUnlock (source, kIOSurfaceLockReadOnly, nil);
   if (lockStatus != kIOReturnSuccess)
     NSLog (@"Failed to unlock source surface: %x", lockStatus);





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-16  2:17                                                     ` Aaron Jensen
  2023-06-19 15:46                                                       ` Aaron Jensen
@ 2023-06-23  8:48                                                       ` Alan Third
  2023-06-23 11:54                                                         ` Aaron Jensen
  1 sibling, 1 reply; 71+ messages in thread
From: Alan Third @ 2023-06-23  8:48 UTC (permalink / raw)
  To: Aaron Jensen; +Cc: Po Lu, Kai Ma, Eli Zaretskii, 63187

On Thu, Jun 15, 2023 at 10:17:11PM -0400, Aaron Jensen wrote:
> 
> I saw a paint issue today. The "<" to the left of the indented (and
> redacted) lines 65-68 was an artifact. It kept painting there even
> while scrolling until I resized the window, then they all disappeared.
> They appeared one at a time while scrolling, as if the painting of one
> the one on line 63 was "fixed" in the window position as I was
> scrolling (likely it just didn't get cleared as necessary).

It could be worth forcing the system to display when we want it to,
rather than leaving it to decide itself... I don't think this will
make any difference, but perhaps it's worth a shot.

modified   src/nsterm.m
@@ -1089,6 +1089,8 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
   [view unlockFocus];
 #if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400
   [[view window] flushWindow];
+#else
+  [view display];
 #endif
 
   unblock_input ();

This feels to me like things are happening out of order or
simultaneously, but I don't really see how that could be happening.
The drawing system throws out errors if you try to use it from sub
threads, so it should be obvious if there was some multi-threading
issue...

-- 
Alan Third





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-23  8:48                                                       ` Alan Third
@ 2023-06-23 11:54                                                         ` Aaron Jensen
  0 siblings, 0 replies; 71+ messages in thread
From: Aaron Jensen @ 2023-06-23 11:54 UTC (permalink / raw)
  To: Alan Third, Aaron Jensen, Kai Ma, 63187, Eli Zaretskii, Po Lu

On Fri, Jun 23, 2023 at 4:48 AM Alan Third <alan@idiocy.org> wrote:
>
> On Thu, Jun 15, 2023 at 10:17:11PM -0400, Aaron Jensen wrote:
> >
> > I saw a paint issue today. The "<" to the left of the indented (and
> > redacted) lines 65-68 was an artifact. It kept painting there even
> > while scrolling until I resized the window, then they all disappeared.
> > They appeared one at a time while scrolling, as if the painting of one
> > the one on line 63 was "fixed" in the window position as I was
> > scrolling (likely it just didn't get cleared as necessary).
>
> It could be worth forcing the system to display when we want it to,
> rather than leaving it to decide itself... I don't think this will
> make any difference, but perhaps it's worth a shot.
>
> modified   src/nsterm.m
> @@ -1089,6 +1089,8 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
>    [view unlockFocus];
>  #if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400
>    [[view window] flushWindow];
> +#else
> +  [view display];
>  #endif
>
>    unblock_input ();
>
> This feels to me like things are happening out of order or
> simultaneously, but I don't really see how that could be happening.
> The drawing system throws out errors if you try to use it from sub
> threads, so it should be obvious if there was some multi-threading
> issue...

I'll try that in a bit, thanks. One interesting thing is that just
yesterday I saw this crash for the first time (with the patch I
recently posted):

Crashed Thread:        0  Dispatch queue: com.apple.main-thread

Exception Type:        EXC_BAD_ACCESS (SIGABRT)
Exception Codes:       KERN_INVALID_ADDRESS at 0x00000000000000c0
Exception Codes:       0x0000000000000001, 0x00000000000000c0

VM Region Info: 0xc0 is not in any region.  Bytes before following
region: 105553518919488
      REGION TYPE                    START - END         [ VSIZE]
PRT/MAX SHRMOD  REGION DETAIL
      UNUSED SPACE AT START
--->
      MALLOC_NANO (reserved)   600018000000-600020000000 [128.0M]
rw-/rwx SM=NUL  ...(unallocated)

Thread 0 Crashed::  Dispatch queue: com.apple.main-thread
0   libsystem_kernel.dylib               0x191db4724 __pthread_kill + 8
1   libsystem_pthread.dylib               0x191debc28 pthread_kill + 288
2   libsystem_c.dylib                     0x191cc246c raise + 32
3   emacs                                 0x1046488c8
terminate_due_to_signal + 212 (emacs.c:464)
4   emacs                                 0x104649128 emacs_abort + 20
(sysdep.c:2320)
5   emacs                                 0x104605ad4 ns_term_shutdown
+ 144 (nsterm.m:5770)
6   emacs                                 0x1044cdcdc shut_down_emacs
+ 332 (emacs.c:3017)
7   emacs                                 0x104648890
terminate_due_to_signal + 156 (emacs.c:447)
8   emacs                                 0x1044f1a20
handle_fatal_signal + 12 (sysdep.c:1783) [inlined]
9   emacs                                 0x1044f1a20
deliver_thread_signal + 112 (sysdep.c:1775) [inlined]
10  emacs                                 0x1044f1a20
deliver_fatal_thread_signal + 128 (sysdep.c:1795)
11  emacs                                 0x1044f38e0 handle_sigsegv +
64 (sysdep.c:1888)
12  libsystem_platform.dylib             0x191e1aa24 _sigtramp + 56
13  ???                            0xffff800104607dc4 ???
14  AppKit                               0x19569b8d0
-[_NSTrackingAreaAKViewHelper
updateTrackingAreasWithInvalidCursorRects:] + 284
15  AppKit                               0x1958a8964
_NSViewSubViewMutationSafeApply + 220
16  AppKit                               0x19569b974
-[_NSTrackingAreaAKViewHelper
updateTrackingAreasWithInvalidCursorRects:] + 448
17  AppKit                               0x1958a8964
_NSViewSubViewMutationSafeApply + 220
18  AppKit                               0x19569b974
-[_NSTrackingAreaAKViewHelper
updateTrackingAreasWithInvalidCursorRects:] + 448
19  AppKit                               0x195699cb4
-[_NSTrackingAreaAKManager displayCycleUpdateStructuralRegions] + 176
20  AppKit                               0x195195658
__NSWindowGetDisplayCycleObserverForUpdateStructuralRegions_block_invoke
+ 364
21  AppKit                               0x195190c30
NSDisplayCycleObserverInvoke + 168
22  AppKit                               0x19519088c NSDisplayCycleFlush + 644
23  QuartzCore                           0x1993adce4
CA::Transaction::run_commit_handlers(CATransactionPhase) + 120
24  QuartzCore                           0x1993acaa0
CA::Transaction::commit() + 320
25  AppKit                               0x195212c7c
__62+[CATransaction(NSCATransaction)
NS_setFlushesWithDisplayLink]_block_invoke + 272
26  AppKit                               0x1958eef7c
___NSRunLoopObserverCreateWithHandler_block_invoke + 64
27  CoreFoundation                       0x191ec99f0
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 36
28  CoreFoundation                       0x191ec98dc
__CFRunLoopDoObservers + 532
29  CoreFoundation                       0x191ec8f14 __CFRunLoopRun + 776
30  CoreFoundation                       0x191ec84b8 CFRunLoopRunSpecific + 612
31  HIToolbox                             0x19b712c40
RunCurrentEventLoopInMode + 292
32  HIToolbox                             0x19b7128d0
ReceiveNextEventCommon + 220
33  HIToolbox                             0x19b7127d4
_BlockUntilNextEventMatchingListInModeWithFilter + 76
34  AppKit                               0x1950e9d44 _DPSNextEvent + 636
35  AppKit                               0x1950e8ee0
-[NSApplication(NSEvent)
_nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 716
36  AppKit                               0x1950dd344 -[NSApplication run] + 464
37  emacs                                 0x104605c24 -[EmacsApp run]
+ 264 (nsterm.m:5823)
38  emacs                                 0x10461842c ns_read_socket_1
+ 560 (nsterm.m:4703)
39  emacs                                 0x10461602c ns_flush_display
+ 44 (nsterm.m:5311)
40  emacs                                 0x104428a04 flush_frame + 32
(frame.h:1760) [inlined]
41  emacs                                 0x104428a04
echo_area_display + 1080 (xdisp.c:13203)
42  emacs                                 0x1044284d8 message3_nolog +
548 (xdisp.c:12104)
43  emacs                                 0x104428078 message3 + 132
(xdisp.c:12034)
44  emacs                                 0x10455456c Fmessage + 68
(editfns.c:3192)
45  emacs                                 0x10455ca4c Ffuncall + 396
(eval.c:3008)
46  emacs                                 0x10455f750 Fapply + 996 (eval.c:2679)
47  emacs                                 0x10455ca4c Ffuncall + 396
(eval.c:3008)
48  subr--trampoline-6d657373616765_message_0.eln        0x1196f7f20
F616e6f6e796d6f75732d6c616d626461_anonymous_lambda_0 + 88
49  magit-process-0a318d45-3f4ff10f.eln        0x128a6262c
F6d616769742d72756e2d6769742d6173796e63_magit_run_git_async_0 + 220
50  emacs                                 0x10455ca4c Ffuncall + 396
(eval.c:3008)
51  magit-fetch-8acc7b48-029daf61.eln        0x12acf664c
F6d616769742d6769742d6665746368_magit_git_fetch_0 + 104
52  emacs                                 0x10455ca4c Ffuncall + 396
(eval.c:3008)
53  magit-fetch-8acc7b48-029daf61.eln        0x12acf6abc
F6d616769742d66657463682d616c6c_magit_fetch_all_0 + 76
54  emacs                                 0x10455ca4c Ffuncall + 396
(eval.c:3008)
55  emacs                                 0x1045a8a0c exec_byte_code +
3236 (bytecode.c:809)
56  emacs                                 0x10455ca4c Ffuncall + 396
(eval.c:3008)
57  emacs                                 0x10455a760 eval_sub + 2356
(eval.c:2483)
58  emacs                                 0x104560e50 Fprogn + 28
(eval.c:436) [inlined]
59  emacs                                 0x104560e50 funcall_lambda +
1356 (eval.c:3246)
60  emacs                                 0x10455ca4c Ffuncall + 396
(eval.c:3008)
61  emacs                                 0x1045a8a0c exec_byte_code +
3236 (bytecode.c:809)
62  emacs                                 0x10455ca4c Ffuncall + 396
(eval.c:3008)
63  emacs                                 0x104557b14
Ffuncall_interactively + 68 (callint.c:250)
64  emacs                                 0x10455ca4c Ffuncall + 396
(eval.c:3008)
65  emacs                                 0x104559000
Fcall_interactively + 5332 (callint.c:342)
66  simple-fab5b0cf-e1c8f2a9.eln         0x107dd4efc
F636f6d6d616e642d65786563757465_command_execute_0 + 652
67  emacs                                 0x10455ca4c Ffuncall + 396
(eval.c:3008)
68  emacs                                 0x1044d1bbc call1 + 20
(lisp.h:3241) [inlined]
69  emacs                                 0x1044d1bbc command_loop_1 +
1384 (keyboard.c:1504)
70  emacs                                 0x10455d7fc
internal_condition_case + 96 (eval.c:1486)
71  emacs                                 0x1044d1640 command_loop_2 +
52 (keyboard.c:1133)
72  emacs                                 0x10455d09c internal_catch +
88 (eval.c:1209)
73  emacs                                 0x104648d1c
command_loop.cold.1 + 80 (keyboard.c:1111)
74  emacs                                 0x1044d0d74 command_loop +
156 (keyboard.c:1110)
75  emacs                                 0x1044d0c2c recursive_edit_1
+ 152 (keyboard.c:720)
76  emacs                                 0x1044d0fe0 Frecursive_edit
+ 372 (keyboard.c:803)
77  emacs                                 0x1044cfdb4 main + 8324 (emacs.c:2530)
78  dyld                                 0x191a93f28 start + 2236





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-19 15:46                                                       ` Aaron Jensen
@ 2023-06-24  4:17                                                         ` Kai Ma
  2023-06-24 13:34                                                           ` Aaron Jensen
  0 siblings, 1 reply; 71+ messages in thread
From: Kai Ma @ 2023-06-24  4:17 UTC (permalink / raw)
  To: Aaron Jensen; +Cc: Po Lu, Alan Third, Eli Zaretskii, 63187

[-- Attachment #1: Type: text/plain, Size: 4156 bytes --]



> On Jun 19, 2023, at 23:46, Aaron Jensen <aaronjensen@gmail.com> wrote:
> 
> Kai, could you try this patch out. It's a total guess, but let me know
> if it does any better for you.

Thanks. I have been running this for several days.  It does not fix the problem completely, but it’s possible to set polling-period to a very small value now.

> 
> diff --git a/src/nsterm.h b/src/nsterm.h
> index b6e5a813a6d..4f6c6f7c28b 100644
> --- a/src/nsterm.h
> +++ b/src/nsterm.h
> @@ -1384,3 +1384,11 @@ #define NSButtonTypeMomentaryPushIn
> NSMomentaryPushInButton
> extern void mark_nsterm (void);
> 
> #endif /* HAVE_NS */
> +
> +#define AJTRACE(...)                                          \
> +  do                                                                      \
> +    {                                                                     \
> +        fprintf (stderr, __VA_ARGS__);                                    \
> +        putc ('\n', stderr);     \
> +    }                                                                     \
> +  while(0)
> diff --git a/src/nsterm.m b/src/nsterm.m
> index 3e089cc1ff1..5a92f4cda0b 100644
> --- a/src/nsterm.m
> +++ b/src/nsterm.m
> @@ -2708,9 +2708,9 @@ Hide the window (X11 semantics)
>     EmacsView *view = FRAME_NS_VIEW (f);
> 
>     [view copyRect:srcRect to:dest];
> -#ifdef NS_IMPL_COCOA
> -    [view setNeedsDisplayInRect:destRect];
> -#endif
> +// #ifdef NS_IMPL_COCOA
> +//     [view setNeedsDisplayInRect:destRect];
> +// #endif
>   }
> 
>   unblock_input ();
> @@ -10636,9 +10636,9 @@ - (void) display
> 
>       /* 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];
> +      // [self performSelectorOnMainThread:@selector (getContext)
> +      //                        withObject:nil
> +      //                     waitUntilDone:NO];
>     }
> }
> 
> @@ -10651,6 +10651,7 @@ - (void) copyContentsTo: (IOSurfaceRef) destination
>   IOReturn lockStatus;
>   IOSurfaceRef source = (IOSurfaceRef)[self contents];
>   void *sourceData, *destinationData;
> +  int seed1 = 0, seed2 = 1;
>   int numBytes = IOSurfaceGetAllocSize (destination);
> 
>   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "[EmacsLayer copyContentsTo:]");
> @@ -10662,14 +10663,31 @@ - (void) copyContentsTo: (IOSurfaceRef) destination
>   if (lockStatus != kIOReturnSuccess)
>     NSLog (@"Failed to lock source surface: %x", lockStatus);
> 
> +  lockStatus = IOSurfaceLock (destination, kIOSurfaceLockAvoidSync, nil);
> +  if (lockStatus != kIOReturnSuccess)
> +    NSLog (@"Failed to lock destination surface: %x", lockStatus);
> +
>   sourceData = IOSurfaceGetBaseAddress (source);
>   destinationData = IOSurfaceGetBaseAddress (destination);
> 
> -  /* Since every IOSurface should have the exact same settings, a
> -     memcpy seems like the fastest way to copy the data from one to
> -     the other.  */
> -  memcpy (destinationData, sourceData, numBytes);
> +  while (seed1 != seed2)
> +    {
> +      seed1 = IOSurfaceGetSeed (source);
> +
> +      /* Since every IOSurface should have the exact same settings, a
> +        memcpy seems like the fastest way to copy the data from one to
> +        the other.  */
> +      memcpy (destinationData, sourceData, numBytes);
> 
> +      seed2 = IOSurfaceGetSeed (source);
> +      if (seed1 != seed2) {
> +        AJTRACE ("SEED DO NOT MATCH");

I haven't seen this message so far. So probably it is removing performSelectorOnMainThread that is effective.

> +      }
> +    }
> +
> +  lockStatus = IOSurfaceUnlock (destination, kIOSurfaceLockAvoidSync, nil);
> +  if (lockStatus != kIOReturnSuccess)
> +    NSLog (@"Failed to unlock destination surface: %x", lockStatus);
>   lockStatus = IOSurfaceUnlock (source, kIOSurfaceLockReadOnly, nil);
>   if (lockStatus != kIOReturnSuccess)
>     NSLog (@"Failed to unlock source surface: %x", lockStatus);


[-- Attachment #2: Type: text/html, Size: 68938 bytes --]

^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-24  4:17                                                         ` Kai Ma
@ 2023-06-24 13:34                                                           ` Aaron Jensen
  2023-06-24 14:14                                                             ` Alan Third
  0 siblings, 1 reply; 71+ messages in thread
From: Aaron Jensen @ 2023-06-24 13:34 UTC (permalink / raw)
  To: Kai Ma; +Cc: Po Lu, Alan Third, Eli Zaretskii, 63187

On Sat, Jun 24, 2023 at 12:18 AM Kai Ma <justksqsf@gmail.com> wrote:
>
>
>
> On Jun 19, 2023, at 23:46, Aaron Jensen <aaronjensen@gmail.com> wrote:
>
> Kai, could you try this patch out. It's a total guess, but let me know
> if it does any better for you.
>
>
> Thanks. I have been running this for several days.  It does not fix the problem completely, but it’s possible to set polling-period to a very small value now.

Hmm, do you see any of the artifacts w/o changing the polling period?

> diff --git a/src/nsterm.h b/src/nsterm.h
> index b6e5a813a6d..4f6c6f7c28b 100644
> --- a/src/nsterm.h
> +++ b/src/nsterm.h
> @@ -1384,3 +1384,11 @@ #define NSButtonTypeMomentaryPushIn
> NSMomentaryPushInButton
> extern void mark_nsterm (void);
>
> #endif /* HAVE_NS */
> +
> +#define AJTRACE(...)                                          \
> +  do                                                                      \
> +    {                                                                     \
> +        fprintf (stderr, __VA_ARGS__);                                    \
> +        putc ('\n', stderr);     \
> +    }                                                                     \
> +  while(0)
> diff --git a/src/nsterm.m b/src/nsterm.m
> index 3e089cc1ff1..5a92f4cda0b 100644
> --- a/src/nsterm.m
> +++ b/src/nsterm.m
> @@ -2708,9 +2708,9 @@ Hide the window (X11 semantics)
>     EmacsView *view = FRAME_NS_VIEW (f);
>
>     [view copyRect:srcRect to:dest];
> -#ifdef NS_IMPL_COCOA
> -    [view setNeedsDisplayInRect:destRect];
> -#endif
> +// #ifdef NS_IMPL_COCOA
> +//     [view setNeedsDisplayInRect:destRect];
> +// #endif
>
>   }
>
>   unblock_input ();
> @@ -10636,9 +10636,9 @@ - (void) display
>
>       /* 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];
> +      // [self performSelectorOnMainThread:@selector (getContext)
> +      //                        withObject:nil
> +      //                     waitUntilDone:NO];
>
>     }
> }
>
> @@ -10651,6 +10651,7 @@ - (void) copyContentsTo: (IOSurfaceRef) destination
>   IOReturn lockStatus;
>   IOSurfaceRef source = (IOSurfaceRef)[self contents];
>   void *sourceData, *destinationData;
> +  int seed1 = 0, seed2 = 1;
>   int numBytes = IOSurfaceGetAllocSize (destination);
>
>   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "[EmacsLayer copyContentsTo:]");
> @@ -10662,14 +10663,31 @@ - (void) copyContentsTo: (IOSurfaceRef) destination
>   if (lockStatus != kIOReturnSuccess)
>     NSLog (@"Failed to lock source surface: %x", lockStatus);
>
> +  lockStatus = IOSurfaceLock (destination, kIOSurfaceLockAvoidSync, nil);
> +  if (lockStatus != kIOReturnSuccess)
> +    NSLog (@"Failed to lock destination surface: %x", lockStatus);
> +
>   sourceData = IOSurfaceGetBaseAddress (source);
>   destinationData = IOSurfaceGetBaseAddress (destination);
>
> -  /* Since every IOSurface should have the exact same settings, a
> -     memcpy seems like the fastest way to copy the data from one to
> -     the other.  */
> -  memcpy (destinationData, sourceData, numBytes);
> +  while (seed1 != seed2)
> +    {
> +      seed1 = IOSurfaceGetSeed (source);
> +
> +      /* Since every IOSurface should have the exact same settings, a
> +        memcpy seems like the fastest way to copy the data from one to
> +        the other.  */
> +      memcpy (destinationData, sourceData, numBytes);
>
> +      seed2 = IOSurfaceGetSeed (source);
> +      if (seed1 != seed2) {
> +        AJTRACE ("SEED DO NOT MATCH");
>
>
> I haven't seen this message so far. So probably it is removing performSelectorOnMainThread that is effective.

Could you try removing the destination lock as well and see if that
impacts anything? From what I can tell, locking the destination may be
a good idea, but I'm curious if Alan has any thoughts as to why it'd
be a bad idea.

Thanks,

Aaron





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-24 13:34                                                           ` Aaron Jensen
@ 2023-06-24 14:14                                                             ` Alan Third
  2023-06-24 14:52                                                               ` Aaron Jensen
  0 siblings, 1 reply; 71+ messages in thread
From: Alan Third @ 2023-06-24 14:14 UTC (permalink / raw)
  To: Aaron Jensen; +Cc: Po Lu, Kai Ma, Eli Zaretskii, 63187

On Sat, Jun 24, 2023 at 09:34:18AM -0400, Aaron Jensen wrote:
> 
> Could you try removing the destination lock as well and see if that
> impacts anything? From what I can tell, locking the destination may be
> a good idea, but I'm curious if Alan has any thoughts as to why it'd
> be a bad idea.

copyContentsTo is only called by getContext, which has already locked
the destination, so there's no need to lock it again.

As I recall locking is really just setting a flag saying it's
currently being used so nobody else should touch it, it doesn't stop
you from doing things with it.

I know, for example, that it's possible to write to a surface that's
been locked by the transfer to VRAM, and that results in tearing
effects where the copy in VRAM is half updated. The VRAM copy isn't
ever copied back down to system RAM, though, so it doesn't have any
permanent consequences beyond a tearing effect at that particular
moment.
-- 
Alan Third





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-24 14:14                                                             ` Alan Third
@ 2023-06-24 14:52                                                               ` Aaron Jensen
  2023-06-24 15:08                                                                 ` Eli Zaretskii
  2023-06-24 15:41                                                                 ` Alan Third
  0 siblings, 2 replies; 71+ messages in thread
From: Aaron Jensen @ 2023-06-24 14:52 UTC (permalink / raw)
  To: Alan Third, Aaron Jensen, Kai Ma, 63187, Eli Zaretskii, Po Lu

On Sat, Jun 24, 2023 at 10:14 AM Alan Third <alan@idiocy.org> wrote:
>
> On Sat, Jun 24, 2023 at 09:34:18AM -0400, Aaron Jensen wrote:
> >
> > Could you try removing the destination lock as well and see if that
> > impacts anything? From what I can tell, locking the destination may be
> > a good idea, but I'm curious if Alan has any thoughts as to why it'd
> > be a bad idea.
>
> copyContentsTo is only called by getContext, which has already locked
> the destination, so there's no need to lock it again.

Ah, I see. Is the kIOSurfaceLockAvoidSync flag valuable for any reason?

> As I recall locking is really just setting a flag saying it's
> currently being used so nobody else should touch it, it doesn't stop
> you from doing things with it.
>
> I know, for example, that it's possible to write to a surface that's
> been locked by the transfer to VRAM, and that results in tearing
> effects where the copy in VRAM is half updated. The VRAM copy isn't
> ever copied back down to system RAM, though, so it doesn't have any
> permanent consequences beyond a tearing effect at that particular
> moment.

If I recall correctly, there's some code in Emacs that optimizes which
areas of the screen glyphs are drawn to. Maybe it remembers what was
the background color already and doesn't clear it again... I don't
remember where I saw it, but I think it was outside of nsterm. Does
that ring a bell? I'm thinking about how this manifests. For me, it's
always whole characters that are painted, they are always painted in
what would otherwise be whitespace, and they tend to get "copied" to
the next line in the whitespace as scrolling happens. In other words,
it doesn't just seem like a fluke write during the transfer to VRAM.
It seems like something in the engine is writing them, that the state
is getting "stuck" somehow. Does any of that ring a bell/jog anything?

Aaron





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-24 14:52                                                               ` Aaron Jensen
@ 2023-06-24 15:08                                                                 ` Eli Zaretskii
  2023-06-24 15:41                                                                 ` Alan Third
  1 sibling, 0 replies; 71+ messages in thread
From: Eli Zaretskii @ 2023-06-24 15:08 UTC (permalink / raw)
  To: Aaron Jensen; +Cc: luangruo, alan, 63187, justksqsf, aaronjensen

> From: Aaron Jensen <aaronjensen@gmail.com>
> Date: Sat, 24 Jun 2023 10:52:08 -0400
> 
> If I recall correctly, there's some code in Emacs that optimizes which
> areas of the screen glyphs are drawn to. Maybe it remembers what was
> the background color already and doesn't clear it again... I don't
> remember where I saw it, but I think it was outside of nsterm. Does
> that ring a bell? I'm thinking about how this manifests. For me, it's
> always whole characters that are painted, they are always painted in
> what would otherwise be whitespace, and they tend to get "copied" to
> the next line in the whitespace as scrolling happens. In other words,
> it doesn't just seem like a fluke write during the transfer to VRAM.
> It seems like something in the engine is writing them, that the state
> is getting "stuck" somehow. Does any of that ring a bell/jog anything?

If you are talking about the frame's scroll_run_hook, then this is
also called by xdisp.c as part of some redisplay optimizations.





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-24 14:52                                                               ` Aaron Jensen
  2023-06-24 15:08                                                                 ` Eli Zaretskii
@ 2023-06-24 15:41                                                                 ` Alan Third
  2023-06-24 16:05                                                                   ` Aaron Jensen
  1 sibling, 1 reply; 71+ messages in thread
From: Alan Third @ 2023-06-24 15:41 UTC (permalink / raw)
  To: Aaron Jensen; +Cc: Po Lu, Kai Ma, Eli Zaretskii, 63187

On Sat, Jun 24, 2023 at 10:52:08AM -0400, Aaron Jensen wrote:
> On Sat, Jun 24, 2023 at 10:14 AM Alan Third <alan@idiocy.org> wrote:
> >
> > On Sat, Jun 24, 2023 at 09:34:18AM -0400, Aaron Jensen wrote:
> > >
> > > Could you try removing the destination lock as well and see if that
> > > impacts anything? From what I can tell, locking the destination may be
> > > a good idea, but I'm curious if Alan has any thoughts as to why it'd
> > > be a bad idea.
> >
> > copyContentsTo is only called by getContext, which has already locked
> > the destination, so there's no need to lock it again.
> 
> Ah, I see. Is the kIOSurfaceLockAvoidSync flag valuable for any reason?

I don't think so... Not in our use-case. IIRC it's possible to get the
GPU to perform actions on the buffer once it's in VRAM. We don't do
that, so we don't need to ever worry about write-backs to system RAM.

I think.

> If I recall correctly, there's some code in Emacs that optimizes which
> areas of the screen glyphs are drawn to. Maybe it remembers what was
> the background color already and doesn't clear it again... I don't
> remember where I saw it, but I think it was outside of nsterm. Does
> that ring a bell? I'm thinking about how this manifests. For me, it's
> always whole characters that are painted, they are always painted in
> what would otherwise be whitespace, and they tend to get "copied" to
> the next line in the whitespace as scrolling happens. In other words,
> it doesn't just seem like a fluke write during the transfer to VRAM.
> It seems like something in the engine is writing them, that the state
> is getting "stuck" somehow. Does any of that ring a bell/jog anything?

Its quite possible. I did say before in the thread that it seems quite
possible to me that something isn't clearing the whitespace correctly.
But it's obviously rare, and I would expect that it's some piece of NS
port code rather than somewhere else.

Unless there's something that's #ifdef'd out because at some point in
the past the NS port has behaved differently...

But more likely if this is what's going on then it's going to be a bug
in the NS port. Unfortunately I don't really understand how the glyph
drawing side works, and never did.

But if that's the case, why would removing the asynchronous call to
getContext fix so many problems?

Something perhaps worth trying... Since removing the asynchronous call
to getContext fixes the problems, perhaps we need to think about the
"lazy" way we get the next buffer when the current one is displayed.
At the moment it just forgets about it until we want to draw to the
screen, at which point we call getContext and it creates the buffer if
necessary and copies the old one to the new one.

Maybe we should get the new buffer and do the copy when we set the
current buffer for display...

IIRC I avoided that because there isn't always time for the buffer to
have been sent to VRAM and unlocked before the *next* call to display,
so I wanted to leave it as long as possible between display and
getting the next buffer, but maybe this is just the wrong way to do
it.

So I suppose putting a call to getContext right after "currentSurface
== NULL" in display might be a quick and dirty way to test that.

-- 
Alan Third





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-24 15:41                                                                 ` Alan Third
@ 2023-06-24 16:05                                                                   ` Aaron Jensen
  2023-06-24 21:29                                                                     ` Alan Third
  0 siblings, 1 reply; 71+ messages in thread
From: Aaron Jensen @ 2023-06-24 16:05 UTC (permalink / raw)
  To: Alan Third, Aaron Jensen, Kai Ma, 63187, Eli Zaretskii, Po Lu

On Sat, Jun 24, 2023 at 11:41 AM Alan Third <alan@idiocy.org> wrote:
>
> On Sat, Jun 24, 2023 at 10:52:08AM -0400, Aaron Jensen wrote:
> > On Sat, Jun 24, 2023 at 10:14 AM Alan Third <alan@idiocy.org> wrote:
> > >
> > > On Sat, Jun 24, 2023 at 09:34:18AM -0400, Aaron Jensen wrote:
> > > >
> > > > Could you try removing the destination lock as well and see if that
> > > > impacts anything? From what I can tell, locking the destination may be
> > > > a good idea, but I'm curious if Alan has any thoughts as to why it'd
> > > > be a bad idea.
> > >
> > > copyContentsTo is only called by getContext, which has already locked
> > > the destination, so there's no need to lock it again.
> >
> > Ah, I see. Is the kIOSurfaceLockAvoidSync flag valuable for any reason?
>
> I don't think so... Not in our use-case. IIRC it's possible to get the
> GPU to perform actions on the buffer once it's in VRAM. We don't do
> that, so we don't need to ever worry about write-backs to system RAM.
>
> I think.
>
> > If I recall correctly, there's some code in Emacs that optimizes which
> > areas of the screen glyphs are drawn to. Maybe it remembers what was
> > the background color already and doesn't clear it again... I don't
> > remember where I saw it, but I think it was outside of nsterm. Does
> > that ring a bell? I'm thinking about how this manifests. For me, it's
> > always whole characters that are painted, they are always painted in
> > what would otherwise be whitespace, and they tend to get "copied" to
> > the next line in the whitespace as scrolling happens. In other words,
> > it doesn't just seem like a fluke write during the transfer to VRAM.
> > It seems like something in the engine is writing them, that the state
> > is getting "stuck" somehow. Does any of that ring a bell/jog anything?
>
> Its quite possible. I did say before in the thread that it seems quite
> possible to me that something isn't clearing the whitespace correctly.
> But it's obviously rare, and I would expect that it's some piece of NS
> port code rather than somewhere else.
>
> Unless there's something that's #ifdef'd out because at some point in
> the past the NS port has behaved differently...
>
> But more likely if this is what's going on then it's going to be a bug
> in the NS port. Unfortunately I don't really understand how the glyph
> drawing side works, and never did.
>
> But if that's the case, why would removing the asynchronous call to
> getContext fix so many problems?

It's possible we have two very different problems that only appear related:
1. The one i'm seeing, which is sort of ghosting of other lines into
the whitespace of nearby lines. The getContext call removal did not
fix this for me, I saw it happen once.
2. The one Kai is seeing, that is exacerbated by decreasing the
polling interval, but seems to be helped by removing the getContext
call.

> Something perhaps worth trying... Since removing the asynchronous call
> to getContext fixes the problems, perhaps we need to think about the
> "lazy" way we get the next buffer when the current one is displayed.
> At the moment it just forgets about it until we want to draw to the
> screen, at which point we call getContext and it creates the buffer if
> necessary and copies the old one to the new one.
>
> Maybe we should get the new buffer and do the copy when we set the
> current buffer for display...
>
> IIRC I avoided that because there isn't always time for the buffer to
> have been sent to VRAM and unlocked before the *next* call to display,
> so I wanted to leave it as long as possible between display and
> getting the next buffer, but maybe this is just the wrong way to do
> it.
>
> So I suppose putting a call to getContext right after "currentSurface
> == NULL" in display might be a quick and dirty way to test that.

My problem is that at this point it happens so infrequently and I have
no idea if that's because of the patches I'm trying or some other
environmental thing or just luck. I'm going to try running without the
async getContext and without the setNeedsDisplay for a while and see
if it happens. Perhaps the setNeedsDisplay is somehow causing an issue
and that's why changing it from source to dest seemed to help but it
didn't alleviate it.

If I see it again, I'll add the sync getContext call in, though I'll
admit I do not understand your paragraph above starting with IIRC. Are
you suspecting a potential problem with reading from the surface that
is in the process of being copied to vram?

Aaron





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-24 16:05                                                                   ` Aaron Jensen
@ 2023-06-24 21:29                                                                     ` Alan Third
  2023-06-24 21:43                                                                       ` Aaron Jensen
  0 siblings, 1 reply; 71+ messages in thread
From: Alan Third @ 2023-06-24 21:29 UTC (permalink / raw)
  To: Aaron Jensen; +Cc: Po Lu, Kai Ma, Eli Zaretskii, 63187

On Sat, Jun 24, 2023 at 12:05:45PM -0400, Aaron Jensen wrote:
> > But if that's the case, why would removing the asynchronous call to
> > getContext fix so many problems?
> 
> It's possible we have two very different problems that only appear related:
> 1. The one i'm seeing, which is sort of ghosting of other lines into
> the whitespace of nearby lines. The getContext call removal did not
> fix this for me, I saw it happen once.
> 2. The one Kai is seeing, that is exacerbated by decreasing the
> polling interval, but seems to be helped by removing the getContext
> call.

Yes, it might be two different things.

> > Something perhaps worth trying... Since removing the asynchronous call
> > to getContext fixes the problems, perhaps we need to think about the
> > "lazy" way we get the next buffer when the current one is displayed.
> > At the moment it just forgets about it until we want to draw to the
> > screen, at which point we call getContext and it creates the buffer if
> > necessary and copies the old one to the new one.
> >
> > Maybe we should get the new buffer and do the copy when we set the
> > current buffer for display...
> >
> > IIRC I avoided that because there isn't always time for the buffer to
> > have been sent to VRAM and unlocked before the *next* call to display,
> > so I wanted to leave it as long as possible between display and
> > getting the next buffer, but maybe this is just the wrong way to do
> > it.
> >
> > So I suppose putting a call to getContext right after "currentSurface
> > == NULL" in display might be a quick and dirty way to test that.
> 
> My problem is that at this point it happens so infrequently and I have
> no idea if that's because of the patches I'm trying or some other
> environmental thing or just luck. I'm going to try running without the
> async getContext and without the setNeedsDisplay for a while and see
> if it happens. Perhaps the setNeedsDisplay is somehow causing an issue
> and that's why changing it from source to dest seemed to help but it
> didn't alleviate it.

OK

> If I see it again, I'll add the sync getContext call in, though I'll
> admit I do not understand your paragraph above starting with IIRC. Are
> you suspecting a potential problem with reading from the surface that
> is in the process of being copied to vram?

Maybe... I'm really not sure what might be going on.

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.

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.

This would possibly explain why Kai lowering the polling interval
induces the issue, as it may increase the frequency at which the
screen is updated beyond the point where we're able to keep up.

To be honest though, I feel it should all be pretty linear and this
idea implies things are happening out-of-order. So I'm not convinced
I'm right.


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.

I'm not sure if that's a legitimate concern... 😕


I've got too many ideas about how to fix it and no way to actually try
them out, never mind the difficulty of inducing the issue if I did.

-- 
Alan Third





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-24 21:29                                                                     ` Alan Third
@ 2023-06-24 21:43                                                                       ` Aaron Jensen
  2023-06-25 12:46                                                                         ` Alan Third
  0 siblings, 1 reply; 71+ messages in thread
From: Aaron Jensen @ 2023-06-24 21:43 UTC (permalink / raw)
  To: Alan Third, Aaron Jensen, Kai Ma, 63187, Eli Zaretskii, Po Lu

On Sat, Jun 24, 2023 at 5:29 PM Alan Third <alan@idiocy.org> wrote:
>
> On Sat, Jun 24, 2023 at 12:05:45PM -0400, Aaron Jensen wrote:
> > > But if that's the case, why would removing the asynchronous call to
> > > getContext fix so many problems?
> >
> > It's possible we have two very different problems that only appear related:
> > 1. The one i'm seeing, which is sort of ghosting of other lines into
> > the whitespace of nearby lines. The getContext call removal did not
> > fix this for me, I saw it happen once.
> > 2. The one Kai is seeing, that is exacerbated by decreasing the
> > polling interval, but seems to be helped by removing the getContext
> > call.
>
> Yes, it might be two different things.
>
> > > Something perhaps worth trying... Since removing the asynchronous call
> > > to getContext fixes the problems, perhaps we need to think about the
> > > "lazy" way we get the next buffer when the current one is displayed.
> > > At the moment it just forgets about it until we want to draw to the
> > > screen, at which point we call getContext and it creates the buffer if
> > > necessary and copies the old one to the new one.
> > >
> > > Maybe we should get the new buffer and do the copy when we set the
> > > current buffer for display...
> > >
> > > IIRC I avoided that because there isn't always time for the buffer to
> > > have been sent to VRAM and unlocked before the *next* call to display,
> > > so I wanted to leave it as long as possible between display and
> > > getting the next buffer, but maybe this is just the wrong way to do
> > > it.
> > >
> > > So I suppose putting a call to getContext right after "currentSurface
> > > == NULL" in display might be a quick and dirty way to test that.
> >
> > My problem is that at this point it happens so infrequently and I have
> > no idea if that's because of the patches I'm trying or some other
> > environmental thing or just luck. I'm going to try running without the
> > async getContext and without the setNeedsDisplay for a while and see
> > if it happens. Perhaps the setNeedsDisplay is somehow causing an issue
> > and that's why changing it from source to dest seemed to help but it
> > didn't alleviate it.
>
> OK
>
> > If I see it again, I'll add the sync getContext call in, though I'll
> > admit I do not understand your paragraph above starting with IIRC. Are
> > you suspecting a potential problem with reading from the surface that
> > is in the process of being copied to vram?
>
> Maybe... I'm really not sure what might be going on.
>
> 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?

> 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 :)

> This would possibly explain why Kai lowering the polling interval
> induces the issue, as it may increase the frequency at which the
> screen is updated beyond the point where we're able to keep up.
>
> To be honest though, I feel it should all be pretty linear and this
> idea implies things are happening out-of-order. So I'm not convinced
> I'm right.
>
>
> 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?

>
> I'm not sure if that's a legitimate concern... 😕
>
>
> I've got too many ideas about how to fix it and no way to actually try
> them out, never mind the difficulty of inducing the issue if I did.

I'm happy to try things if you don't mind a 1-2 week feedback cycle
(since lately that's about how long it takes for me to see an issue...





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-24 21:43                                                                       ` Aaron Jensen
@ 2023-06-25 12:46                                                                         ` Alan Third
  2023-06-25 17:07                                                                           ` Aaron Jensen
  2023-06-26  7:27                                                                           ` Kai Ma
  0 siblings, 2 replies; 71+ messages in thread
From: Alan Third @ 2023-06-25 12:46 UTC (permalink / raw)
  To: Aaron Jensen; +Cc: Po Lu, Kai Ma, Eli Zaretskii, 63187

On Sat, Jun 24, 2023 at 05:43:04PM -0400, Aaron Jensen wrote:
> On Sat, Jun 24, 2023 at 5:29 PM Alan Third <alan@idiocy.org> 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





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-25 12:46                                                                         ` Alan Third
@ 2023-06-25 17:07                                                                           ` Aaron Jensen
  2023-06-25 18:17                                                                             ` Alan Third
  2023-06-26  7:27                                                                           ` Kai Ma
  1 sibling, 1 reply; 71+ messages in thread
From: Aaron Jensen @ 2023-06-25 17:07 UTC (permalink / raw)
  To: Alan Third, Aaron Jensen, Kai Ma, 63187, Eli Zaretskii, Po Lu

On Sun, Jun 25, 2023 at 8:46 AM Alan Third <alan@idiocy.org> wrote:
>
> On Sat, Jun 24, 2023 at 05:43:04PM -0400, Aaron Jensen wrote:
> > On Sat, Jun 24, 2023 at 5:29 PM Alan Third <alan@idiocy.org> 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.

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-notes/

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





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-25 17:07                                                                           ` Aaron Jensen
@ 2023-06-25 18:17                                                                             ` Alan Third
  2023-06-25 19:07                                                                               ` Aaron Jensen
  0 siblings, 1 reply; 71+ messages in thread
From: Alan Third @ 2023-06-25 18:17 UTC (permalink / raw)
  To: Aaron Jensen; +Cc: Po Lu, Kai Ma, Eli Zaretskii, 63187

On Sun, Jun 25, 2023 at 01:07:19PM -0400, Aaron Jensen wrote:
> 
> 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

Yep.

> 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.

No, you can use [NSGraphicsContext flushGraphics] and CGContextFlush
to force it.

As I recall we've tried that in both copyRect and display.

Ultimately releasing the context will have to flush any buffered
writes, if it didn't then this would be a widely known problem as
practically nothing graphical could be relied upon.

This is my point about why I can't see this being the issue. Although
it looks like it explains what we're seeing, we would have to be
hitting some extreme edge-case.

> I came across some notes from the Chromium team:
> https://www.chromium.org/developers/design-documents/iosurface-meeting-notes/
> 
> 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.

Set CACHE_MAX_SIZE to 1.

But on my machine this resulted in unacceptable rendering flaws on
almost all animated gifs as partially drawn buffers were sent to VRAM.

And adding more open frames just made it worse, as I recall. I never
really understood why.

It wasn't just gifs, but they were an easy test.

But then, I'll bet performance is incredible. ;)

> 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.

I'm not sure if I'm following your question correctly, but yes, not
copying is usually going to be faster, but it depends how long it
takes the buffer to copy to VRAM, you might well find that you're
waiting for it to finish when you may have already been in the
position to start drawing to a second buffer.

In theory, if you set CACHE_MAX_SIZE > 1, and change

    [cache addObject:(id)currentSurface];

to

    [cache insertObject:(id)currentSurface
                atIndex:0]

It should try to pick up the most recent surface first, then
copyContentsTo will recognise that it's the same surface as last time,
and not bother with the copy. I think you'd have to enable

    [self setContents:nil];

to work all the time too, as you might be wanting to "replace" the
contents layer with itself.

I've no idea if that would really work. IIRC on my machine the surface
that was "in flight" to VRAM was never done fast enough that it would
be picked up by the next getContext call so I felt it was a waste to
check it every time. (And in fast-scrolling situations I could have as
many as three surfaces in-flight at once if I let the cache grow that
big.)
-- 
Alan Third





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-25 18:17                                                                             ` Alan Third
@ 2023-06-25 19:07                                                                               ` Aaron Jensen
  2023-06-25 21:18                                                                                 ` Alan Third
  0 siblings, 1 reply; 71+ messages in thread
From: Aaron Jensen @ 2023-06-25 19:07 UTC (permalink / raw)
  To: Alan Third, Aaron Jensen, Kai Ma, 63187, Eli Zaretskii, Po Lu

On Sun, Jun 25, 2023 at 2:17 PM Alan Third <alan@idiocy.org> wrote:
>
> On Sun, Jun 25, 2023 at 01:07:19PM -0400, Aaron Jensen wrote:
> >
> > 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
>
> Yep.
>
> > 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.
>
> No, you can use [NSGraphicsContext flushGraphics] and CGContextFlush
> to force it.

OK, that makes sense, but it's hard to find definitive documentation
of that (and ChatGPT seems to think that it's not true, but that's
likely a hallucination):

=====START GPT=====
[NSGraphicsContext flushGraphics] (in Cocoa) and CGContextFlush (in
Core Graphics) are used to bypass this batching process and force any
pending drawing commands to be executed immediately. After calling
these methods, you can be sure that all your previously issued drawing
commands have been sent to the GPU.

However, it's important to understand that while these functions
ensure that the commands are sent to the GPU, they don't guarantee
that the GPU has finished executing them. The actual rendering work is
still done asynchronously by the GPU.

So if you need to read back the results of your rendering (e.g., from
an IOSurface), there might still be a brief period where the rendering
hasn't completed yet, even after calling flushGraphics or
CGContextFlush. If you need to ensure that all GPU rendering work is
complete before you proceed, you would typically need to use a more
low-level API (like Metal or OpenGL) that provides explicit
synchronization capabilities.

...

Regarding your question about the [NSGraphicsContext flushGraphics]
and CGContextFlush, here are the descriptions directly from Apple's
documentation:

[NSGraphicsContext flushGraphics]: "Forces any buffered drawing
commands to be sent to the destination."

CGContextFlush: "Forces all drawing operations to be completed in the
specified context."

It's important to understand these function calls ensure that drawing
commands are dispatched, not that they are completed. This is an
inference based on understanding of how graphics pipelines generally
work. For more detailed behavior and how these calls interact with
your specific use-case, you should refer to Apple's documentation and
guides, or consider reaching out to Apple's developer support.
=====END GPT=====

> As I recall we've tried that in both copyRect and display.
>
> Ultimately releasing the context will have to flush any buffered
> writes, if it didn't then this would be a widely known problem as
> practically nothing graphical could be relied upon.
>
> This is my point about why I can't see this being the issue. Although
> it looks like it explains what we're seeing, we would have to be
> hitting some extreme edge-case.
>
> > I came across some notes from the Chromium team:
> > https://www.chromium.org/developers/design-documents/iosurface-meeting-notes/
> >
> > 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.
>
> Set CACHE_MAX_SIZE to 1.
>
> But on my machine this resulted in unacceptable rendering flaws on
> almost all animated gifs as partially drawn buffers were sent to VRAM.

What did you see?
I tried with this:

https://share.cleanshot.com/vJTClHW9

And I didn't notice anything drawing related, but I have an M1 with
integrated memory.

Aaron

> And adding more open frames just made it worse, as I recall. I never
> really understood why.
>
> It wasn't just gifs, but they were an easy test.
>
> But then, I'll bet performance is incredible. ;)
>
> > 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.
>
> I'm not sure if I'm following your question correctly, but yes, not
> copying is usually going to be faster, but it depends how long it
> takes the buffer to copy to VRAM, you might well find that you're
> waiting for it to finish when you may have already been in the
> position to start drawing to a second buffer.
>
> In theory, if you set CACHE_MAX_SIZE > 1, and change
>
>     [cache addObject:(id)currentSurface];
>
> to
>
>     [cache insertObject:(id)currentSurface
>                 atIndex:0]
>
> It should try to pick up the most recent surface first, then
> copyContentsTo will recognise that it's the same surface as last time,
> and not bother with the copy. I think you'd have to enable
>
>     [self setContents:nil];
>
> to work all the time too, as you might be wanting to "replace" the
> contents layer with itself.
>
> I've no idea if that would really work. IIRC on my machine the surface
> that was "in flight" to VRAM was never done fast enough that it would
> be picked up by the next getContext call so I felt it was a waste to
> check it every time. (And in fast-scrolling situations I could have as
> many as three surfaces in-flight at once if I let the cache grow that
> big.)
> --
> Alan Third





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-25 19:07                                                                               ` Aaron Jensen
@ 2023-06-25 21:18                                                                                 ` Alan Third
  2023-06-25 22:33                                                                                   ` Aaron Jensen
  0 siblings, 1 reply; 71+ messages in thread
From: Alan Third @ 2023-06-25 21:18 UTC (permalink / raw)
  To: Aaron Jensen; +Cc: Po Lu, Kai Ma, Eli Zaretskii, 63187

On Sun, Jun 25, 2023 at 03:07:39PM -0400, Aaron Jensen wrote:
> On Sun, Jun 25, 2023 at 2:17 PM Alan Third <alan@idiocy.org> wrote:
> > No, you can use [NSGraphicsContext flushGraphics] and CGContextFlush
> > to force it.
> 
> OK, that makes sense, but it's hard to find definitive documentation
> of that (and ChatGPT seems to think that it's not true, but that's
> likely a hallucination):
> 
> =====START GPT=====
> [NSGraphicsContext flushGraphics] (in Cocoa) and CGContextFlush (in
> Core Graphics) are used to bypass this batching process and force any
> pending drawing commands to be executed immediately. After calling
> these methods, you can be sure that all your previously issued drawing
> commands have been sent to the GPU.
> 
> However, it's important to understand that while these functions
> ensure that the commands are sent to the GPU, they don't guarantee
> that the GPU has finished executing them. The actual rendering work is
> still done asynchronously by the GPU.
> 
> So if you need to read back the results of your rendering (e.g., from
> an IOSurface), there might still be a brief period where the rendering
> hasn't completed yet, even after calling flushGraphics or
> CGContextFlush. If you need to ensure that all GPU rendering work is
> complete before you proceed, you would typically need to use a more
> low-level API (like Metal or OpenGL) that provides explicit
> synchronization capabilities.
> 
> ...
> 
> Regarding your question about the [NSGraphicsContext flushGraphics]
> and CGContextFlush, here are the descriptions directly from Apple's
> documentation:
> 
> [NSGraphicsContext flushGraphics]: "Forces any buffered drawing
> commands to be sent to the destination."
> 
> CGContextFlush: "Forces all drawing operations to be completed in the
> specified context."
> 
> It's important to understand these function calls ensure that drawing
> commands are dispatched, not that they are completed. This is an
> inference based on understanding of how graphics pipelines generally
> work. For more detailed behavior and how these calls interact with
> your specific use-case, you should refer to Apple's documentation and
> guides, or consider reaching out to Apple's developer support.
> =====END GPT=====

The GPU isn't involved in this part. We're drawing to an IOSurface,
which is a buffer in system memory. So when we draw and flush the
graphics it's all done by the CPU in system memory.

Then we put the IOSurfaceRef in the contents variable of the layer and
at that point the GPU uses DMA to copy the buffer from system memory
to GPU memory. While this is happening the IOSurface is locked so we
know we shouldn't use it.

Once it's in GPU memory, the GPU blits it to the screenbuffer or
something, but by that time the IOSurface should be unlocked and we
can start (safely) working on it again.

> > Set CACHE_MAX_SIZE to 1.
> >
> > But on my machine this resulted in unacceptable rendering flaws on
> > almost all animated gifs as partially drawn buffers were sent to VRAM.
> 
> What did you see?
> I tried with this:
> 
> https://share.cleanshot.com/vJTClHW9
> 
> And I didn't notice anything drawing related, but I have an M1 with
> integrated memory.

Lots of white space. I thought that it was being caught either just
before or as the image was being drawn into the buffer, so some
portion of the image area was blank.
-- 
Alan Third





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-25 21:18                                                                                 ` Alan Third
@ 2023-06-25 22:33                                                                                   ` Aaron Jensen
  0 siblings, 0 replies; 71+ messages in thread
From: Aaron Jensen @ 2023-06-25 22:33 UTC (permalink / raw)
  To: Alan Third, Aaron Jensen, Kai Ma, 63187, Eli Zaretskii, Po Lu

On Sun, Jun 25, 2023 at 5:18 PM Alan Third <alan@idiocy.org> wrote:
>
> On Sun, Jun 25, 2023 at 03:07:39PM -0400, Aaron Jensen wrote:
> > On Sun, Jun 25, 2023 at 2:17 PM Alan Third <alan@idiocy.org> wrote:
> > > No, you can use [NSGraphicsContext flushGraphics] and CGContextFlush
> > > to force it.
> >
> > OK, that makes sense, but it's hard to find definitive documentation
> > of that (and ChatGPT seems to think that it's not true, but that's
> > likely a hallucination):
> >
> > =====START GPT=====
> > [NSGraphicsContext flushGraphics] (in Cocoa) and CGContextFlush (in
> > Core Graphics) are used to bypass this batching process and force any
> > pending drawing commands to be executed immediately. After calling
> > these methods, you can be sure that all your previously issued drawing
> > commands have been sent to the GPU.
> >
> > However, it's important to understand that while these functions
> > ensure that the commands are sent to the GPU, they don't guarantee
> > that the GPU has finished executing them. The actual rendering work is
> > still done asynchronously by the GPU.
> >
> > So if you need to read back the results of your rendering (e.g., from
> > an IOSurface), there might still be a brief period where the rendering
> > hasn't completed yet, even after calling flushGraphics or
> > CGContextFlush. If you need to ensure that all GPU rendering work is
> > complete before you proceed, you would typically need to use a more
> > low-level API (like Metal or OpenGL) that provides explicit
> > synchronization capabilities.
> >
> > ...
> >
> > Regarding your question about the [NSGraphicsContext flushGraphics]
> > and CGContextFlush, here are the descriptions directly from Apple's
> > documentation:
> >
> > [NSGraphicsContext flushGraphics]: "Forces any buffered drawing
> > commands to be sent to the destination."
> >
> > CGContextFlush: "Forces all drawing operations to be completed in the
> > specified context."
> >
> > It's important to understand these function calls ensure that drawing
> > commands are dispatched, not that they are completed. This is an
> > inference based on understanding of how graphics pipelines generally
> > work. For more detailed behavior and how these calls interact with
> > your specific use-case, you should refer to Apple's documentation and
> > guides, or consider reaching out to Apple's developer support.
> > =====END GPT=====
>
> The GPU isn't involved in this part. We're drawing to an IOSurface,
> which is a buffer in system memory. So when we draw and flush the
> graphics it's all done by the CPU in system memory.
>
> Then we put the IOSurfaceRef in the contents variable of the layer and
> at that point the GPU uses DMA to copy the buffer from system memory
> to GPU memory. While this is happening the IOSurface is locked so we
> know we shouldn't use it.
>
> Once it's in GPU memory, the GPU blits it to the screenbuffer or
> something, but by that time the IOSurface should be unlocked and we
> can start (safely) working on it again.

OK, that's clarifying, thank you.

> > > Set CACHE_MAX_SIZE to 1.
> > >
> > > But on my machine this resulted in unacceptable rendering flaws on
> > > almost all animated gifs as partially drawn buffers were sent to VRAM.
> >
> > What did you see?
> > I tried with this:
> >
> > https://share.cleanshot.com/vJTClHW9
> >
> > And I didn't notice anything drawing related, but I have an M1 with
> > integrated memory.
>
> Lots of white space. I thought that it was being caught either just
> before or as the image was being drawn into the buffer, so some
> portion of the image area was blank.

Interesting. Would:

+  if (context && context != [NSGraphicsContext currentContext])

have impacted that in any way?

Aaron





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-25 12:46                                                                         ` Alan Third
  2023-06-25 17:07                                                                           ` Aaron Jensen
@ 2023-06-26  7:27                                                                           ` Kai Ma
  2023-06-28 19:53                                                                             ` Alan Third
  1 sibling, 1 reply; 71+ messages in thread
From: Kai Ma @ 2023-06-26  7:27 UTC (permalink / raw)
  To: Alan Third; +Cc: Po Lu, 63187, Eli Zaretskii, Aaron Jensen



> On Jun 25, 2023, at 20:46, Alan Third <alan@idiocy.org> wrote:
> 
>>> 
>>> 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?
> 
> 
> Kai, it might be worth trying just that change above, while keeping
> the call to performSelectorInMainThread and see if it fixes anything
> for you.

Unfortunately, the problem persists (as in the YouTube video) if performSelectorInMainThread is present.






^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-26  7:27                                                                           ` Kai Ma
@ 2023-06-28 19:53                                                                             ` Alan Third
  2023-07-21  2:02                                                                               ` Aaron Jensen
  0 siblings, 1 reply; 71+ messages in thread
From: Alan Third @ 2023-06-28 19:53 UTC (permalink / raw)
  To: Kai Ma; +Cc: Po Lu, 63187, Eli Zaretskii, Aaron Jensen

On Mon, Jun 26, 2023 at 03:27:41PM +0800, Kai Ma wrote:
> 
> 
> > On Jun 25, 2023, at 20:46, Alan Third <alan@idiocy.org> wrote:
> > 
> >>> 
> >>> 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?
> > 
> > 
> > Kai, it might be worth trying just that change above, while keeping
> > the call to performSelectorInMainThread and see if it fixes anything
> > for you.
> 
> Unfortunately, the problem persists (as in the YouTube video) if performSelectorInMainThread is present.

OK. Thanks for trying it.
-- 
Alan Third





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-06-28 19:53                                                                             ` Alan Third
@ 2023-07-21  2:02                                                                               ` Aaron Jensen
  2023-07-23 11:20                                                                                 ` Alan Third
  0 siblings, 1 reply; 71+ messages in thread
From: Aaron Jensen @ 2023-07-21  2:02 UTC (permalink / raw)
  To: Alan Third, Kai Ma, Aaron Jensen, 63187, Eli Zaretskii, Po Lu

On Wed, Jun 28, 2023 at 3:53 PM Alan Third <alan@idiocy.org> wrote:
>
> On Mon, Jun 26, 2023 at 03:27:41PM +0800, Kai Ma wrote:
> >
> >
> > > On Jun 25, 2023, at 20:46, Alan Third <alan@idiocy.org> wrote:
> > >
> > >>>
> > >>> 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?
> > >
> > >
> > > Kai, it might be worth trying just that change above, while keeping
> > > the call to performSelectorInMainThread and see if it fixes anything
> > > for you.
> >
> > Unfortunately, the problem persists (as in the YouTube video) if performSelectorInMainThread is present.
>
> OK. Thanks for trying it.


I've been using this for about a month now and have seen no artifacts:

diff --git a/src/nsterm.m b/src/nsterm.m
index 78089906752..d23fb650ab8 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -2708,9 +2708,6 @@ Hide the window (X11 semantics)
     EmacsView *view = FRAME_NS_VIEW (f);

     [view copyRect:srcRect to:dest];
-#ifdef NS_IMPL_COCOA
-    [view setNeedsDisplayInRect:destRect];
-#endif
   }

   unblock_input ();
@@ -10435,7 +10432,7 @@ @implementation EmacsLayer
    cache.  If no free surfaces are found in the cache then a new one
    is created.  */

-#define CACHE_MAX_SIZE 2
+#define CACHE_MAX_SIZE 1

 - (id) initWithColorSpace: (CGColorSpaceRef)cs
 {
@@ -10621,7 +10618,7 @@ - (void) display
 {
   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "[EmacsLayer display]");

-  if (context)
+  if (context && context != [NSGraphicsContext currentContext])
     {
       [self releaseContext];


I'm not sure what the ramifications are for CACHE_MAX_SIZE 1 on slower
machines, but I don't notice any performance issues on my M1.

Alan, what do you think we should do? Is there anything else you think
I should test for the next bit of time?

Thanks,

Aaron





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-07-21  2:02                                                                               ` Aaron Jensen
@ 2023-07-23 11:20                                                                                 ` Alan Third
  2023-07-23 13:01                                                                                   ` Aaron Jensen
  0 siblings, 1 reply; 71+ messages in thread
From: Alan Third @ 2023-07-23 11:20 UTC (permalink / raw)
  To: Aaron Jensen; +Cc: Po Lu, Kai Ma, Eli Zaretskii, 63187

[-- Attachment #1: Type: text/plain, Size: 1803 bytes --]

On Thu, Jul 20, 2023 at 10:02:53PM -0400, Aaron Jensen wrote:
> 
> I've been using this for about a month now and have seen no artifacts:
> 
> diff --git a/src/nsterm.m b/src/nsterm.m
> index 78089906752..d23fb650ab8 100644
> --- a/src/nsterm.m
> +++ b/src/nsterm.m
> @@ -2708,9 +2708,6 @@ Hide the window (X11 semantics)
>      EmacsView *view = FRAME_NS_VIEW (f);
> 
>      [view copyRect:srcRect to:dest];
> -#ifdef NS_IMPL_COCOA
> -    [view setNeedsDisplayInRect:destRect];
> -#endif
>    }
> 
>    unblock_input ();
> @@ -10435,7 +10432,7 @@ @implementation EmacsLayer
>     cache.  If no free surfaces are found in the cache then a new one
>     is created.  */
> 
> -#define CACHE_MAX_SIZE 2
> +#define CACHE_MAX_SIZE 1
> 
>  - (id) initWithColorSpace: (CGColorSpaceRef)cs
>  {
> @@ -10621,7 +10618,7 @@ - (void) display
>  {
>    NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "[EmacsLayer display]");
> 
> -  if (context)
> +  if (context && context != [NSGraphicsContext currentContext])
>      {
>        [self releaseContext];
> 
> 
> I'm not sure what the ramifications are for CACHE_MAX_SIZE 1 on slower
> machines, but I don't notice any performance issues on my M1.
> 
> Alan, what do you think we should do? Is there anything else you think
> I should test for the next bit of time?

I dug out my mac and built this and it still flickers with animated
gifs. It's pretty easy to make happen, so it must be some hardware
performance thing.

Anyway, I've tried simplifying the double buffering code and put in
all the wee changes I've thought about. Who knows if this will work
any better...

(It may be worth making the single/double buffering a run-time option
as theoretically the single buffering will perform better, although
always at the increased risk of tearing effects etc.)
-- 
Alan Third

[-- Attachment #2: 0001-Simplify-the-EmacsLayer-double-buffering-code-bug-63.patch --]
[-- Type: text/x-diff, Size: 12556 bytes --]

From 4a486d74acb5f8f17266d65629aa7f884efb2834 Mon Sep 17 00:00:00 2001
From: Alan Third <alan@idiocy.org>
Date: Sun, 23 Jul 2023 12:00:30 +0100
Subject: [PATCH] Simplify the EmacsLayer double buffering code (bug#63187)

* src/nsterm.h (EmacsLayer): Remove cache and replace with two
IOSurface variables.
* src/nsterm.m (ns_scroll_run): Remove redundant code.
([EmacsView copyRect:to:]): Ensure the context is flushed before we
start messign directly with the pixel buffer.
([EmacsLayer initWithColorSpace:]):
([EmacsLayer dealloc]):
([EmacsLayer releaseSurfaces]):
([EmacsLayer checkDimensions]):
([EmacsLayer getContext]):
([EmacsLayer releaseContext]):
([EmacsLayer display]):
([EmacsLayer copyContentsTo:]): Remove cache and replace with two
IOSurface variables.
---
 src/nsterm.h |   3 +-
 src/nsterm.m | 147 +++++++++++++++++++--------------------------------
 2 files changed, 56 insertions(+), 94 deletions(-)

diff --git a/src/nsterm.h b/src/nsterm.h
index b6e5a813a6d..22dbf2d8f27 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -742,9 +742,8 @@ #define NSTRACE_UNSILENCE()
 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MIN_REQUIRED >= 101400
 @interface EmacsLayer : CALayer
 {
-  NSMutableArray *cache;
   CGColorSpaceRef colorSpace;
-  IOSurfaceRef currentSurface;
+  IOSurfaceRef frontSurface, backSurface;
   CGContextRef context;
 }
 - (id) initWithColorSpace: (CGColorSpaceRef)cs;
diff --git a/src/nsterm.m b/src/nsterm.m
index 78089906752..c23238b7dec 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -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
   }
@@ -8664,8 +8663,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);
@@ -10421,21 +10422,16 @@ @implementation EmacsLayer
    of the output.  To avoid this problem we can check if the surface
    is "in use", and if it is then avoid using it.  Unfortunately to
    avoid writing to a surface that's in use, but still maintain the
-   ability to draw to the screen at any time, we need to keep a cache
-   of multiple surfaces that we can use at will.
+   ability to draw to the screen at any time, we need to mantain
+   multiple surfaces that we can use at will.
 
-   The EmacsLayer class maintains this cache of surfaces, and
-   handles the conversion to a CGGraphicsContext that AppKit can use
-   to draw on.
+   The EmacsLayer class maintains these surfaces, and handles the
+   conversion to a CGGraphicsContext that AppKit can use to draw on.
 
-   The cache is simple: if a free surface is found it is removed from
-   the cache and set as the "current" surface.  Emacs draws to the
-   surface and when the layer wants to update the screen we set it's
-   contents to the surface and then add it back on to the end of the
-   cache.  If no free surfaces are found in the cache then a new one
-   is created.  */
+   We simply have a "back" surface, which we can draw to, and a
+   "front" buffer that is currently being displayed on the screen.  */
 
-#define CACHE_MAX_SIZE 2
+#define EMACSLAYER_DOUBLE_BUFFERED 1
 
 - (id) initWithColorSpace: (CGColorSpaceRef)cs
 {
@@ -10443,14 +10439,9 @@ - (id) initWithColorSpace: (CGColorSpaceRef)cs
 
   self = [super init];
   if (self)
-    {
-      cache = [[NSMutableArray arrayWithCapacity:CACHE_MAX_SIZE] retain];
-      [self setColorSpace:cs];
-    }
+    [self setColorSpace:cs];
   else
-    {
-      return nil;
-    }
+    return nil;
 
   return self;
 }
@@ -10470,8 +10461,6 @@ - (void) setColorSpace: (CGColorSpaceRef)cs
 - (void) dealloc
 {
   [self releaseSurfaces];
-  [cache release];
-
   [super dealloc];
 }
 
@@ -10481,18 +10470,16 @@ - (void) releaseSurfaces
   [self setContents:nil];
   [self releaseContext];
 
-  if (currentSurface)
+  if (frontSurface)
     {
-      CFRelease (currentSurface);
-      currentSurface = nil;
+      CFRelease (frontSurface);
+      frontSurface = nil;
     }
 
-  if (cache)
+  if (backSurface)
     {
-      for (id object in cache)
-        CFRelease ((IOSurfaceRef)object);
-
-      [cache removeAllObjects];
+      CFRelease (backSurface);
+      backSurface = nil;
     }
 }
 
@@ -10503,8 +10490,7 @@ - (BOOL) checkDimensions
 {
   int width = NSWidth ([self bounds]) * [self contentsScale];
   int height = NSHeight ([self bounds]) * [self contentsScale];
-  IOSurfaceRef s = currentSurface ? currentSurface
-    : (IOSurfaceRef)[cache firstObject];
+  IOSurfaceRef s = backSurface ? backSurface : frontSurface;
 
   return !s || (IOSurfaceGetWidth (s) == width
                 && IOSurfaceGetHeight (s) == height);
@@ -10517,41 +10503,21 @@ - (CGContextRef) getContext
   CGFloat scale = [self contentsScale];
 
   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "[EmacsLayer getContext]");
-  NSTRACE_MSG ("IOSurface count: %lu", [cache count] + (currentSurface ? 1 : 0));
 
   if (![self checkDimensions])
     [self releaseSurfaces];
 
   if (!context)
     {
-      IOSurfaceRef surface = NULL;
       int width = NSWidth ([self bounds]) * scale;
       int height = NSHeight ([self bounds]) * scale;
 
-      for (id object in cache)
-        {
-          if (!IOSurfaceIsInUse ((IOSurfaceRef)object))
-            {
-              surface = (IOSurfaceRef)object;
-              [cache removeObject:object];
-              break;
-            }
-        }
-
-      if (!surface && [cache count] >= CACHE_MAX_SIZE)
-        {
-          /* Just grab the first one off the cache.  This may result
-             in tearing effects.  The alternative is to wait for one
-             of the surfaces to become free.  */
-          surface = (IOSurfaceRef)[cache firstObject];
-          [cache removeObject:(id)surface];
-        }
-      else if (!surface)
+      if (!backSurface)
         {
           int bytesPerRow = IOSurfaceAlignProperty (kIOSurfaceBytesPerRow,
                                                     width * 4);
 
-          surface = IOSurfaceCreate
+          backSurface = IOSurfaceCreate
             ((CFDictionaryRef)@{(id)kIOSurfaceWidth:[NSNumber numberWithInt:width],
                 (id)kIOSurfaceHeight:[NSNumber numberWithInt:height],
                 (id)kIOSurfaceBytesPerRow:[NSNumber numberWithInt:bytesPerRow],
@@ -10559,25 +10525,23 @@ - (CGContextRef) getContext
                 (id)kIOSurfacePixelFormat:[NSNumber numberWithUnsignedInt:'BGRA']});
         }
 
-      if (!surface)
+      if (!backSurface)
         {
           NSLog (@"Failed to create IOSurface for frame %@", [self delegate]);
           return nil;
         }
 
-      IOReturn lockStatus = IOSurfaceLock (surface, 0, nil);
+      IOReturn lockStatus = IOSurfaceLock (backSurface, 0, nil);
       if (lockStatus != kIOReturnSuccess)
         NSLog (@"Failed to lock surface: %x", lockStatus);
 
-      [self copyContentsTo:surface];
+      [self copyContentsTo:backSurface];
 
-      currentSurface = surface;
-
-      context = CGBitmapContextCreate (IOSurfaceGetBaseAddress (currentSurface),
-                                       IOSurfaceGetWidth (currentSurface),
-                                       IOSurfaceGetHeight (currentSurface),
+      context = CGBitmapContextCreate (IOSurfaceGetBaseAddress (backSurface),
+                                       IOSurfaceGetWidth (backSurface),
+                                       IOSurfaceGetHeight (backSurface),
                                        8,
-                                       IOSurfaceGetBytesPerRow (currentSurface),
+                                       IOSurfaceGetBytesPerRow (backSurface),
                                        colorSpace,
                                        (kCGImageAlphaPremultipliedFirst
                                         | kCGBitmapByteOrder32Host));
@@ -10585,13 +10549,13 @@ - (CGContextRef) getContext
       if (!context)
         {
           NSLog (@"Failed to create context for frame %@", [self delegate]);
-          IOSurfaceUnlock (currentSurface, 0, nil);
-          CFRelease (currentSurface);
-          currentSurface = nil;
+          IOSurfaceUnlock (backSurface, 0, nil);
+          CFRelease (backSurface);
+          backSurface = nil;
           return nil;
         }
 
-      CGContextTranslateCTM(context, 0, IOSurfaceGetHeight (currentSurface));
+      CGContextTranslateCTM(context, 0, IOSurfaceGetHeight (backSurface));
       CGContextScaleCTM(context, scale, -scale);
     }
 
@@ -10608,10 +10572,11 @@ - (void) releaseContext
   if (!context)
     return;
 
+  CGContextFlush (context);
   CGContextRelease (context);
   context = NULL;
 
-  IOReturn lockStatus = IOSurfaceUnlock (currentSurface, 0, nil);
+  IOReturn lockStatus = IOSurfaceUnlock (backSurface, 0, nil);
   if (lockStatus != kIOReturnSuccess)
     NSLog (@"Failed to unlock surface: %x", lockStatus);
 }
@@ -10621,63 +10586,61 @@ - (void) display
 {
   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "[EmacsLayer display]");
 
-  if (context)
+  if (context && context != [[NSGraphicsContext currentContext] CGContext])
     {
       [self releaseContext];
 
-#if CACHE_MAX_SIZE == 1
+#ifdef EMACSLAYER_DOUBLE_BUFFERED
+      IOSurfaceRef tmp = frontSurface;
+      frontSurface = backSurface;
+      backSurface = tmp;
+
+      [self setContents:(id)frontSurface];
+#else
       /* This forces the layer to see the surface as updated.  */
       [self setContents:nil];
-#endif
-
-      [self setContents:(id)currentSurface];
 
-      /* Put currentSurface back on the end of the cache.  */
-      [cache addObject:(id)currentSurface];
-      currentSurface = NULL;
+      /* Since we're not doible buffering, just use the back
+         surface. */
+      [self setContents:(id)backSurface];
 
-      /* 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];
+#endif
     }
 }
 
 
-/* Copy the contents of lastSurface to DESTINATION.  This is required
+/* Copy the contents of frontSurface to DESTINATION.  This is required
    every time we want to use an IOSurface as its contents are probably
    blanks (if it's new), or stale.  */
 - (void) copyContentsTo: (IOSurfaceRef) destination
 {
   IOReturn lockStatus;
-  IOSurfaceRef source = (IOSurfaceRef)[self contents];
-  void *sourceData, *destinationData;
+  void *frontSurfaceData, *destinationData;
   int numBytes = IOSurfaceGetAllocSize (destination);
 
   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "[EmacsLayer copyContentsTo:]");
 
-  if (!source || source == destination)
+  if (!frontSurface || frontSurface == destination)
     return;
 
-  lockStatus = IOSurfaceLock (source, kIOSurfaceLockReadOnly, nil);
+  lockStatus = IOSurfaceLock (frontSurface, kIOSurfaceLockReadOnly, nil);
   if (lockStatus != kIOReturnSuccess)
     NSLog (@"Failed to lock source surface: %x", lockStatus);
 
-  sourceData = IOSurfaceGetBaseAddress (source);
+  frontSurfaceData = IOSurfaceGetBaseAddress (frontSurface);
   destinationData = IOSurfaceGetBaseAddress (destination);
 
   /* Since every IOSurface should have the exact same settings, a
      memcpy seems like the fastest way to copy the data from one to
      the other.  */
-  memcpy (destinationData, sourceData, numBytes);
+  memcpy (destinationData, frontSurfaceData, numBytes);
 
-  lockStatus = IOSurfaceUnlock (source, kIOSurfaceLockReadOnly, nil);
+  lockStatus = IOSurfaceUnlock (frontSurface, kIOSurfaceLockReadOnly, nil);
   if (lockStatus != kIOReturnSuccess)
     NSLog (@"Failed to unlock source surface: %x", lockStatus);
 }
 
-#undef CACHE_MAX_SIZE
+#undef EMACSLAYER_DOUBLE_BUFFERED
 
 @end /* EmacsLayer */
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-07-23 11:20                                                                                 ` Alan Third
@ 2023-07-23 13:01                                                                                   ` Aaron Jensen
  2023-07-25 14:47                                                                                     ` Aaron Jensen
  0 siblings, 1 reply; 71+ messages in thread
From: Aaron Jensen @ 2023-07-23 13:01 UTC (permalink / raw)
  To: Alan Third, Aaron Jensen, Kai Ma, 63187, Eli Zaretskii, Po Lu

On Sun, Jul 23, 2023 at 7:20 AM Alan Third <alan@idiocy.org> wrote:
>
> On Thu, Jul 20, 2023 at 10:02:53PM -0400, Aaron Jensen wrote:
> >
> > I've been using this for about a month now and have seen no artifacts:
> >
> > diff --git a/src/nsterm.m b/src/nsterm.m
> > index 78089906752..d23fb650ab8 100644
> > --- a/src/nsterm.m
> > +++ b/src/nsterm.m
> > @@ -2708,9 +2708,6 @@ Hide the window (X11 semantics)
> >      EmacsView *view = FRAME_NS_VIEW (f);
> >
> >      [view copyRect:srcRect to:dest];
> > -#ifdef NS_IMPL_COCOA
> > -    [view setNeedsDisplayInRect:destRect];
> > -#endif
> >    }
> >
> >    unblock_input ();
> > @@ -10435,7 +10432,7 @@ @implementation EmacsLayer
> >     cache.  If no free surfaces are found in the cache then a new one
> >     is created.  */
> >
> > -#define CACHE_MAX_SIZE 2
> > +#define CACHE_MAX_SIZE 1
> >
> >  - (id) initWithColorSpace: (CGColorSpaceRef)cs
> >  {
> > @@ -10621,7 +10618,7 @@ - (void) display
> >  {
> >    NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "[EmacsLayer display]");
> >
> > -  if (context)
> > +  if (context && context != [NSGraphicsContext currentContext])
> >      {
> >        [self releaseContext];
> >
> >
> > I'm not sure what the ramifications are for CACHE_MAX_SIZE 1 on slower
> > machines, but I don't notice any performance issues on my M1.
> >
> > Alan, what do you think we should do? Is there anything else you think
> > I should test for the next bit of time?
>
> I dug out my mac and built this and it still flickers with animated
> gifs. It's pretty easy to make happen, so it must be some hardware
> performance thing.
>
> Anyway, I've tried simplifying the double buffering code and put in
> all the wee changes I've thought about. Who knows if this will work
> any better...
>
> (It may be worth making the single/double buffering a run-time option
> as theoretically the single buffering will perform better, although
> always at the increased risk of tearing effects etc.)

Thanks, I'll try this one out. FYI there was a typo in a comment: doible

Aaron





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-07-23 13:01                                                                                   ` Aaron Jensen
@ 2023-07-25 14:47                                                                                     ` Aaron Jensen
  2023-07-25 15:45                                                                                       ` Eli Zaretskii
  0 siblings, 1 reply; 71+ messages in thread
From: Aaron Jensen @ 2023-07-25 14:47 UTC (permalink / raw)
  To: Alan Third, Aaron Jensen, Kai Ma, 63187, Eli Zaretskii, Po Lu

Would it be worth putting this in Emacs 29 since the RC is out? This
is likely better and so far there are no obvious issues.

Aaron

On Sun, Jul 23, 2023 at 9:01 AM Aaron Jensen <aaronjensen@gmail.com> wrote:
>
> On Sun, Jul 23, 2023 at 7:20 AM Alan Third <alan@idiocy.org> wrote:
> >
> > On Thu, Jul 20, 2023 at 10:02:53PM -0400, Aaron Jensen wrote:
> > >
> > > I've been using this for about a month now and have seen no artifacts:
> > >
> > > diff --git a/src/nsterm.m b/src/nsterm.m
> > > index 78089906752..d23fb650ab8 100644
> > > --- a/src/nsterm.m
> > > +++ b/src/nsterm.m
> > > @@ -2708,9 +2708,6 @@ Hide the window (X11 semantics)
> > >      EmacsView *view = FRAME_NS_VIEW (f);
> > >
> > >      [view copyRect:srcRect to:dest];
> > > -#ifdef NS_IMPL_COCOA
> > > -    [view setNeedsDisplayInRect:destRect];
> > > -#endif
> > >    }
> > >
> > >    unblock_input ();
> > > @@ -10435,7 +10432,7 @@ @implementation EmacsLayer
> > >     cache.  If no free surfaces are found in the cache then a new one
> > >     is created.  */
> > >
> > > -#define CACHE_MAX_SIZE 2
> > > +#define CACHE_MAX_SIZE 1
> > >
> > >  - (id) initWithColorSpace: (CGColorSpaceRef)cs
> > >  {
> > > @@ -10621,7 +10618,7 @@ - (void) display
> > >  {
> > >    NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "[EmacsLayer display]");
> > >
> > > -  if (context)
> > > +  if (context && context != [NSGraphicsContext currentContext])
> > >      {
> > >        [self releaseContext];
> > >
> > >
> > > I'm not sure what the ramifications are for CACHE_MAX_SIZE 1 on slower
> > > machines, but I don't notice any performance issues on my M1.
> > >
> > > Alan, what do you think we should do? Is there anything else you think
> > > I should test for the next bit of time?
> >
> > I dug out my mac and built this and it still flickers with animated
> > gifs. It's pretty easy to make happen, so it must be some hardware
> > performance thing.
> >
> > Anyway, I've tried simplifying the double buffering code and put in
> > all the wee changes I've thought about. Who knows if this will work
> > any better...
> >
> > (It may be worth making the single/double buffering a run-time option
> > as theoretically the single buffering will perform better, although
> > always at the increased risk of tearing effects etc.)
>
> Thanks, I'll try this one out. FYI there was a typo in a comment: doible
>
> Aaron





^ permalink raw reply	[flat|nested] 71+ messages in thread

* bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS
  2023-07-25 14:47                                                                                     ` Aaron Jensen
@ 2023-07-25 15:45                                                                                       ` Eli Zaretskii
  0 siblings, 0 replies; 71+ messages in thread
From: Eli Zaretskii @ 2023-07-25 15:45 UTC (permalink / raw)
  To: Aaron Jensen; +Cc: luangruo, alan, 63187, justksqsf, aaronjensen

> From: Aaron Jensen <aaronjensen@gmail.com>
> Date: Tue, 25 Jul 2023 10:47:53 -0400
> 
> Would it be worth putting this in Emacs 29 since the RC is out? This
> is likely better and so far there are no obvious issues.

Not yet, please wait until Emacs 29.1 is officially released.

Thanks.





^ permalink raw reply	[flat|nested] 71+ messages in thread

end of thread, other threads:[~2023-07-25 15:45 UTC | newest]

Thread overview: 71+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <m2fs8histt.fsf@gmail.com>
2023-04-30 10:33 ` bug#63187: 30.0.50; Tail of longer lines painted after end of nearby lines on macOS Eli Zaretskii
2023-04-30 10:46   ` Aaron Jensen
2023-04-30 13:25 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-04-30 14:25   ` Aaron Jensen
2023-04-30 14:42     ` Eli Zaretskii
2023-04-30 14:57       ` Aaron Jensen
2023-04-30 15:26         ` Eli Zaretskii
2023-04-30 16:48           ` Aaron Jensen
2023-04-30 19:04             ` Eli Zaretskii
2023-04-30 23:58     ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-05-01 12:40       ` Eli Zaretskii
2023-05-01 13:18         ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-05-01 13:25           ` Eli Zaretskii
2023-05-01 13:47             ` Aaron Jensen
2023-05-01 13:52               ` Eli Zaretskii
2023-05-01 13:55                 ` Aaron Jensen
2023-05-01 14:06                   ` Aaron Jensen
2023-05-09  3:07               ` Aaron Jensen
2023-05-09  5:39                 ` Eli Zaretskii
2023-05-13 13:54                   ` Eli Zaretskii
2023-05-13 14:23                     ` Aaron Jensen
2023-05-18 11:21                       ` Eli Zaretskii
2023-05-18 15:59                         ` Aaron Jensen
2023-06-08  5:40                           ` Kai Ma
2023-06-08  7:33                             ` Kai Ma
2023-06-08 12:51                               ` Alan Third
2023-06-08 13:42                                 ` Kai Ma
2023-06-08 14:57                                   ` Kai Ma
2023-06-08 17:22                                     ` Alan Third
2023-06-09  2:42                                       ` Kai Ma
2023-06-09  2:47                                         ` Aaron Jensen
2023-06-09  3:12                                           ` Kai Ma
2023-06-09 18:27                                             ` Alan Third
2023-06-09 18:46                                               ` Aaron Jensen
2023-06-09 20:00                                                 ` Alan Third
2023-06-12 13:04                                                   ` Aaron Jensen
2023-06-16  2:17                                                     ` Aaron Jensen
2023-06-19 15:46                                                       ` Aaron Jensen
2023-06-24  4:17                                                         ` Kai Ma
2023-06-24 13:34                                                           ` Aaron Jensen
2023-06-24 14:14                                                             ` Alan Third
2023-06-24 14:52                                                               ` Aaron Jensen
2023-06-24 15:08                                                                 ` Eli Zaretskii
2023-06-24 15:41                                                                 ` Alan Third
2023-06-24 16:05                                                                   ` Aaron Jensen
2023-06-24 21:29                                                                     ` Alan Third
2023-06-24 21:43                                                                       ` Aaron Jensen
2023-06-25 12:46                                                                         ` Alan Third
2023-06-25 17:07                                                                           ` Aaron Jensen
2023-06-25 18:17                                                                             ` Alan Third
2023-06-25 19:07                                                                               ` Aaron Jensen
2023-06-25 21:18                                                                                 ` Alan Third
2023-06-25 22:33                                                                                   ` Aaron Jensen
2023-06-26  7:27                                                                           ` Kai Ma
2023-06-28 19:53                                                                             ` Alan Third
2023-07-21  2:02                                                                               ` Aaron Jensen
2023-07-23 11:20                                                                                 ` Alan Third
2023-07-23 13:01                                                                                   ` Aaron Jensen
2023-07-25 14:47                                                                                     ` Aaron Jensen
2023-07-25 15:45                                                                                       ` Eli Zaretskii
2023-06-23  8:48                                                       ` Alan Third
2023-06-23 11:54                                                         ` Aaron Jensen
2023-05-01 17:26             ` Alan Third
2023-05-01 22:40               ` Aaron Jensen
2023-05-02 10:14                 ` Alan Third
2023-05-02 12:21                   ` Eli Zaretskii
2023-05-02 22:36                     ` Alan Third
2023-05-03  8:11                       ` Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-05-03 13:08                       ` Eli Zaretskii
2023-05-02  0:07               ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-05-02  0:32                 ` Aaron Jensen

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.