Complete.Org: Mailing Lists: Archives: freeciv-dev: October 2004:
[Freeciv-Dev] (PR#10549) don't use GDK for mapview dirty/flush operation
Home

[Freeciv-Dev] (PR#10549) don't use GDK for mapview dirty/flush operation

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: undisclosed-recipients: ;
Subject: [Freeciv-Dev] (PR#10549) don't use GDK for mapview dirty/flush operations in gui-gtk-2.0
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Fri, 15 Oct 2004 19:56:09 -0700
Reply-to: rt@xxxxxxxxxxx

<URL: http://rt.freeciv.org/Ticket/Display.html?id=10549 >

This patch does something Raimar wanted a long time ago: uses a simple 
impelementation of the dirty/flush operations in gui-gtk-2.0.

The current method calls gdk_window_invalidate_rect to dirty an area of 
the rectangle.  Then to flush, we call gdk_window_process_updates.  The 
advantage is that this means GDK may do other updates during that time: 
leading to greater responsiveness in the application (particularly 
during end-of-turn).

The new method, which is used in all other GUIs already, simply keeps 
track of which rects are dirty.  When the flush is done we write them 
all to the window.  The advantage of this is that there's less overhead. 
  There's also an advantage that since the implementation is the same 
between all GUIs, we may perhaps move these functions into the common code.

In my tests this raises the scroll speed by around 80%.  Instead of 
getting 4-8 FPS in fullscreen mode I can get 8-14 FPS.  And instead of 
12 FPS in standard window size I can get 22 FPS.  (This is from the FPS 
patch, also attached.)

Please test and give some feedback (you'll have to set the sliding time, 
in the client options, to a non-zero value - I use 500 ms).  Is there a 
difference in responsiveness under the patch?  Is the faster drawing 
worth it?

jason

? newtiles
Index: client/gui-gtk-2.0/mapview.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/mapview.c,v
retrieving revision 1.143
diff -u -r1.143 mapview.c
--- client/gui-gtk-2.0/mapview.c        11 Oct 2004 01:52:16 -0000      1.143
+++ client/gui-gtk-2.0/mapview.c        16 Oct 2004 02:41:54 -0000
@@ -414,6 +414,35 @@
                    pixel_width, pixel_height);
 }
 
+#define MAX_DIRTY_RECTS 20
+static int num_dirty_rects = 0;
+static GdkRectangle dirty_rects[MAX_DIRTY_RECTS];
+static bool is_flush_queued = FALSE;
+
+/**************************************************************************
+  A callback invoked as a result of gtk_idle_add, this function simply
+  flushes the mapview canvas.
+**************************************************************************/
+static gint unqueue_flush(gpointer data)
+{
+  flush_dirty();
+  is_flush_queued = FALSE;
+  return 0;
+}
+
+/**************************************************************************
+  Called when a region is marked dirty, this function queues a flush event
+  to be handled later by GTK.  The flush may end up being done
+  by freeciv before then, in which case it will be a wasted call.
+**************************************************************************/
+static void queue_flush(void)
+{
+  if (!is_flush_queued) {
+    gtk_idle_add(unqueue_flush, NULL);
+    is_flush_queued = TRUE;
+  }
+}
+
 /**************************************************************************
   Mark the rectangular region as "dirty" so that we know to flush it
   later.
@@ -421,15 +450,14 @@
 void dirty_rect(int canvas_x, int canvas_y,
                int pixel_width, int pixel_height)
 {
-  /* GDK gives an error if we invalidate out-of-bounds parts of the
-     window. */
-  GdkRectangle rect = {MAX(canvas_x, 0), MAX(canvas_y, 0),
-                      MIN(pixel_width,
-                          map_canvas->allocation.width - canvas_x),
-                      MIN(pixel_height,
-                          map_canvas->allocation.height - canvas_y)};
-
-  gdk_window_invalidate_rect(map_canvas->window, &rect, FALSE);
+  if (num_dirty_rects < MAX_DIRTY_RECTS) {
+    dirty_rects[num_dirty_rects].x = canvas_x;
+    dirty_rects[num_dirty_rects].y = canvas_y;
+    dirty_rects[num_dirty_rects].width = pixel_width;
+    dirty_rects[num_dirty_rects].height = pixel_height;
+    num_dirty_rects++;
+    queue_flush();
+  }
 }
 
 /**************************************************************************
@@ -437,10 +465,8 @@
 **************************************************************************/
 void dirty_all(void)
 {
-  GdkRectangle rect = {0, 0, map_canvas->allocation.width,
-                      map_canvas->allocation.height};
-
-  gdk_window_invalidate_rect(map_canvas->window, &rect, FALSE);
+  num_dirty_rects = MAX_DIRTY_RECTS;
+  queue_flush();
 }
 
 /**************************************************************************
@@ -450,7 +476,18 @@
 **************************************************************************/
 void flush_dirty(void)
 {
-  gdk_window_process_updates(map_canvas->window, FALSE);
+  if (num_dirty_rects == MAX_DIRTY_RECTS) {
+    flush_mapcanvas(0, 0, map_canvas->allocation.width,
+                   map_canvas->allocation.height);
+  } else {
+    int i;
+
+    for (i = 0; i < num_dirty_rects; i++) {
+      flush_mapcanvas(dirty_rects[i].x, dirty_rects[i].y,
+                     dirty_rects[i].width, dirty_rects[i].height);
+    }
+  }
+  num_dirty_rects = 0;
 }
 
 /****************************************************************************
? fctest
? freeciv-2.0.0-beta1.tar.gz
Index: client/mapview_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/mapview_common.c,v
retrieving revision 1.151.2.3
diff -u -r1.151.2.3 mapview_common.c
--- client/mapview_common.c     9 Oct 2004 16:00:37 -0000       1.151.2.3
+++ client/mapview_common.c     11 Oct 2004 22:16:39 -0000
@@ -503,6 +503,7 @@
     int diff_x, diff_y;
     double timing_sec = (double)smooth_center_slide_msec / 1000.0, mytime;
     static struct timer *anim_timer;
+    int frames = 0;
 
     gui_distance_vector(&diff_x, &diff_y, start_x, start_y, gui_x0, gui_y0);
     anim_timer = renew_timer_start(anim_timer, TIMER_USER, TIMER_ACTIVE);
@@ -514,7 +515,12 @@
                              start_y + diff_y * (mytime / timing_sec));
       flush_dirty();
       gui_flush();
+      frames++;
     } while (mytime < timing_sec);
+
+    mytime = read_timer_seconds(anim_timer);
+    freelog(LOG_NORMAL, "Got %d frames in %f seconds; %f FPS.",
+           frames, mytime, (float)frames / mytime);
   } else {
     base_set_mapview_origin(gui_x0, gui_y0);
   }

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] (PR#10549) don't use GDK for mapview dirty/flush operations in gui-gtk-2.0, Jason Short <=