Re: performance problems double buffering to 1600x1200 window



I have attached an example program.  With this example I get 220 FPS using a pixmap for buffer and 11 FPS using the GDK buffering.

I am using the X11 backend with Compiz.

I have run it with sysprof. sysprof tells me that most of the time is being spent in the X process but there is no further detail as to where in the X11 library.

I will experiment more to see if it is related to re-allocating the pixmap.



On Wed, Jan 27, 2010 at 9:12 PM, Robert Gibbs <gibbsrc gmail com> wrote:
I am running into a severe performance degradation when using the built in GtkDrawingArea double buffering to a 1600x1200 window.  The program sets a default priority idle handler which calls gtk_widget_queue_draw.  The expose event originally would draw about 1000 polygons, but I commented out the drawing portion and still saw the same poor performance.  The best performance I can get is about 10 frames per second.

If call GTK_WIDGET_UNSET_FLAGS (drawing_area, GTK_DOUBLE_BUFFERED), then use my own pixmap for double buffering, the performance goes up to 50 frames per second.

Can anyone tell me why the built-in double buffering would yield such poor performance?

 

#include <math.h>
#include <time.h>
#include <string.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <gdk/gdkkeysyms.h>

typedef struct {
        guint idle_id;
        GtkWidget *da;
        GdkPixmap *pix;
        gboolean use_buffer;
} AppData;


static gboolean
on_expose(GtkWidget *widget, GdkEventExpose *event, AppData *app)
{
        GdkColor color;
        GdkDrawable *drawable;
        GdkGC *gc;

        if (app->use_buffer) {
                drawable = GDK_DRAWABLE(app->pix);
                gc = gdk_gc_new(drawable);
                gdk_color_parse("black", &color);
                gdk_gc_set_rgb_fg_color(gc, &color);
                gdk_draw_rectangle(drawable, gc, TRUE, 0, 0,
                                widget->allocation.width, 
                                widget->allocation.height);
        }
        else {
                drawable = GDK_DRAWABLE(widget->window);
                gc = gdk_gc_new(drawable);
        }
        gdk_color_parse("red", &color);
        gdk_gc_set_rgb_fg_color(gc, &color);

        gdk_draw_line(drawable, gc, 0, 0,
                        widget->allocation.width,
                        widget->allocation.height);
        gdk_draw_line(drawable, gc, widget->allocation.width, 0,
                        0, widget->allocation.height);

        if (app->use_buffer) {
                gdk_draw_drawable(GDK_DRAWABLE(widget->window), gc, 
                                GDK_DRAWABLE(app->pix), 0, 0, 0, 0, -1, -1);
        }
        return TRUE;
}

static gboolean
on_configure(GtkWidget *widget, GdkEventConfigure *event, AppData *app)
{
        if (app->use_buffer) {
                if (app->pix) g_object_unref(app->pix);
                app->pix = gdk_pixmap_new(GDK_DRAWABLE(app->da->window), 
                                event->width, event->height, -1);
        }
        return TRUE;
}

static gboolean
on_fps_idle(AppData *app)
{
        static time_t t = 0;
        static float total = 0;


        if (t == 0) t = time(0);
        gtk_widget_queue_draw(app->da);
        total++;
        if (time(0) - t >= 10) {
                printf("%.1f FPS\n", total / ((float)(time(0)-t)));
                t = time(0);
                total = 0;
        }
        return TRUE;
}

static gboolean
on_key_press_event(GtkWidget *widget, GdkEventKey *event, AppData *app)
{
        switch (event->keyval) {
                case GDK_t:
                case GDK_T:
                        if (!g_source_remove_by_user_data(app))
                        {
                                g_idle_add((GSourceFunc) 
                                        on_fps_idle, app);
                        }
                        break;
                case GDK_b:
                case GDK_B:
                        if (app->use_buffer) {
                                printf("Using GDK buffering\n");
                                app->use_buffer = FALSE;
                                GTK_WIDGET_SET_FLAGS (app->da, 
                                                GTK_DOUBLE_BUFFERED);
                                if (app->pix) g_object_unref(app->pix);
                                app->pix = NULL;
                        }
                        else {
                                printf("Using internal buffer\n");
                                app->use_buffer = TRUE;
                                GTK_WIDGET_UNSET_FLAGS (app->da, 
                                                GTK_DOUBLE_BUFFERED);
                                app->pix = gdk_pixmap_new(GDK_DRAWABLE(
                                                app->da->window),
                                                app->da->allocation.width,
                                                app->da->allocation.height, -1);
                        }
                        break;
                default:
                        break;
        }
        return FALSE;
}

static char *keymaps = "\
t.T\t\tStart or stop a frame per second (FPS) timing test.\n\
b.B\t\tToggle internal buffering on or off..\n\
";

int
main(int argc, char **argv)
{
        GtkWidget *window;
        GdkColor color;
        AppData app;

        memset(&app, 0, sizeof(app));

        gtk_init(&argc, &argv);
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        g_signal_connect(window, "delete-event", gtk_main_quit, NULL);
        app.da = gtk_drawing_area_new();
        GTK_WIDGET_SET_FLAGS (app.da, GTK_CAN_FOCUS);
        gdk_color_parse("black", &color);
        gtk_widget_modify_bg(app.da, GTK_STATE_NORMAL, &color);
        gtk_widget_set_size_request(app.da, 400, 400);
        gtk_widget_set_events(app.da,
                        GDK_KEY_PRESS_MASK |
                        GDK_KEY_RELEASE_MASK |
                        GDK_LEAVE_NOTIFY_MASK |
                        GDK_FOCUS_CHANGE_MASK |
                        GDK_EXPOSURE_MASK);
        g_signal_connect(app.da, "key-press-event", 
                        G_CALLBACK(on_key_press_event), &app);
        g_signal_connect(app.da, "expose-event", G_CALLBACK(on_expose), &app);
        g_signal_connect(app.da, "configure-event", G_CALLBACK(on_configure), 
                        &app);
        gtk_container_add(GTK_CONTAINER(window), app.da);
        gtk_widget_show_all(window);

        printf("%s\n", keymaps);
        gtk_main();
        return 0;
}




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]