Colomban Wendling
2014-04-22 22:13:20 UTC
Hi,
https://sourceforge.net/p/scintilla/bugs/1567/ reports a important
flickering issue when using GTK >= 3.9.2.
TL;DR: it's complicated, but there is a patch linked at the bottom.
## Why does something happen on GTK 3.9.2?
This is due to a change in the way GTK 3.9.2 performs drawing, which
basically makes gtk_widget_set_double_buffered() useless.
In practice, now GTK draws the whole app on one single buffer (Cairo
context), from the bottom-up (from the root window to the deepest
children). This means that the area of the buffer on which we draw will
*always* be invalidated first, because the parent container will have
had drawn its background already. Before this change, we had our own
buffer no one else would mess with.
## Why does this make Scintilla flicker?
When we receive a draw request, we first try to honor it, and if
everything goes well, we do -- and everybody's happy.
But if the area is not large enough for the redraw we have to do,
instead of gently finishing the current draw and then invalidating a
larger area, we try to perform an optimization by abandoning the pain as
soon as we realize it won't be enough. This typically happens when
folding changes.
This used not to be a problem, since we just pained over the existing
buffer: at worse we had inconsistent display before the next scheduled
paint kicked in, it was hardly possible to notice. But now the area
scheduled for repaint it unconditionally pain blank first, we see the
blank area flashing.
## What can we do about this?
Well. First, we could hope for GTK to revert this change since it broke
some applications (at least us), but I doubt this is realistic.
Then, we could try to always paint the whole requested area. This even
sounds more sensible, because relying on single buffering is kind of out
of the time, nowadays most (if not all?) display APIs expect the client
to sensibly answer the draw requests fitting the model.
To properly do this, we have several solutions, with various degrees of
quality and complexity.
1) ScintillaBase::Paint() could be modified never to abandon a paint.
This would remove what looks like an optimization, and would affect all
platforms. I guess this is not an option.
2) ScintillaGTK could have pixel caching. This can possibly be the best
solution, as it allows to paint e.g. on tiles on free time, and simply
"blit" them when the actual draw occurs. It could reduce the drawing
time since the real drawing code could possibly have lot less to draw
(only the parts that actually changed), and could possibly improve
display reactivity (as we would take virtually no time performing the
visible draw).
3) Instead of scheduling a new draw when the pain area is not large
enough, extend the clip manually. This is kind of dirty and requires
non-obvious API, but fortunately Cairo has it: cairo_reset_clip().
This can have better overall performance than we have now (no
re-scheduling), but could make one draw longer (since the full redraw
would happen immediately).
4) Maybe something else??? What do other platform layers do?
Well. I guess 1) is not an option. I would think 2) is the way to go,
but probably requires quite some work. 3) is a bit of a hack, but is
pretty easy, and does work (at least on X11?).
## Proposed solution
I have attached a proposed patch using solution 3 to the bug:
https://sourceforge.net/p/scintilla/bugs/_discuss/thread/6d86168e/8182/attachment/0001-Avoid-flickering-on-some-redraws-with-GTK-3-9-2.patch
Note that most of the changes in ScintillaGTK::DrawTextThis() are
indentation changes because of the added outer `for` loop, most of the
code is the same (you can check the diff ignoring space changes).
What do you think?
Regards,
Colomban
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scintilla-interest+***@googlegroups.com.
To post to this group, send email to scintilla-***@googlegroups.com.
Visit this group at http://groups.google.com/group/scintilla-interest.
For more options, visit https://groups.google.com/d/optout.
https://sourceforge.net/p/scintilla/bugs/1567/ reports a important
flickering issue when using GTK >= 3.9.2.
TL;DR: it's complicated, but there is a patch linked at the bottom.
## Why does something happen on GTK 3.9.2?
This is due to a change in the way GTK 3.9.2 performs drawing, which
basically makes gtk_widget_set_double_buffered() useless.
In practice, now GTK draws the whole app on one single buffer (Cairo
context), from the bottom-up (from the root window to the deepest
children). This means that the area of the buffer on which we draw will
*always* be invalidated first, because the parent container will have
had drawn its background already. Before this change, we had our own
buffer no one else would mess with.
## Why does this make Scintilla flicker?
When we receive a draw request, we first try to honor it, and if
everything goes well, we do -- and everybody's happy.
But if the area is not large enough for the redraw we have to do,
instead of gently finishing the current draw and then invalidating a
larger area, we try to perform an optimization by abandoning the pain as
soon as we realize it won't be enough. This typically happens when
folding changes.
This used not to be a problem, since we just pained over the existing
buffer: at worse we had inconsistent display before the next scheduled
paint kicked in, it was hardly possible to notice. But now the area
scheduled for repaint it unconditionally pain blank first, we see the
blank area flashing.
## What can we do about this?
Well. First, we could hope for GTK to revert this change since it broke
some applications (at least us), but I doubt this is realistic.
Then, we could try to always paint the whole requested area. This even
sounds more sensible, because relying on single buffering is kind of out
of the time, nowadays most (if not all?) display APIs expect the client
to sensibly answer the draw requests fitting the model.
To properly do this, we have several solutions, with various degrees of
quality and complexity.
1) ScintillaBase::Paint() could be modified never to abandon a paint.
This would remove what looks like an optimization, and would affect all
platforms. I guess this is not an option.
2) ScintillaGTK could have pixel caching. This can possibly be the best
solution, as it allows to paint e.g. on tiles on free time, and simply
"blit" them when the actual draw occurs. It could reduce the drawing
time since the real drawing code could possibly have lot less to draw
(only the parts that actually changed), and could possibly improve
display reactivity (as we would take virtually no time performing the
visible draw).
3) Instead of scheduling a new draw when the pain area is not large
enough, extend the clip manually. This is kind of dirty and requires
non-obvious API, but fortunately Cairo has it: cairo_reset_clip().
This can have better overall performance than we have now (no
re-scheduling), but could make one draw longer (since the full redraw
would happen immediately).
4) Maybe something else??? What do other platform layers do?
Well. I guess 1) is not an option. I would think 2) is the way to go,
but probably requires quite some work. 3) is a bit of a hack, but is
pretty easy, and does work (at least on X11?).
## Proposed solution
I have attached a proposed patch using solution 3 to the bug:
https://sourceforge.net/p/scintilla/bugs/_discuss/thread/6d86168e/8182/attachment/0001-Avoid-flickering-on-some-redraws-with-GTK-3-9-2.patch
Note that most of the changes in ScintillaGTK::DrawTextThis() are
indentation changes because of the added outer `for` loop, most of the
code is the same (you can check the diff ignoring space changes).
What do you think?
Regards,
Colomban
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scintilla-interest+***@googlegroups.com.
To post to this group, send email to scintilla-***@googlegroups.com.
Visit this group at http://groups.google.com/group/scintilla-interest.
For more options, visit https://groups.google.com/d/optout.