Re: Results on Claasen's -nocairo patches
- From: "Matt Hoosier" <mwhoosier gmail com>
- To: performance-list gnome org
- Subject: Re: Results on Claasen's -nocairo patches
- Date: Thu, 13 Jul 2006 09:12:39 -0500
And now the attachment...
On 7/13/06, Matt Hoosier <mwhoosier gmail com> wrote:
About tens days ago, Matthias Claasen posted a series of patches which
reverted some common drawing operations to use GDK calls rather than
Cairo. I'm referring particularly to the following post:
http://mail.gnome.org/archives/performance-list/2006-July/msg00000.html
I've done a little bit of benchmarking using the attached program (be
sure to give the --overlay-widgets switch on its command line). If
you'll ignore the portion of that program which animates GdkImage's
onto the background of a window, the remainder of it essentially
counts the number of times per second that a GtkButton can be painted.
Without the -nocairo patches from Matthias's posts, I get about 65
frames per second on some ARM hardware with a 320x240x16 display.
Applying the patches, I get about 85 frames per second. I used the
X.org KDrive server from the 7.1 release. (If anybody wants the gory
details on which extensions were supported, I can supply those too.)
I understand that the consensus (reached earlier) among this group is
that the dashed line which indicates focus on a button is the culprit
on non-FPU Cairo systems. So the patch which backports the default Gtk
style (probably gtk_default_draw_focus) is likely the big helper here.
--Matt
#include <stdlib.h>
#include <string.h>
#include <gtk/gtk.h>
#include <gdk/gdkwindow.h>
#include <glib.h>
static void on_destroy_cleanup ( gpointer user_data );
static void on_destroy_quit ( gpointer user_data );
static gboolean on_drawing_area_exposed ( gpointer user_data );
static gboolean idle_invalidate_window ( gpointer user_data );
static void paint_moving_background ( GtkWidget *widget );
static gboolean overlay_widgets = FALSE;
static GOptionEntry entries[] =
{
{
.long_name = "overlay-widgets",
.short_name = 0,
.flags = 0,
.arg = G_OPTION_ARG_NONE,
.arg_data = &overlay_widgets,
.description = "Whether to draw a widget atop the animated frame",
.arg_description = (gpointer) 0
},
{ NULL }
};
int main
(
int argc,
char *argv[]
)
{
gtk_init( &argc, &argv );
gtk_rc_parse( "/usr/local/share/garminsdk-theme/default/gtkrc" );
GOptionContext *option_context = g_option_context_new("- Rendering");
g_option_context_add_main_entries(option_context, entries, NULL);
g_option_context_parse(option_context, &argc, &argv, NULL);
g_option_context_free(option_context);
GtkWidget *window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
GtkWidget *alignment = gtk_alignment_new( 0.5f, 0.5f, 0.0f, 0.0f );
GtkWidget *button = gtk_button_new_with_label( "Click Me" );
gtk_container_add( GTK_CONTAINER( window ), alignment );
gtk_container_add( GTK_CONTAINER( alignment ), button );
g_signal_connect
(
G_OBJECT( window ),
"destroy",
G_CALLBACK( on_destroy_cleanup ),
NULL
);
g_signal_connect
(
G_OBJECT( window ),
"destroy",
G_CALLBACK( on_destroy_quit ),
NULL
);
g_signal_connect
(
G_OBJECT( alignment ),
"expose_event",
G_CALLBACK( on_drawing_area_exposed ),
(gpointer) alignment
);
gtk_idle_add
(
idle_invalidate_window,
(gpointer) alignment
);
gtk_widget_set_size_request
(
window,
gdk_screen_get_width( gtk_widget_get_screen( window ) ),
gdk_screen_get_height( gtk_widget_get_screen( window ) )
);
/* don't decorate window; fouls up Matchbox */
gtk_window_set_decorated( GTK_WINDOW(window), FALSE );
gtk_widget_show_all( window );
gtk_main();
return 0;
}
static gboolean on_drawing_area_exposed
(
gpointer user_data
)
{
paint_moving_background( GTK_WIDGET( user_data ) );
/* return FALSE to indicate that usual expose handlers should run too */
return overlay_widgets ? FALSE : TRUE;
}
static gboolean idle_invalidate_window
(
gpointer user_data
)
{
gtk_widget_queue_draw( GTK_WIDGET( user_data ) );
return TRUE;
}
static void draw_line_in_buffer
(
GdkImage *image
)
{
static int last_x_position = 0;
static int x_delta = 1;
int lsb_index = image->byte_order == GDK_LSB_FIRST ? 0 : 1;
int msb_index = image->byte_order == GDK_MSB_FIRST ? 0 : 1;
char *mem = (char *)image->mem;
/* set to white */
memset
(
mem,
(char) 0xff,
image->bpl * image->height
);
/* draw a stripe */
int x;
int y;
if (x_delta > 0)
{
if (last_x_position + x_delta < image->width)
{
x = last_x_position + x_delta;
}
else if (last_x_position - x_delta >= 0)
{
x = last_x_position - x_delta;
x_delta = -1;
}
else
{
/* no change possible */
x = last_x_position;
}
}
else
{
if (last_x_position + x_delta >= 0)
{
x = last_x_position + x_delta;
}
else if (last_x_position - x_delta < image->width)
{
x = last_x_position - x_delta;
x_delta = +1;
}
else
{
/* no change possible */
x = last_x_position;
}
}
/* save these results */
last_x_position = x;
int y_min = image->height / 4;
int y_max = (image->height * 3) / 4;
for (y = y_min; y < y_max; y++)
{
int offset = (y * image->bpl) + (x * image->bpp);
/* ZPixmap format (which is always used by GdkImage) has
565 format (RGB) in 16-bit mode */
/*
// red
mem[offset + msb_index] = (char) 0xf8;
mem[offset + lsb_index] = (char) 0x00;
*/
/*
// green
mem[offset + msb_index] = (char) 0x07;
mem[offset + lsb_index] = (char) 0xe0;
*/
// blue
mem[offset + msb_index] = (char) 0x00;
mem[offset + lsb_index] = (char) 0x1f;
}
}
static GdkImage *image;
static void paint_moving_background
(
GtkWidget *widget
)
{
static const int REPORT_GAP = 500;
static struct timeval last_timeval;
static int iteration = 0;
if (iteration == 0)
{
gettimeofday( &last_timeval, NULL );
}
GdkDrawable *drawable = GDK_DRAWABLE( widget->window );
int window_width;
int window_height;
int window_x;
int window_y;
int window_depth;
gdk_window_get_geometry
(
widget->window,
&window_x,
&window_y,
&window_width,
&window_height,
&window_depth
);
if (image == NULL || image->width != window_width || image->height != window_height)
{
if (image != NULL)
{
g_object_unref( image );
}
image = gdk_image_new
(
GDK_IMAGE_SHARED,
gdk_drawable_get_visual( drawable ),
window_width,
window_height
);
/* fall back to non-shared memory XImage */
if (image == NULL)
{
g_printf
(
"Warning; couldn't get XShmImage, falling back to "
"standard slow version\n"
);
image = gdk_image_new
(
GDK_IMAGE_FASTEST,
gdk_drawable_get_visual( drawable ),
window_width,
window_height
);
}
else
{
g_printf( "Got XShmImage.\n" );
}
if (image != NULL)
{
switch (image->byte_order)
{
case GDK_LSB_FIRST:
printf( "Little endian\n" );
break;
case GDK_MSB_FIRST:
printf( "Big endian\n" );
break;
}
}
else
{
g_printf( "Couldn't allocate GdkImage\n" );
}
/*
printf
(
"%dx%d window\n",
window_width,
window_height
);
printf
(
"%dx%d image, using %d bytes per pixel\n",
image->width,
image->height,
image->bpp
);
printf
(
"%d bytes per line, %d bytes per pixel, ~%d pixels per line\n",
image->bpl,
image->bpp,
image->bpl / image->bpp
);
*/
}
if (image != NULL)
{
draw_line_in_buffer( image );
gdk_draw_image
(
drawable,
widget->style->fg_gc[GTK_STATE_NORMAL],
image,
0,
0,
0,
0,
image->width,
image->height
);
/* Every so often, take timing data to figure out frame rate */
if (iteration % REPORT_GAP == 0)
{
struct timeval now_timeval;
gettimeofday( &now_timeval, NULL );
double now_sec = (now_timeval.tv_usec / 1000000.0)
+ now_timeval.tv_sec;
double last_sec = (last_timeval.tv_usec / 1000000.0)
+ last_timeval.tv_sec;
double fps = REPORT_GAP / (now_sec - last_sec);
last_timeval = now_timeval;
printf( "Over [%f, %f] sec, %f fps\n", last_sec, now_sec, fps );
}
}
else
{
printf( "Couldn't allocated shared memory image.\n" );
}
iteration++;
}
static void on_destroy_cleanup
(
gpointer user_data
)
{
if (image != NULL)
{
g_object_unref( image );
image = NULL;
}
}
static void on_destroy_quit
(
gpointer user_data
)
{
gtk_main_quit();
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]