Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Synchronize updates with terminal clients #598

Closed
fuine opened this issue Jun 1, 2017 · 42 comments · Fixed by #4768
Closed

Synchronize updates with terminal clients #598

fuine opened this issue Jun 1, 2017 · 42 comments · Fixed by #4768

Comments

@fuine
Copy link

fuine commented Jun 1, 2017

Whenever I use <C-d> or <C-f> in vim while scrolling through a large file the screen flickers - it looks like for a moment the screen goes black and then the new content is redrawn, but it takes enough time to be noticeable and annoying. What's perhaps more interesting is that when I scroll half of the page via <C-d> only the bottom part of the window flickers, while top one does not. This issue is observed both inside and outside of tmux. Other terminal emulators don't have this issue.

  • My alacritty is built with cargo from sources, repo at commit d5ab418.
  • OS: Arch linux with kernel 4.10.13-1-ARCH
  • Graphics:
    • drivers: intel (unloaded: modesetting)
    • GLX Renderer: Mesa DRI Intel Ivybridge Mobile
    • GLX Version: 3.0 Mesa 17.1.0

I have also reproduced it on a different machine, with nvidia's GPU, alas low in terms of performance:

  • The same repository commit (d5ab418)
  • OS: Arch linux kernel 4.11.2-1-ARCH
  • Graphics:
    • driver: nvidia
    • GLX Renderer: Quadro 600/PCIe/SSE2
    • GLX Version: 4.5.0 NVIDIA 381.22
    • Direct Rendering: Yes

Do you have any idea what could be a problem here? This issue prevents me from using alacritty on a daily basis, because said flashing constantly distracts me.

This problem is also mentioned in #555

@jwilm
Copy link
Contributor

jwilm commented Jun 1, 2017

I've experienced this as well. This bug turns out to be an interesting problem! To see why we get the flickering and why it's difficult to resolve, consider how the read/parse/draw loop works:

  1. Some data arrives from the pty. The I/O thread reads this into a buffer.
  2. I/O thread locks the terminal state struct and runs that buffer through the parser.
  3. I/O thread registers that terminal is dirty and requests a draw.
  4. I/O thread releases lock on terminal state, blocks for another read.
  5. The render thread acquires lock, draws frame, and calls swap buffers.

The call at the end to swap buffers will block for ~17ms, and another frame cannot be drawn until it returns. The flickering happens because:

  1. Just enough data is read to cause the terminal to scroll
  2. frame is drawn
  3. more data arrives to fill in scrolled area, but it cannot be drawn until next frame

To me, this seems like a problem with terminal protocol. There's no framing, so we cannot know whether more data is coming or not.

Since we can't fix terminal protocol, we're left with doing something heuristical like trying to read with a short timeout. The trick with such a heuristic is providing sufficient time for related data to arrive without ever causing a frame skip.

If you or anyone else has other ideas on how to address this, or even ideas about how such a heuristic could work, I'm all ears. I've been thinking about this problem for a while and haven't come up with a solution I love.

@asilvadesigns
Copy link

asilvadesigns commented Jun 1, 2017

@fuine I'm using this plugin, and not experienced the flicker with it, might want to check it out: https://github.com/yuttie/comfortable-motion.vim. It's also pretty cool to use.

@fuine
Copy link
Author

fuine commented Jun 1, 2017

@jwilm thanks for the explanation, I will think about that problem. @asilvadesigns I've tried that plugin before but I don't like the CPU overhead that it brings to the table

@DarkDefender
Copy link
Contributor

DarkDefender commented Jun 1, 2017

There is also ongoing work in neovim to improve the terminal gui. For example:
neovim/neovim#6816

When using alacritty in neovim I notice a lot more cursor flickering than with other terminals. However, I think this is a problem with vim/neovim because there as been quite a few pull requests that tries to clean up the terminal ui code so that the cursor doesn't jump around so much when drawing updates. (Like this one: neovim/neovim#6366)

Speaking of which, @jwilm could there perhaps be a debug mode in alacritty where you can step though the screen updates? That is, you can freeze the screen and then step through the cell updates. I think it would be really helpful when debugging flickering issues in neovim (so you can see what neovim does when it redraws the cursor position for example).

