all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Daniel Colascione <dancol@dancol.org>
To: Eli Zaretskii <eliz@gnu.org>
Cc: emacs-devel@gnu.org
Subject: Re: RFC: flicker-free double-buffered Emacs under X11
Date: Fri, 21 Oct 2016 11:27:29 -0700	[thread overview]
Message-ID: <r025zilxsgku.fsf@dancol.org> (raw)
In-Reply-To: <831sz9sime.fsf@gnu.org> (Eli Zaretskii's message of "Fri, 21 Oct 2016 20:43:21 +0300")

Eli Zaretskii <eliz@gnu.org> writes:

>> Cc: emacs-devel@gnu.org
>> From: Daniel Colascione <dancol@dancol.org>
>> Date: Fri, 21 Oct 2016 04:04:21 -0700
>> 
>>  > Also, the call to font_flush_frame_caches is unconditional, although
>>  > only one font back-end supports it.  That seems to incur a gratuitous
>>  > overhead of a function call for the other font back-ends.
>> 
>> We're testing whether the hook function is non-NULL before calling into 
>> it, so only that one backend gets the call. In any case, the overhead is 
>> trivial --- it's one indirect function call compared to all of 
>> redisplay. (Every call into a shared library is the same indirect jump.)
>
> The code is more clear with the test before the call, otherwise the
> code reader needs to look in the hook to understand when it's a no-op.

But the test (of whether the hook exists) _is_ before the call. What are
you proposing?

    some_backend_needs_flush = False
    for backend in font_back_ends:
      if has_flush_hook(backend):
        some_back_end_needs_flush = True
    if some_back_end_needs_flush:
      for backend in font_back_ends:
        if has_flush_hook(backend):
          backend.flush_hook()
    
That's silly. Can you elaborate on what you consider a cleaner approach?

> So I'd prefer to have the test outside of the call, or even outside of
> the loop.

See below. I don't think that giving font back-ends an opportunity to do
_something_ in response to a frame being garbaged in certain ways is a
bad thing.

>>  >> +  FOR_EACH_FRAME (tail, frame)
>>  >> +    {
>>  >> +      struct frame *f = XFRAME (frame);
>>  >> +      if (FRAME_TERMINAL (f)->redisplay_end_hook)
>>  >> +        (*FRAME_TERMINAL (f)->redisplay_end_hook) (f);
>>  >> +    }
>>  >
>>  > This will call the hook for each frame, every redisplay cycle.  By
>>  > contrast, redisplay_internal many times updates only the selected
>>  > window of the selected frame.  Is calling the hook for all the frames
>>  > really needed, or should we only call it for the selected frame in the
>>  > latter case, or maybe just for frames that got updated?
>> 
>> The hook only does something in the case where someone called update_end 
>> and we demurred on actually flipping the buffer because we knew we were 
>> in redisplay and would be getting redisplay_end_hook shortly. That is, 
>> if we update only one frame, we're only going to do one buffer flip.
>
> That might be so, but what you say above is in no way apparent from
> looking at the code.  IME, it is very important to have the idea when
> something is being done and when not just by looking at the code in
> redisplay_internal; having to find that out by realizing that some
> flag is set in update_end and then tested in the hook makes the code
> more subtle and its maintenance harder.  It's not like keeping this
> detail from redisplay_internal makes this detail local to some
> functions, or somesuch, so there's really no reason to conceal it,
> IMO.

This sentiment strikes me as being analogous to the old "no use of hooks
in Emacs internals" line --- yet we have facilities like syntax-ppss
that rely on hooks in core, and it's worked out fine.

We need to do a buffer flip at the end of redisplay for each frame on
which update_end was called during redisplay.  If someone calls
update_end _outside_ redisplay, we should do a buffer flip
immediately. The code I've sent is the cleanest way of implementing this
model short of changing how update_begin and update_end work.

I think thhat what you're proposing is a layering violation. It will
make maintenance harder. The only facility that cares about the
has-a-frame-been-updated state is the X11 double-buffered back-end, so
making xdisp track this state makes everything more complicated,
especially because xdisp already has a "needs redisplay" flag and
shouldn't need to keep track of a separate "needs buffer flip" flag.
It shouldn't have to care. That's not its job.

>> Or are you worried about the function call overhead? That, as I 
>> mentioned above, is trivial.
>
> No, I worry about maintainability of the display code and about
> lowering the risk of bugs introduced due to such subtleties.
>

I'm also worried about maintainability: that's why I don't want to make
redisplay_internal any more of a big ball of mud than it already is. I
think it's cleaner to have xterm keep track of state only xterm needs.

>>  > Also, should
>>  > we distinguish between visible and iconified frames?
>> 
>> If we do, we should do it in the code that performs the updates, not the 
>> code (the snippet immediately above) that publishes the updates we've 
>> already done.
>
> See above: I don't like such dependencies and find them in general an
> obstacle to understanding the overall logic of the display code.  I
> don't mind adding a test in update_frame and friends, but that
> shouldn't prevent us from having a similar (or even identical) test
> here.

What dependency? You're proposing adding a lot of complexity to the loop
that calls redisplay_end_hook, and I still have no idea what this
complexity is supposed to accomplish.

>
>>  >> +#ifdef HAVE_XDBE
>>  >> +  if (FRAME_DISPLAY_INFO (f)->supports_xdbe)
>>  >> +    {
>>  >> +      /* If allocating a back buffer fails, just use single-buffered
>>  >> +         rendering.  */
>>  >> +      x_sync (f);
>>  >> +      x_catch_errors (FRAME_X_DISPLAY (f));
>>  >> +      FRAME_X_DRAWABLE (f) = XdbeAllocateBackBufferName (
>>  >> +        FRAME_X_DISPLAY (f),
>>  >> +        FRAME_X_WINDOW (f),
>>  >> +        XdbeCopied);
>>  >> +      if (x_had_errors_p (FRAME_X_DISPLAY (f)))
>>  >> +        FRAME_X_DRAWABLE (f) = FRAME_X_WINDOW (f);
>>  >
>>  > Shouldn't we turn off the supports_xdbe flag in the case of failure?
>> 
>> supports_xdbe is whether XDBE is supported on a connection at all. What 
>> if XdbeAllocateBackBufferName fails transiently?
>
> How can it fail transiently?  And why turning off supports_xdbe in
> that case would mean trouble?

It's an allocation. Allocations can fail. And XDBE isn't guaranteed to
work for all visuals.

>
>>  >> +#ifdef HAVE_XDBE
>>  >> +  dpyinfo->supports_xdbe = false;
>>  >> +    {
>>  >> +      int xdbe_major;
>>  >> +      int xdbe_minor;
>>  >> +      if (XdbeQueryExtension (dpyinfo->display, &xdbe_major, 
>> &xdbe_minor))
>>  >> +        dpyinfo->supports_xdbe = true;
>>  >> +    }
>>  >> +#endif
>>  >
>>  > No need for braces here, since we now require a C99 compiler.
>> 
>> If we put xdbe_major and xdbe_minor at function level, the names leak 
>> into function scope. With braces, they exist only around the call to 
>> XdbeQueryExtension
>
> We use that in many other places, so I think these precautions are
> misguided and generally make our coding style less apparent.

Fine.



  reply	other threads:[~2016-10-21 18:27 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-10-21  1:32 RFC: flicker-free double-buffered Emacs under X11 Daniel Colascione
2016-10-21  2:27 ` Lars Ingebrigtsen
2016-10-21  2:31   ` Daniel Colascione
2016-10-21  3:24 ` Óscar Fuentes
2016-10-21  3:31   ` Clément Pit--Claudel
2016-10-21  3:41     ` Óscar Fuentes
2016-10-21  3:50       ` Clément Pit--Claudel
2016-10-21  8:23     ` Andreas Schwab
2016-10-21  8:25       ` Andreas Schwab
2016-10-21  3:56 ` Clément Pit--Claudel
2016-10-21  8:49 ` Eli Zaretskii
2016-10-21 11:04   ` Daniel Colascione
2016-10-21 17:43     ` Eli Zaretskii
2016-10-21 18:27       ` Daniel Colascione [this message]
2016-10-21 19:27         ` Eli Zaretskii
2016-10-23 20:51           ` Daniel Colascione
2016-10-24  8:05             ` Eli Zaretskii
2016-10-24 18:43               ` Ken Raeburn
2016-10-27 19:06               ` dancol
2016-10-27 19:36                 ` Eli Zaretskii
     [not found]                   ` <db81befd-7a72-58d9-b7a8-107df89bcab3@dancol.org>
2016-10-27 19:56                     ` Daniel Colascione
2016-10-28  6:31                       ` Eli Zaretskii
2016-10-27 22:18                 ` Paul Eggert
2016-10-27 22:46                   ` Clément Pit--Claudel
2016-10-28 13:14                     ` Stefan Monnier
2016-11-01  0:03                       ` Dmitry Gutov
2016-10-27 23:10                   ` Daniel Colascione
2016-10-28  2:07                     ` Paul Eggert
2016-10-28  7:19                       ` Eli Zaretskii
2016-11-06  3:51                         ` Paul Eggert
2016-11-06 15:46                           ` Eli Zaretskii

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=r025zilxsgku.fsf@dancol.org \
    --to=dancol@dancol.org \
    --cc=eliz@gnu.org \
    --cc=emacs-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.