5
votes

I wrote an app that uses Cairo to draw things on screen (on a Gtk::DrawingArea, to be exact). It needs to redraw everything frequently. It turns out, that despite the draphics drawn are very simple, the X server uses LOTS of CPU when redrawing, and the applications works terribly slow. Is there any way to speed this up? Or maybe I shouldn't use DrawingArea and some other widget?

What I draw is set of rectangles, which user can move around by dragging them with mouse. The whole drawing is done withing on_expose_event, but as the mouse pointer moves around (with button pressed), I call queue_draw() to refresh drawing.

4
Description of what are you drawing and how are you drawing would probably bring more insites.Artyom
Please add some numbers. Just a little counter in the expose event to measure the frame rate. Maybe we are talking about to many refreshs and not a slow drawing. A high resolution laser mouse can produce a lot mouse motion events.Lothar

4 Answers

9
votes

Just a couple things to check:

Is your drawing done in the expose event?

Draw your image to a Cairo Surface, and then in the expose event simply copy from that surface to the widget's surface.

Are you clipping and drawing only the region necessary?

The expose event gives you an X, Y, width, height of the area that needs to be redrawn. In cairo, create a rectangle on your surface with these dimensions and call clip so that you aren't wasting time redrawing stuff that doesn't need to be.

3
votes

Drawing is expensive, especially text drawing has become the most CPU expensive task of a GUI.

The only way to speed this up is to reduce the amount of drawn items. Check if you really only draw the items that are necessary. The expose-event is giving you a rectangle. Only refresh this part of the widget.

Maybe cache items in a bitmap.

For smooth scrolling for example it can help to draw the content into a bitmap that is for example 500 pixels larger so that in most cases you just need to copy the image and don't draw anything at all (you usually get expose rectangles that are just 5 to 10 pixels high during scrolling).

But you need to give us more information what you are drawing and what the system load is to get a better answer.

0
votes

I found this article about threaded drawing in cairo to solve the speed-problem, maybe that helps:

http://cairographics.org/threaded_animation_with_cairo/

About the high CPU usage:

Do you have proper hardware accelerated drivers installed for X?

0
votes

I finally forced to use maximally 25 fps, by using a lock flag.

bool lock = 0;
bool needs_redraw = 0;

void Redraw(){
    if(lock){
        needs_redraw = 1;
        return;
    }

    //draw image to a surface

    needs_redraw = 0;
    lock = 1;
    Glib::signal_timeout().connect(Unlock, 20);

    queue_draw();
}

bool Unlock(){
    lock = 0;
    if(needs_redraw) Redraw();
    return false;
}

void on_expose_event(something){
    //copy image from surface to widget's context
}

This is a sample code, but that's the idea. It will disallow redraw to be done more often then once per 20 ms.