@jdebp
Copy link

jdebp commented Jun 3, 2017

If your program operates as described, which I am taking on trust and have not looked at your program to check, then this does have its roots in your program.

Programs like vim and nvim collect screen output into in-memory buffers and flush it at certain points. (This is their own buffering system. Of course, full-screen programs that use standard I/O buffering instead, still do the same thing.) This results (as one can see from tools like truss, dtrace, and strace) in all output for things like scrolling operations or full screen redraws being sent often in one giant write() system call, often several KiB in one big lump.

Your best strategy in receiving this is to attempt to read and process all of that lump in one go before letting your renderer lock the terminal state for a vertical blanking interval. It is a falsehood to say that there's no way of doing this. There are three different approaches, each with their own tradeoffs:

  • For programs based upon kevent(), the EVFILT_READ events contains the number of bytes available to read in the data field of the event structure. It also signals EOF separately from this.
  • Making the pseudo-terminal master use non-blocking I/O tells read() to return if there are no more data. This somewhat complicates hangup processing as a side-effect, as read() returning zero bytes can mean either temporarily no more data or pseudo-terminal EOF.
  • There is a FIONREAD generic ioctl() available (at least) on the BSDs, on Solaris, and on Linux for terminal devices.

Instead of simply reading a portion, processing it whilst holding a lock, sending the other thread a shoulder-tap, then going back to look for another portion; make your program repeatedly read and process all portions until the master side of the pseudo-terminal is drained of output sent from the slave side, and only send the shoulder-tap when that is the case.

Or make your rendering side use a snapshot of the terminal state, and not lock the terminal state for the entire length of time that takes to render.

@Aaron1011
Copy link
Contributor

Instead of simply reading a portion, processing it whilst holding a lock, sending the other thread a shoulder-tap, then going back to look for another portion; make your program repeatedly read and process all portions until the master side of the pseudo-terminal is drained of output sent from the slave side, and only send the shoulder-tap when that is the case.

That's actually how alacritty currently works: https://github.com/jwilm/alacritty/blob/3c8514ba103d5d987d2269c421a3cc09e6784904/src/event_loop.rs#L259-L307

However, I think the idea of snapshotting the terminal state instead of holding a lock sound promising.

@jdebp
Copy link

jdebp commented Jun 18, 2017

No, that's not how that code works. That reads a portion, processes it whilst holding a lock, sends the other thread a shoulder-tap the first time around, and then releases the lock and goes back to look for another portion. That's not the same as sending the shoulder tap after the master has been drained; it is not the same as checking that there's no more to read before sending a shoulder tap.

Moreover, programs like nvim easily will cause multiple iterations of that loop with a single screen refresh, or scroll. A redraw of a mere 80×25 window with syntax colouring on, for example, can easily generate between 6KiB and 8KiB of output in 256-colour mode; more in true-colour mode. (I have managed to cut this down a bit for the nvim people, but this is what current release nvim does.)

Programs such as nvim can easily generate far more output in one lump for a single scroll/redraw than you are reading there in each iteration. And the initial clear screen or scroll command that comes early in the output leaves part of the terminal blank until they re-draw what is on it later in the output.

So the problem behaviour is as described. You are starting the render, locking the terminal state for a vertical blanking interval, when there's more than half of the nvim refresh/scroll output yet to be read from the pseudo-terminal and processed and half of the terminal is temporarily blank. The fix is to process it all before rendering. Then you won't get tearing like this.

@jwilm
Copy link
Contributor

jwilm commented Jul 2, 2017

@jdebp thanks for all the feedback. I'm working on this right now, and I think the way to go is just reading until getting an EWOULDBLOCK.

For programs based upon kevent(), the EVFILT_READ ...

This sounds great, but there's no equivalent for epoll.

There is a FIONREAD generic ioctl() ...

Doesn't work in my testing on macOS. Upon the event loop signaling read readiness, the ioctl just returns 0.

Making the pseudo-terminal master use non-blocking I/O tells read() to return if there are no more data.

I've been experimenting with this approach locally with good results. Note that nvim sometimes sends another tiny chunk after the primary chunk when paging. Here's some logs showing bytes processed on each iteration. When WouldBlock is encountered, the renderer is notified and the terminal lock released.

