Re: performance problems double buffering to 1600x1200 window



Hi Robert,

On 29 January 2010 02:06, Robert Gibbs <gibbsrc gmail com> wrote:
> 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.

Here's a very slightly modified version of your program. I put the fps
measure in the expose handler rather than in the idle callback, since
GDK can coalesce exposes, and added a bit more feedback about when
it's starting and stopping tests.

On my work machine (x.org 1.6.4 with nvidia driver 185 on a quadro nvs
285, compiz enabled, 1920x1200 display) I get these results:

Using GDK buffering
starting fps test
1 fps
62 fps
64 fps
64 fps
64 fps
64 fps
64 fps
stopping fps test
Using internal buffer
starting fps test
64 fps
127 fps
52 fps
53 fps
52 fps
52 fps
52 fps
53 fps
52 fps
53 fps

So on this machine anyway, the gdk double buffering does not cause
terrible performance.

John
/* compile with
 
   gcc double-buffer.c `pkg-config gtk+-2.0 --cflags --libs`

 */

#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)
{
  static GTimer *timer = NULL;
  static int frames = 0;

  GdkColor color;
  GdkDrawable *drawable;
  GdkGC *gc;

  if (!timer)
    timer = g_timer_new ();
  frames += 1;

  if (g_timer_elapsed (timer, NULL) > 1)
    {
      printf ("%d fps\n", frames);
      g_timer_reset (timer);
      frames = 0;
    }

  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)
{
  gtk_widget_queue_draw (app->da);

  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))
	{
	  printf ("stopping fps test\n");
	}
      else
	{
	  printf ("starting fps test\n");
	  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]