Subject: Re: bug#17124: 24.3.50; Occasional Extremely Slow Redraws in OSX Emacs

From: Jan Djärv <[email-masked]>
Date: Fri, 27 Jun 2014 19:13:00 +0200

Hello.

27 jun 2014 kl. 15:37 skrev Eli Zaretskii <[email-masked]>:

>> From: Jan Djärv <[email-masked]>
>> Date: Fri, 27 Jun 2014 12:44:58 +0200
>> Cc: Eli Zaretskii <[email-masked]>,
>> [email-masked]
>> 
>> With the "shake the divider" recepie (see below), redisplay_internal is called more than 30 times per second.  On an old computer (end of 2008) I get about 37 times per second.
>> But each redisplay results in multiple draw_begin/end, so for drawing, it is more than 37 times per second.
> 
> Does it help to set redisplay-dont-pause to nil?

The "shake the divider" case becomes much worse, lots of flickering and incomplete text.
Wheter it prevents the slow redraws in real usage is hard to tell.  It is not easily reproduced in normal Emacs usage.

> 
>> What we would need is for redisplay to be more in line with what toolkits does w.r.t. drawing.
>> First calculate all glyphs, but don't do any drawing.
>> Then invalidate those regions that needs redraw (a new RIF function), and let the backends deside when it is appropriate to draw by calling a redisplay function that does the actual drawing, based on the latest glyphs.
> 
> We already have the first stage of that in place: that's
> redisplay_windows, which is called for each frame that needs to be
> redisplayed.  What you are suggesting is to make update_frame, which
> currently redraws the frame's windows based on what redisplay_windows
> calculated, to instead just mark the areas which need redrawing as
> dirty.

Basically yes.

> 
> That sounds easy enough, but the problem is that we might need more
> display updates until the backend decides that it is a good time to
> actually redraw.  E.g., the user might type some commands in the
> meantime.  AFAIU, what you are saying is let all these changes affect
> only the glyph matrices that redisplay_windows calculates, so that
> when the backend wants to redraw, the Emacs function that actually
> redraws will see the up-to-date glyph matrices and use them.

Yes.

> 
> This could work if the backend can accumulate durty regions
> incrementally.  IOW, if it gets 2 requests for areas that partially
> overlap, will it mark the union of those areas as dirty?  If not, we
> will need serious changes to how redisplay_windows and its subroutines
> work, because they currently assume the previous full redisplay cycle
> updated everything on the glass, and don't keep record of the glyph
> matrices beyond the last redisplay.

The toolkits I know of can handle invalidating different regions.

> Incidentally, I don't think your suggestion will help in the "shake
> the divider" scenario: when window dimensions are changed, we toss the
> glyph matrices of the affected windows, and then allocate them anew
> (and perform a thorough redisplay of those windows).  So this will
> anyhow require to redisplay the entire window completely, and the
> backend will not be able to save us any redraws.

Not by itself, but if the backend is responsible for when actual drawing happens we can make sure we don't draw faster than the screen can update.  If the user is shaking the divider faster than we can draw, we should toss intermediate steps.  That is, if redisplay has to recalculate all matrices before they have been drawn on the screen, so be it.

In this case I suspect it does help.  When redisplay says "this region needs to redraw", the backend (NS) tells Cocoa, "this region needs to redraw".  Cocoa then calls our code to say "please redraw this region".  I assume Cocoa does not call our draw function faster than it can handle, i.e. it is called when the previous drawing is on screen.

I don't know if Cocoa actually does this, it is pure speculation.

> 
>> I think there is room for optimizations in the generic display also, for example moving the mouse redraws the entire mode line, even if the mouse pointer is outside the frame.
> 
> Please show the recipe to reproduce this.  I just tried a naive way of
> doing that, and didn't see any mode-line updates even when the mouse
> is inside the frame.  So I must be missing something.
> 

I had problems seeing what was drawn and when so I added debug code to see what the font driver actually draws.  But I see now that it is different for X11.  So it might be NS specific.  What can make the modeline redraw in one version of Emacs and not in another?  I thought all that was generic code.

>> I can sort of fix this by replacing some flushWindow with setNeedsDisplay:YES.
>> This has the drawback that updating the frame while shaking the divider becomes slower, and sometimes stops updating the frame at all until I stop moving the mouse.
> 
> Isn't this a problem that might make the entire idea unworkable?

Well, shake the divider is not really something normal a user does.  It is just a way to force the issue.  But slow redraws happens in normal usage also, i.e. switching buffers and editing.  It solves the second case, but makes shake the divider worse in terms of smooth redraws.

	Jan D.