==== enter loop ====
got 1024
got 1024
got 1024
got 1024
got 1024
got 1024
got 1024
got 1024
got 1024
got 1024
got 1024
got 635
got 25
WouldBlock
processed: 11924
==== enter loop ====
got 75
got 81
WouldBlock
processed: 156

I'll follow up again here once there's a patch for others to try.

@jwilm
Copy link
Contributor

jwilm commented Jul 4, 2017

Please see #650 for the patch I promised. Although it seems to resolve the issue with neovim, it doesn't have any affect with vim 7.4 (haven't tested with 8) since write batching was apparently added in neovim.

I'm looking for some specific feedback on the patch. It seems that, on my system, this patch causes some hiccups where a frame is skipped, or input isn't delivered in a timely fashion. Could have been my imagination too. Would love to hear how it works for others!

@asilvadesigns
Copy link

@jwilm no flicker in neovim, or neovim in tmux!!

@fuine
Copy link
Author

fuine commented Jul 11, 2017

@jwilm I get very occasional flickers on ctrl-f with neovim and the screen still flickers using neovim in tmux

@melonmanchan
Copy link

melonmanchan commented Jul 23, 2017

FWIW, applying #650 on top of the current master helped with the flickering issues I previously had with regular vim 8.0 inside tmux 2.5 when scrolling files up and down. There's still some flickering, but the patch helped a lot.

> vim --version
VIM - Vi IMproved 8.0 (2016 Sep 12, compiled Jul 22 2017 14:20:33)
MacOS X (unix) version
Included patches: 1-741
Compiled by Homebrew
Huge version without GUI.  Features included (+) or not (-):
+acl             +file_in_path    +mouse_sgr       +tag_old_static
+arabic          +find_in_path    -mouse_sysmouse  -tag_any_white
+autocmd         +float           +mouse_urxvt     -tcl
-balloon_eval    +folding         +mouse_xterm     +termguicolors
-browse          -footer          +multi_byte      -terminal
++builtin_terms  +fork()          +multi_lang      +terminfo
+byte_offset     -gettext         -mzscheme        +termresponse
+channel         -hangul_input    +netbeans_intg   +textobjects
+cindent         +iconv           +num64           +timers
-clientserver    +insert_expand   +packages        +title
+clipboard       +job             +path_extra      -toolbar
+cmdline_compl   +jumplist        +perl            +user_commands
+cmdline_hist    +keymap          +persistent_undo +vertsplit
+cmdline_info    +lambda          +postscript      +virtualedit
+comments        +langmap         +printer         +visual
+conceal         +libcall         +profile         +visualextra
+cryptv          +linebreak       +python          +viminfo
+cscope          +lispindent      -python3         +vreplace
+cursorbind      +listcmds        +quickfix        +wildignore
+cursorshape     +localmap        +reltime         +wildmenu
+dialog_con      +lua             +rightleft       +windows
+diff            +menu            +ruby            +writebackup
+digraphs        +mksession       +scrollbind      -X11
-dnd             +modify_fname    +signs           -xfontset
-ebcdic          +mouse           +smartindent     -xim
+emacs_tags      -mouseshape      +startuptime     -xpm
+eval            +mouse_dec       +statusline      -xsmp
+ex_extra        -mouse_gpm       -sun_workshop    -xterm_clipboard
+extra_search    -mouse_jsbterm   +syntax          -xterm_save
+farsi           +mouse_netterm   +tag_binary
   system vimrc file: "$VIM/vimrc"
     user vimrc file: "$HOME/.vimrc"
 2nd user vimrc file: "~/.vim/vimrc"
      user exrc file: "$HOME/.exrc"
       defaults file: "$VIMRUNTIME/defaults.vim"
  fall-back for $VIM: "/usr/local/share/vim"
