new browser windows slower than first one
Hello, just noticed a scroll performance-related problem: When I create many browser windows (e.g. using the middle mouse button), srolling in these created windows causes more Xorg CPU usage than in the first one. Maybe, scrolling in the new windows causes redraws from the old ones? Johannes
On Sat, Oct 20, 2007 at 08:14:47PM +0200, Johannes Hofmann wrote:
Hello,
just noticed a scroll performance-related problem: When I create many browser windows (e.g. using the middle mouse button), srolling in these created windows causes more Xorg CPU usage than in the first one. Maybe, scrolling in the new windows causes redraws from the old ones?
Argh, fltk2 uses double-buffering by default. This uses quite some memory on the X-server side and slows things down. --- a/src/ui.cc Sat Oct 20 17:59:33 2007 +0200 +++ b/src/ui.cc Sun Oct 21 14:47:49 2007 +0200 @@ -580,6 +580,7 @@ UI::UI(int win_w, int win_h, const char* { int s_h = 20; resizable(this); + clear_double_buffer(); begin(); TopGroup = this; switches double-buffering off. This makes quite a difference for scrolling here. However during rendering there is some flicker now. But the excessive redraws that cause the flicker should be addressed anyhow. Johannes
Hi, On Sun, Oct 21, 2007 at 03:35:49PM +0200, Johannes Hofmann wrote:
On Sat, Oct 20, 2007 at 08:14:47PM +0200, Johannes Hofmann wrote:
Hello,
just noticed a scroll performance-related problem: When I create many browser windows (e.g. using the middle mouse button), srolling in these created windows causes more Xorg CPU usage than in the first one. Maybe, scrolling in the new windows causes redraws from the old ones?
Argh, fltk2 uses double-buffering by default. This uses quite some memory on the X-server side and slows things down.
--- a/src/ui.cc Sat Oct 20 17:59:33 2007 +0200 +++ b/src/ui.cc Sun Oct 21 14:47:49 2007 +0200 @@ -580,6 +580,7 @@ UI::UI(int win_w, int win_h, const char* { int s_h = 20; resizable(this); + clear_double_buffer(); begin(); TopGroup = this;
switches double-buffering off. This makes quite a difference for scrolling here. However during rendering there is some flicker now. But the excessive redraws that cause the flicker should be addressed anyhow.
Commited! This is will be very good for debugging screen updates. Those not working in it can comment it out in src/ui.cc: + //clear_double_buffer(); -- Cheers Jorge.-
Turning off double buffering means that the default code from the tree is unusably slow and annoying on my ancient(*) computer. This might dissuade someone who comes along at the wrong time intending to give the fltk dillo a look. Though admittedly it might be my configuration... * Computers never get slow; software gets slow!
Hi, On Mon, Oct 22, 2007 at 06:39:09PM +0000, place wrote:
Turning off double buffering means that the default code from the tree is unusably slow and annoying on my ancient(*) computer. This might dissuade someone who comes along at the wrong time intending to give the fltk dillo a look.
Though admittedly it might be my configuration...
I'll try to check this on wednesday, in a slow machine.
* Computers never get slow; software gets slow!
TRUE. -- Cheers Jorge.-
Hi, On Mon, Oct 22, 2007 at 06:39:09PM +0000, place wrote:
Turning off double buffering means that the default code from the tree is unusably slow and annoying on my ancient(*) computer. This might dissuade someone who comes along at the wrong time intending to give the fltk dillo a look.
Though admittedly it might be my configuration...
When testing in a Pentium I, 233Mhz, 96MB ram, the results were mixed, varied and confusing to me! For instance with dillo2-noDB, I get faster scrolling in a down-arrow-always-pressed-test, varying from 25% to 95% more or less of CPU depending on what is to be rendered and the X server's internal memory usage. Mouse drag-scrolling sometimes is better, some others worst and others the same !? With dillo2-DB, sometimes I get faster mouse drag-scrolling, others the same. Down-arrow-always-pressed-test is consistently worst, but sometimes pages render much faster and others the same. Frankly, I don't understand what this means. Ah, I also noticed that in a fast machine dillo2-noDB is much better than dillo2-DB (but annoying at flickering). -- Cheers Jorge.-
Hi Jorge, On Thu, Oct 25, 2007 at 04:10:12PM -0300, Jorge Arellano Cid wrote:
Hi,
On Mon, Oct 22, 2007 at 06:39:09PM +0000, place wrote:
Turning off double buffering means that the default code from the tree is unusably slow and annoying on my ancient(*) computer. This might dissuade someone who comes along at the wrong time intending to give the fltk dillo a look.
Though admittedly it might be my configuration...
When testing in a Pentium I, 233Mhz, 96MB ram, the results were mixed, varied and confusing to me!
For instance with dillo2-noDB, I get faster scrolling in a down-arrow-always-pressed-test, varying from 25% to 95% more or less of CPU depending on what is to be rendered and the X server's internal memory usage. Mouse drag-scrolling sometimes is better, some others worst and others the same !?
With dillo2-DB, sometimes I get faster mouse drag-scrolling, others the same. Down-arrow-always-pressed-test is consistently worst, but sometimes pages render much faster and others the same.
Frankly, I don't understand what this means.
Yes, the performance is pretty confusing sometimes. The main drawback for me of standard DB dillo is that CPU usage and server side memory consumption gets horrible on my laptop when I open 5 or more windows.
Ah, I also noticed that in a fast machine dillo2-noDB is much better than dillo2-DB (but annoying at flickering).
I think, we need something like DB for drawing. Dillo1 also draws to a backbuffer and then copies the result to the screen - please correct me if I'm wrong. As dillo first draws the background and then the text/images on top, we will always see annoying flickering if we draw directly to the screen, especially with frequent redraws during incremental page rendering while the page is loaded (which is a great feature of dillo btw). However, I hope that we can do better than switch on DB generally. As dillo is single threaded even for multiple windows, we could use a single backbuffer for all windows. I've got this working, but unfortunately currently only if XFT is disabled. Johannes
I think my biggest problem is that I can't read a page until it's finished downloading because it's spending the whole time redrawing, redrawing, redrawing.
On Thu, Oct 25, 2007 at 07:42:30PM +0000, place wrote:
I think my biggest problem is that I can't read a page until it's finished downloading because it's spending the whole time redrawing, redrawing, redrawing.
For me it's no problem to comment clear_double_buffer() in ui.cc, as long as we remember to fix the excess of redrawing. -- Cheers Jorge.-
On Thu, Oct 25, 2007 at 05:34:30PM -0300, Jorge Arellano Cid wrote:
On Thu, Oct 25, 2007 at 07:42:30PM +0000, place wrote:
I think my biggest problem is that I can't read a page until it's finished downloading because it's spending the whole time redrawing, redrawing, redrawing.
For me it's no problem to comment clear_double_buffer() in ui.cc, as long as we remember to fix the excess of redrawing.
I don't mind either, it's just one line anyway. And I think that dillo1 also has frequent redraws but they are not as apparent as the rendering is done to a pixmap and the result is copied. Can others please add the following debug messages to see how often dillo1 rerenders a certain page compared to dillo2 on their machines? dillo1: --- dillo-0.8.6/src/dw_gtk_viewport.c.orig 2007-10-25 22:36:44 +0200 +++ dillo-0.8.6/src/dw_gtk_viewport.c 2007-10-23 19:52:02 +0200 @@ -333,6 +333,7 @@ static void Dw_gtk_viewport_paint (GtkWi /* Widgets draw in backing pixmap. */ p_Dw_widget_draw (viewport->child, &intersection, event); /* Copy backing pixmap into window. */ +fprintf(stderr, "====> DRAW ======\n"); gdk_draw_pixmap (layout->bin_window, widget->style->black_gc, viewport->back_pixmap, area->x, area->y, area->x, area->y, area->width, area->height); dillo2: diff -r 31fd33cfb784 dw/fltkviewbase.cc --- a/dw/fltkviewbase.cc Wed Oct 24 22:25:25 2007 +0200 +++ b/dw/fltkviewbase.cc Thu Oct 25 22:51:11 2007 +0200 @@ -50,6 +50,7 @@ FltkViewBase::~FltkViewBase () void FltkViewBase::draw () { +fprintf(stderr, "====> DRAW ======\n"); Group::draw (); ::fltk::Rectangle rect (x(), y(), w(), h()); Johannes
Hi, here is a patch to avoid the flickering even with clear_double_buffer() as currently in CVS. It uses a self-made double buffering for those drawing operations that need it (as it was done in dillo1). The main advantage over generally switching on double buffering, is that we need only one buffer for all windows, which saves X-server side memory and avoids slowdowns with many open windows. However this approach has some drawbacks: * The newly introduced FltkOffscreen class contains X11 specific code and it would be better if this could be done by fltk. But unfortunately there is an open bug (http://www.fltk.org/str.php?L1042). * When you compile fltk with the --disable-xft option you now need to do "export CPPFLAGS=-DNO_XFT" before configuring dw-testbed. * It makes the redraws invisible again, which we might want to reduce by other means. Jorge, regardless of whether you want to apply this patch, could you please apply the @@ -225,15 +239,7 @@ void FltkViewBase::queueDraw (core::Rect { /** \bug Inefficient */ - push_clip( - translateCanvasXToViewX (area->x), - translateCanvasYToViewY (area->y), - area->width, - area->height); - redraw (DAMAGE_EXPOSE); - - pop_clip(); } part, which removes some calls added with my initial scrolling patch. These calls are just wrong. push_clip/pop_clip can only be called from within the draw() method. Regards, Johannes diff --git a/dw/Makefile.am b/dw/Makefile.am --- a/dw/Makefile.am +++ b/dw/Makefile.am @@ -45,7 +45,9 @@ libDw_fltk_a_SOURCES = \ fltkviewbase.cc \ fltkviewbase.hh \ fltkviewport.cc \ - fltkviewport.hh + fltkviewport.hh \ + fltkoffscreen.cc \ + fltkoffscreen.hh libDw_fltk_a_CXXFLAGS = @LIBFLTK_CXXFLAGS@ diff --git a/dw/fltkoffscreen.cc b/dw/fltkoffscreen.cc new file mode 100644 --- /dev/null +++ b/dw/fltkoffscreen.cc @@ -0,0 +1,104 @@ +/* + * Dillo Widget + * + * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include <fltk/x11.h> + +#ifndef NO_XFT +#include <X11/Xft/Xft.h> +#endif + + +#include "fltkoffscreen.hh" + +using namespace fltk; + +namespace dw { +namespace fltk { + +FltkOffscreen::FltkOffscreen () { + w = 0; + h = 0; + pixmap = 0; + this->xftc = NULL; +} + + +FltkOffscreen::~FltkOffscreen () { + if (pixmap) { + XFreePixmap(xdisplay, pixmap); + } +#ifndef NO_XFT + if (this->xftc) { + XftDrawDestroy((XftDraw*) this->xftc); + } +#endif +} + + +void FltkOffscreen::begin (int w, int h) { + gsave = new GSave(); + + if (!pixmap || w > this->w || h > this->h) { + if (pixmap) { + XFreePixmap (xdisplay, pixmap); + } + pixmap = XCreatePixmap (xdisplay, xwindow, w, h, xvisual->depth); + +#ifndef NO_XFT + if (!this->xftc) { + this->xftc = XftDrawCreate(xdisplay, pixmap, + xvisual->visual, xcolormap); + } else { + XftDrawChange ((XftDraw*) this->xftc, pixmap); + } +#endif + + this->w = w; + this->h = h; + } + + saveWindow = xwindow; + xwindow = pixmap; +#ifndef NO_XFT + saveXftc = ::fltk::xftc; + ::fltk::xftc = (XftDraw*) this->xftc; +#endif + push_no_clip(); +} + + +void FltkOffscreen::end () { + pop_clip(); + xwindow = saveWindow; +#ifndef NO_XFT + ::fltk::xftc = (XftDraw*) saveXftc; +#endif + delete gsave; +} + + +void FltkOffscreen::draw (const ::fltk::Rectangle &area, int srcx, int srcy) { + XCopyArea(xdisplay, pixmap, xwindow, gc, srcx, srcy, + area.w(), area.h(), area.x(), area.y()); +} + +} // namespace fltk +} // namespace dw diff --git a/dw/fltkoffscreen.hh b/dw/fltkoffscreen.hh new file mode 100644 --- /dev/null +++ b/dw/fltkoffscreen.hh @@ -0,0 +1,34 @@ +#ifndef __DW_FLTKOFFSCREEN_HH__ +#define __DW_FLTKOFFSCREEN_HH__ + +#include <fltk/Rectangle.h> +#include <fltk/draw.h> + +namespace dw { +namespace fltk { + +class FltkOffscreen +{ +private: + int w; + int h; + unsigned long pixmap; + unsigned long saveWindow; + void *xftc; /* void* to avoid to include Xft/Xft.h */ + void *saveXftc; + ::fltk::GSave *gsave; + +public: + FltkOffscreen (); + ~FltkOffscreen (); + + void begin (int w, int h); + void end (); + void draw (const ::fltk::Rectangle &area, int srcx, int srcy); +}; + +} // namespace fltk +} // namespace dw + +#endif // __DW_FLTKOFFSCREEN_HH__ + diff --git a/dw/fltkviewbase.cc b/dw/fltkviewbase.cc --- a/dw/fltkviewbase.cc +++ b/dw/fltkviewbase.cc @@ -18,15 +18,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - - #include "fltkviewport.hh" #include <fltk/draw.h> #include <fltk/damage.h> #include <fltk/events.h> #include <fltk/Cursor.h> - #include <stdio.h> using namespace fltk; @@ -36,12 +33,19 @@ namespace dw { namespace dw { namespace fltk { +FltkOffscreen *FltkViewBase::backBuffer; + FltkViewBase::FltkViewBase (int x, int y, int w, int h, const char *label): Group (x, y, w, h, label) { canvasWidth = 1; canvasHeight = 1; bgColor = WHITE; + + if (!backBuffer) { + backBuffer = new FltkOffscreen(); + } + } FltkViewBase::~FltkViewBase () @@ -50,14 +54,19 @@ FltkViewBase::~FltkViewBase () void FltkViewBase::draw () { - Group::draw (); - + int d = damage(); ::fltk::Rectangle rect (x(), y(), w(), h()); /* fltk-clipping seems not to use widget coordinates */ ::fltk::intersect_with_clip(rect); rect.x(rect.x() - x()); rect.y(rect.y() - y()); + + if (!(d & DAMAGE_SCROLL)) { + backBuffer->begin(rect.w(), rect.h()); + + translate(-rect.x()-x() , -rect.y()-y() ); + } setcolor (bgColor); fillrect (rect); @@ -68,6 +77,11 @@ void FltkViewBase::draw () area.width = rect.w(); area.height = rect.h(); theLayout->expose (this, &area); + + if (!(d & DAMAGE_SCROLL)) { + backBuffer->end(); + backBuffer->draw(Rectangle(rect.x() + x(), rect.y() + y(), rect.w(), rect.h()), 0, 0); + } } core::ButtonState getDwButtonState () @@ -162,7 +176,7 @@ void FltkViewBase::setCanvasSize (int wi void FltkViewBase::setCursor (core::style::Cursor cursor) { - static Cursor *mapDwToFltk[] = { + static ::fltk::Cursor *mapDwToFltk[] = { CURSOR_CROSS, CURSOR_ARROW, CURSOR_HAND, @@ -225,15 +239,7 @@ void FltkViewBase::queueDraw (core::Rect { /** \bug Inefficient */ - push_clip( - translateCanvasXToViewX (area->x), - translateCanvasYToViewY (area->y), - area->width, - area->height); - redraw (DAMAGE_EXPOSE); - - pop_clip(); } void FltkViewBase::queueDrawTotal () diff --git a/dw/fltkviewbase.hh b/dw/fltkviewbase.hh --- a/dw/fltkviewbase.hh +++ b/dw/fltkviewbase.hh @@ -5,7 +5,7 @@ #include <fltk/Scrollbar.h> #include "fltkcore.hh" -#include "fltkcore.hh" +#include "fltkoffscreen.hh" namespace dw { namespace fltk { @@ -14,6 +14,7 @@ class FltkViewBase: public FltkView, pub { private: int bgColor; + static FltkOffscreen *backBuffer; protected: core::Layout *theLayout;
Hi Johannes, On Tue, Nov 06, 2007 at 08:51:15PM +0100, Johannes Hofmann wrote:
Hi,
here is a patch to avoid the flickering even with clear_double_buffer() as currently in CVS. It uses a self-made double buffering for those drawing operations that need it (as it was done in dillo1). The main advantage over generally switching on double buffering, is that we need only one buffer for all windows, which saves X-server side memory and avoids slowdowns with many open windows.
Yes, and it works much better than what we have now...
However this approach has some drawbacks:
* The newly introduced FltkOffscreen class contains X11 specific code and it would be better if this could be done by fltk. But unfortunately there is an open bug (http://www.fltk.org/str.php?L1042).
Yes. One of the main advanteges of relying completely on fltk2 for drawing is that porting fltk2 to a new backend, makes dillo2 automatically work there too. Some people long for OpenGl, others the framebuffer, etc.
* When you compile fltk with the --disable-xft option you now need to do "export CPPFLAGS=-DNO_XFT" before configuring dw-testbed.
`fltk2-config --ldflags` reports on "-lXft". Maybe it can be used in configure.in as a test and thus, set CPPFLAGS automatically.
* It makes the redraws invisible again, which we might want to reduce by other means.
Yes, this is the key point. The main reason of leaving double buffering out is to remember that drawing needs an urgent fix. The number of redraws is not acceptable, and double buffering conceals it. I understand the need to reduce the annoying flickering, and huge memory footprint, but hesitate to commit the patch as is because it could stop people from porting fltk2 to a new backend when they need a browser. If you can add it as a compile time option (e.g. --with-internal-buffering) and automate the CPPFLAGS setting from configure, I'd commit. Now, what I'd really like is to reduce the number of redraws (an ugly bug) and to have an fltk2 means to make calls to X11. If you can work on the first task, it's more than welcomed. For the second one we need to coordinate with the fltk2 team. What do you think of this?
Jorge, regardless of whether you want to apply this patch, could you please apply the
@@ -225,15 +239,7 @@ void FltkViewBase::queueDraw (core::Rect { /** \bug Inefficient */
- push_clip( - translateCanvasXToViewX (area->x), - translateCanvasYToViewY (area->y), - area->width, - area->height); - redraw (DAMAGE_EXPOSE); - - pop_clip(); }
part, which removes some calls added with my initial scrolling patch. These calls are just wrong. push_clip/pop_clip can only be called from within the draw() method.
Out of place push/pop pair removal, commited. -- Cheers Jorge.-
Hi Jorge, I fully agree with your comments on my buffering patch. We should focus on the real solution, which is to fix the fltk library and then use their code for offscreen drawing. Whoever needs it can apply the patch manually. Regarding the frequent redraws I made the following observations: * Redraw requests are accumulated by fltk and then result in a single redraw when fltk thinks it should actually do the drawing. * Current code issues a full redraw request even if only part of the screen needs redrawing. This is a commented deficiancy and can be fixed quite easily. However there are so many full redraw requests, that one will hardly see any difference by that change. * Most full redraw requests come from Layout::queueResize() which in turn causes Layout::resizeIdle() to be called when fltk is idle for a moment. Every change of the size of a widget may change the whole layout on the screen and therefore require a complete redraw. If I understand the code correctly this is the similar in dillo1. So what can we do? For the second point I can provide a patch that accumulates screen regions that need redrawing until fltk actually redraws. The last point is more difficult to improve. For example think of a long page containing just text. Every time a new chunk comes in over the net, dillo creates a redraw request for the whole screen, even though there is already enough text to fill the screen so that the new data does not actually change the layout of the part that is currently visible. But how can we know, whether new data changes the layout of the currently visible part or not? The only rather simple improvement I can think of is that we could use the image sizes provided in the <img/> tags and only issue a Layout::queueResize() if the image proves to be of a different size. Currently there is a Layout::queueResize() for every image as it gets loaded. Regards, Johannes
On Sun, Oct 21, 2007 at 03:35:49PM +0200, Johannes Hofmann wrote:
switches double-buffering off. This makes quite a difference for scrolling here.
Scrolling an empty page at fullscreen now consumes 1.5% CPU load and not 100% as before. Fantastic!!! If the page has content, it's considerably more (at least 20%), most likely because of the many unneccessary redraws. Cheers, -- Matthias Franz
participants (5)
-
bogus@does.not.exist.com
-
jcid@dillo.org
-
Johannes.Hofmann@gmx.de
-
matthias.franz@ujf-grenoble.fr
-
place@gobigwest.com