Compilation: clang -c -I. -Iproto -DHAVE_CONFIG_H   -DMACOS_X_UNIX  -g -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1
Linking: clang   -L. -fstack-protector -L/usr/local/lib -L/usr/local/opt/libyaml/lib -L/usr/local/opt/openssl/lib -L/usr/local/opt/readline/lib  -L/usr/local/lib -o vim        -lncurses -liconv -framework Cocoa  -L/usr/local/lib -llua -mmacosx-version-min=10.12 -fstack-protector-strong -L/usr/local/lib  -L/usr/local/Cellar/perl/5.26.0/lib/perl5/5.26.0/darwin-thread-multi-2level/CORE -lperl -lm -lutil -lc -F/usr/local/opt/python/Frameworks -framework Python   -lruby.2.4.1 -lobjc

@dvergeylen
Copy link

dvergeylen commented Nov 11, 2018

I am not experiencing any more flickers while scrolling since #1403 merge. Can anyone confirm this?

@chrisduerr
Copy link
Member

@fuine Has this issue been resolved for you with the latest master?

@chrisduerr
Copy link
Member

Closing as resolved by #1403. Should this issue still occur, please let me know and I'll re-open.

@pr4th4m
Copy link

pr4th4m commented Apr 9, 2019

Still experiencing this

Details:
OS: MacOS Mojave
Alacritty: 0.3.0
Nvim: 0.3.4
Tmux: 2.8

NOTE: Alacritty flickers without tmux as well.

AlacrittyFlickers

@chrisduerr chrisduerr reopened this Apr 9, 2019
@tuannvm
Copy link

tuannvm commented May 6, 2019

I'm on MacOS, this fix the flickering issue without tmux:

startup_mode: SimpleFullscreen

@chrisduerr
Copy link
Member

You only need to render that frame before the next page flip, it doesn't matter when you render it (between the last flip and the next). Yes?

No? Rendering a frame does not take a fixed amount of time, it depends on vsync which is its purpose. We might have approximately the same amount of time between frames, but even that would only be true if every frame was dirty. While it might be possible to delay the rendering a bit, up to the point where vsync blocks for basically zero seconds, this is not reliable, hard to determine consistently and would only give an extremely small timeframe that likely isn't going to help much.

XTerm's 25ms are massive for example. No matter how far away you are from the next vsync, that'll cause troubles. Which means frames are actually delayed, causing increased input latency.

Not working, no.

Not working, yes. No matter how long you delay, it will never stop you from an application pushing new stuff right when you decide to render.

The absolutely most advantageous and preferred one, yes. Only one, no.

Delaying rendering is not a solution. It's a hack that should help users perceive the problem less in some scenarios. The issue persists, it's just less prominent. That is not what a solution is.

The assumption is that the writes of an update comes in a very quick succession.

Just like the assumption that all connected data will be done in a single write. Completely pointless if you have to make assumptions about a client you have no control over.

Just that XTerm also has this synchronization problem since there were comments here suggestion only "fast" terminals have it.

The suggestion is just that fast terminals make it more obvious, which is true based on my testing.

@dnkl
Copy link
Contributor

dnkl commented Feb 5, 2020

No? Rendering a frame does not take a fixed amount of time, it depends on vsync which is its purpose.

Obviously, if you include the wait time caused by vsync. But that's an implementation artifact. Actual rendering is more or less fixed. At least if we for simplicity assume for example a full window with no empty cells.

While it might be possible to delay the rendering a bit, up to the point where vsync blocks for basically zero seconds, this is not reliable, hard to determine consistently and would only give an extremely small timeframe that likely isn't going to help much.

I did say it was tricky. My CPU-based terminal renders a full window update in ~5ms on a laptop without the CPU running in power saving mode. That means I have ~11ms to play with. That's not a "small" timeframe. Yes, it is unreliable. With the presentation protocol on Wayland, one can do better.

Not working, yes. No matter how long you delay, it will never stop you from an application pushing new stuff right when you decide to render.

Of course. It's a mitigation. Not a solution. While it's not "working", in theory, it actually does work in practice. But if it works in all the applications I use, then it is working. For me.

Delaying rendering is not a solution. It's a hack that should help users perceive the problem less in some scenarios. The issue persists, it's just less prominent. That is not what a solution is.

Yes, it's a hack. And I'll agree to not calling it a solution.

Just like the assumption that all connected data will be done in a single write. Completely pointless if you have to make assumptions about a client you have no control over.

Except that in practice, clients aren't malicious entities trying to break your terminal. This isn't about providing a 100% fool proof, always working solution, but, yes, to hide the problem from the users. A temporary workaround until clients, and terminals, implement synchronized updates.

The suggestion is just that fast terminals make it more obvious, which is true based on my testing.

Did you check if they implement workarounds?

@chrisduerr
Copy link
Member

My CPU-based terminal renders a full window update in ~5ms

That highly depends on the content of your full window and its size. Worst case you have basically no time to do any additional waiting and then just spend valuable resources that could have been used to actually improve the performance itself. That just doesn't align with Alacritty's goals.

I'm fully willing to implement the escape as soon as it's standardized on though and I'm perfectly happy driving that forwards. I've got only limited time and the time I have I'd rather spend bothering people to drive forwards a proper solution rather than implementing a hack that doesn't work, goes against the project's goals and has only negative impacts on people that do not experience these issues.

Did you check if they implement workarounds?

I tested Alacritty against itself. So yeah, pretty sure it doesn't implement any hacks for this.

@Xyene
Copy link

Xyene commented Mar 23, 2020

To save a future reader/searcher of GitHub issues some time (and to save the maintainers having to answer the same thing twice ;-)...

This issue makes most programs using ncurses susceptible to flickering.

I did a bit of digging into ncurses itself to find out why this is the case; links below.

By default, ncurses buffers up changes made to the screen, and writes out only the difference between the last screen and the current one on a call to refresh(3). It does this with multiple write(2) calls that change the cursor position, satisfying the conditions for this issue.

A program can ask ncurses to not do this diffing, and instead redraw the entire screen, using clearok(3). Anecdotally, though, this'll still lead to multiple write(2) calls. I tried inserting a call to clearok(3) right before calling refresh(3), and ncurses redrew the entire screen with dozens of calls to write(2) (one per non-empty line).

That is to say, there is no obvious workaround here short of patching/refactoring ncurses itself to use a big enough buffer to perform the entire update in one go.

@pbartyik
Copy link

pbartyik commented Jul 9, 2020

That is to say, there is no obvious workaround here short of patching/refactoring ncurses itself to use a big enough buffer to perform the entire update in one go.

In that case can this be reported to ncurses?

@linde12
Copy link

linde12 commented Oct 5, 2020

Chiming in here, please do tell if you wan't me to provide any sorts of information! It's still happening for me (running alacritty 0.5 on Windows)

Same behavior with scrolling in fzf as in #3819 (with and without tmux, doesn't matter) but it also happens when typing (filtering) in fzf. Highlighting things in vim with * causes the cursor to disappear completely and generally just moving with hjkl causes ghost cursors to appear (for me) both in bottom bar and in buffer/tab bar.

Another interesting problem occurs when running tmux with 2 windows, one containing vim and one just a terminal running yes. This causes cursor flickering in vim (cause yes is spamming the other window with y ?) and whenever you type in vim cursor flickering also occurs in the window running yes. This is a minor annoyance (similar to the fzf issue), but even more annoying is that vim is extremely slow during this time, compared to a traditional terminal emulator which runs fine without flickering. Now, of course i don't sit in vim all day with yes running in another tmux window, but the same behavior for applications producing any kind of output (e.g. logs or compilations etc.)

This, unfortunately, makes the terminal emulator borderline to unusable, as a daily driver, to me :-(

I'm not sure if the disappearing cursor on highlight is related, or if it's a separate issue (let me know and i'll create one with more info)

chrisduerr added a commit to chrisduerr/alacritty that referenced this issue Jan 18, 2021
This adds support for the synchronized updates escape sequence
(`DCS = 1 s`/`DCS = 2 s`). This allows terminal applications to freeze
Alacritty's rendering temporarily to prevent excessive redraws and
flickering.

There seem to be two possible approaches for implementing this escape
sequence. Some terminal emulators like Kitty have an internal escape
sequence buffer which reads every byte, then upon receiving the freezing
escape they stop reading from this buffer and keep going when the
terminal is unfrozen or the buffer is full.

The alternative implementation, which this patch has taken, is to freeze
the rendering completely, while still updating the grid state in the
background.

The approach taken in this patch has the advantage that the number of
bytes written can be optimally compressed, there's no need for an
additional buffer and no risk of running out of buffer space and having
to end synchronization prematurely. On the other hand since only the
visible part of the terminal can be frozen because of performance and
memory limitations, many user interactions with the terminal need to
forcefully interrupt the synchronized update.

While the advantages and disadvantages seem somewhat on par for both
approaches and most limitations shouldn't be noticeable with the
synchronized updates under normal operating conditions, the rendering
freeze was much easier to implement efficiently in Alacritty.

Since this is an escape sequence, all the rendering freezes must be
handled by `alacritty_terminal` internally. Because of this a new
intermediate `RenderableContent` struct has been introduced which
contains all the information necessary for rendering the visible
terminal region. This single interface allows for decoupling the
integration between terminal and rendering and at the same time makes it
possible to clone the entire structure to preserve during a freeze.

Fixes alacritty#598.
chrisduerr added a commit to chrisduerr/alacritty that referenced this issue Jan 19, 2021
This adds support for the synchronized updates escape sequence
(`DCS = 1 s ST`/`DCS = 2 s ST`). This allows terminal applications to
freeze Alacritty's rendering temporarily to prevent excessive redraws
and flickering.

There seem to be two possible approaches for implementing this escape
sequence. Some terminal emulators like Kitty have an internal escape
sequence buffer which reads every byte, then upon receiving the freezing
escape they stop reading from this buffer and keep going when the
terminal is unfrozen or the buffer is full.

The alternative implementation, which this patch has taken, is to freeze
the rendering completely, while still updating the grid state in the
background.

The approach taken in this patch has the advantage that the number of
bytes written can be optimally compressed, there's no need for an
additional buffer and no risk of running out of buffer space and having
to end synchronization prematurely. On the other hand since only the
visible part of the terminal can be frozen because of performance and
memory limitations, many user interactions with the terminal need to
forcefully interrupt the synchronized update.

While the advantages and disadvantages seem somewhat on par for both
approaches and most limitations shouldn't be noticeable with the
synchronized updates under normal operating conditions, the rendering
freeze was much easier to implement efficiently in Alacritty.

Since this is an escape sequence, all the rendering freezes must be
handled by `alacritty_terminal` internally. Because of this a new
intermediate `RenderableContent` struct has been introduced which
contains all the information necessary for rendering the visible
terminal region. This single interface allows for decoupling the
integration between terminal and rendering and at the same time makes it
possible to clone the entire structure to preserve during a freeze.

Fixes alacritty#598.
chrisduerr added a commit to chrisduerr/alacritty that referenced this issue Feb 5, 2021
This implements support for temporarily freezing the terminal grid to
prevent rendering of incomplete frames.

This can be triggered using the escapes `DCS = 1 s` (start) and
`DCS = 2 s` (end).

The synchronization is implemented by forwarding all received PTY bytes
to a 2 MiB buffer. This should allow updating the entire grid even if it
is fairly dense. Unfortunately this also means that another branch is
necessary in Alacritty's parser which does have a slight performance
impact.

In a previous version the freezing was implemented by caching the
renderable grid state whenever a synchronized update is started. While
this strategy makes it possible to implement this without any
performance impact without synchronized updates, a significant
performance overhead is introduced whenever a synchronized update is
started. Since this can happen thousands of times per frame, it is not a
feasible solution.

While it would be possible to render at most one synchronized update per
frame, it is possible that another synchronized update comes in at any
time and stays active for an extended period. As a result the state
visible before the long synchronization would be the first received
update per frame, not the last, which could lead to the user missing
important information during the long freezing interval.

Fixes alacritty#598.
chrisduerr added a commit to chrisduerr/alacritty that referenced this issue Feb 5, 2021
This implements support for temporarily freezing the terminal grid to
prevent rendering of incomplete frames.

This can be triggered using the escapes `DCS = 1 s` (start) and
`DCS = 2 s` (end).

The synchronization is implemented by forwarding all received PTY bytes
to a 2 MiB buffer. This should allow updating the entire grid even if it
is fairly dense. Unfortunately this also means that another branch is
necessary in Alacritty's parser which does have a slight performance
impact.

In a previous version the freezing was implemented by caching the
renderable grid state whenever a synchronized update is started. While
this strategy makes it possible to implement this without any
performance impact without synchronized updates, a significant
performance overhead is introduced whenever a synchronized update is
started. Since this can happen thousands of times per frame, it is not a
feasible solution.

While it would be possible to render at most one synchronized update per
frame, it is possible that another synchronized update comes in at any
time and stays active for an extended period. As a result the state
visible before the long synchronization would be the first received
update per frame, not the last, which could lead to the user missing
important information during the long freezing interval.

Fixes alacritty#598.
chrisduerr added a commit to chrisduerr/alacritty that referenced this issue Feb 5, 2021
This implements support for temporarily freezing the terminal grid to
prevent rendering of incomplete frames.

This can be triggered using the escapes `DCS = 1 s` (start) and
`DCS = 2 s` (end).

The synchronization is implemented by forwarding all received PTY bytes
to a 2 MiB buffer. This should allow updating the entire grid even if it
is fairly dense. Unfortunately this also means that another branch is
necessary in Alacritty's parser which does have a slight performance
impact.

In a previous version the freezing was implemented by caching the
renderable grid state whenever a synchronized update is started. While
this strategy makes it possible to implement this without any
performance impact without synchronized updates, a significant
performance overhead is introduced whenever a synchronized update is
started. Since this can happen thousands of times per frame, it is not a
feasible solution.

While it would be possible to render at most one synchronized update per
frame, it is possible that another synchronized update comes in at any
time and stays active for an extended period. As a result the state
visible before the long synchronization would be the first received
update per frame, not the last, which could lead to the user missing
important information during the long freezing interval.

Fixes alacritty#598.
chrisduerr added a commit to chrisduerr/alacritty that referenced this issue Feb 14, 2021
This implements support for temporarily freezing the terminal grid to
prevent rendering of incomplete frames.

This can be triggered using the escapes `DCS = 1 s` (start) and
`DCS = 2 s` (end).

The synchronization is implemented by forwarding all received PTY bytes
to a 2 MiB buffer. This should allow updating the entire grid even if it
is fairly dense. Unfortunately this also means that another branch is
necessary in Alacritty's parser which does have a slight performance
impact.

In a previous version the freezing was implemented by caching the
renderable grid state whenever a synchronized update is started. While
this strategy makes it possible to implement this without any
performance impact without synchronized updates, a significant
performance overhead is introduced whenever a synchronized update is
started. Since this can happen thousands of times per frame, it is not a
feasible solution.

While it would be possible to render at most one synchronized update per
frame, it is possible that another synchronized update comes in at any
time and stays active for an extended period. As a result the state
visible before the long synchronization would be the first received
update per frame, not the last, which could lead to the user missing
important information during the long freezing interval.

Fixes alacritty#598.
chrisduerr added a commit to chrisduerr/alacritty that referenced this issue Feb 17, 2021
This implements support for temporarily freezing the terminal grid to
prevent rendering of incomplete frames.

This can be triggered using the escapes `DCS = 1 s` (start) and
`DCS = 2 s` (end).

The synchronization is implemented by forwarding all received PTY bytes
to a 2 MiB buffer. This should allow updating the entire grid even if it
is fairly dense. Unfortunately this also means that another branch is
necessary in Alacritty's parser which does have a slight performance
impact.

In a previous version the freezing was implemented by caching the
renderable grid state whenever a synchronized update is started. While
this strategy makes it possible to implement this without any
performance impact without synchronized updates, a significant
performance overhead is introduced whenever a synchronized update is
started. Since this can happen thousands of times per frame, it is not a
feasible solution.

While it would be possible to render at most one synchronized update per
frame, it is possible that another synchronized update comes in at any
time and stays active for an extended period. As a result the state
visible before the long synchronization would be the first received
update per frame, not the last, which could lead to the user missing
important information during the long freezing interval.

Fixes alacritty#598.
chrisduerr added a commit to chrisduerr/alacritty that referenced this issue Feb 20, 2021
This implements support for temporarily freezing the terminal grid to
prevent rendering of incomplete frames.

This can be triggered using the escapes `DCS = 1 s` (start) and
`DCS = 2 s` (end).

The synchronization is implemented by forwarding all received PTY bytes
to a 2 MiB buffer. This should allow updating the entire grid even if it
is fairly dense. Unfortunately this also means that another branch is
necessary in Alacritty's parser which does have a slight performance
impact.

In a previous version the freezing was implemented by caching the
renderable grid state whenever a synchronized update is started. While
this strategy makes it possible to implement this without any
performance impact without synchronized updates, a significant
performance overhead is introduced whenever a synchronized update is
started. Since this can happen thousands of times per frame, it is not a
feasible solution.

While it would be possible to render at most one synchronized update per
frame, it is possible that another synchronized update comes in at any
time and stays active for an extended period. As a result the state
visible before the long synchronization would be the first received
update per frame, not the last, which could lead to the user missing
important information during the long freezing interval.

Fixes alacritty#598.
chrisduerr added a commit to chrisduerr/alacritty that referenced this issue Feb 23, 2021
This implements support for temporarily freezing the terminal grid to
prevent rendering of incomplete frames.

This can be triggered using the escapes `DCS = 1 s` (start) and
`DCS = 2 s` (end).

The synchronization is implemented by forwarding all received PTY bytes
to a 2 MiB buffer. This should allow updating the entire grid even if it
is fairly dense. Unfortunately this also means that another branch is
necessary in Alacritty's parser which does have a slight performance
impact.

In a previous version the freezing was implemented by caching the
renderable grid state whenever a synchronized update is started. While
this strategy makes it possible to implement this without any
performance impact without synchronized updates, a significant
performance overhead is introduced whenever a synchronized update is
started. Since this can happen thousands of times per frame, it is not a
feasible solution.

While it would be possible to render at most one synchronized update per
frame, it is possible that another synchronized update comes in at any
time and stays active for an extended period. As a result the state
visible before the long synchronization would be the first received
update per frame, not the last, which could lead to the user missing
important information during the long freezing interval.

Fixes alacritty#598.
chrisduerr added a commit to chrisduerr/alacritty that referenced this issue Feb 23, 2021
This implements support for temporarily freezing the terminal grid to
prevent rendering of incomplete frames.

This can be triggered using the escapes `DCS = 1 s` (start) and
`DCS = 2 s` (end).

The synchronization is implemented by forwarding all received PTY bytes
to a 2 MiB buffer. This should allow updating the entire grid even if it
is fairly dense. Unfortunately this also means that another branch is
necessary in Alacritty's parser which does have a slight performance
impact.

In a previous version the freezing was implemented by caching the
renderable grid state whenever a synchronized update is started. While
this strategy makes it possible to implement this without any
performance impact without synchronized updates, a significant
performance overhead is introduced whenever a synchronized update is
started. Since this can happen thousands of times per frame, it is not a
feasible solution.

While it would be possible to render at most one synchronized update per
frame, it is possible that another synchronized update comes in at any
time and stays active for an extended period. As a result the state
visible before the long synchronization would be the first received
update per frame, not the last, which could lead to the user missing
important information during the long freezing interval.

Fixes alacritty#598.
chrisduerr added a commit that referenced this issue Feb 24, 2021
This implements support for temporarily freezing the terminal grid to
prevent rendering of incomplete frames.

This can be triggered using the escapes `DCS = 1 s` (start) and
`DCS = 2 s` (end).

The synchronization is implemented by forwarding all received PTY bytes
to a 2 MiB buffer. This should allow updating the entire grid even if it
is fairly dense. Unfortunately this also means that another branch is
necessary in Alacritty's parser which does have a slight performance
impact.

In a previous version the freezing was implemented by caching the
renderable grid state whenever a synchronized update is started. While
this strategy makes it possible to implement this without any
performance impact without synchronized updates, a significant
performance overhead is introduced whenever a synchronized update is
started. Since this can happen thousands of times per frame, it is not a
feasible solution.

While it would be possible to render at most one synchronized update per
frame, it is possible that another synchronized update comes in at any
time and stays active for an extended period. As a result the state
visible before the long synchronization would be the first received
update per frame, not the last, which could lead to the user missing
important information during the long freezing interval.

Fixes #598.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging a pull request may close this issue.