[xiph-commits] r11965 - trunk/sushivision

xiphmont at svn.xiph.org xiphmont at svn.xiph.org
Fri Oct 27 17:58:52 PDT 2006


Author: xiphmont
Date: 2006-10-27 17:58:49 -0700 (Fri, 27 Oct 2006)
New Revision: 11965

Modified:
   trunk/sushivision/main.c
   trunk/sushivision/panel-2d.c
   trunk/sushivision/plot.c
Log:
Decouple scale drawing from primary UI thread to keep sliders
responsive; this feature trips a bug in currently released versions of
Cairo that will cause an abort-- you will need the patch attached to
bug 8801 in Cairo CVS in order to use Sushivision from this commit on
(obviously, next release of Cairo should be fixed... that would be
1.2.6).



Modified: trunk/sushivision/main.c
===================================================================
--- trunk/sushivision/main.c	2006-10-27 23:07:12 UTC (rev 11964)
+++ trunk/sushivision/main.c	2006-10-28 00:58:49 UTC (rev 11965)
@@ -34,6 +34,9 @@
 #include "sushivision.h"
 #include "internal.h"
 
+
+static pthread_mutex_t gdkm;
+static pthread_mutexattr_t gdkma;
 static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
 static pthread_cond_t mc = PTHREAD_COND_INITIALIZER;
 sig_atomic_t _sushiv_exiting=0;
@@ -132,11 +135,29 @@
     sushiv_realize_instance(instance_list[i]);
 }
 
+static void recursive_gdk_lock(void){
+  pthread_mutex_lock(&gdkm);
+}
+
+static void recursive_gdk_unlock(void){
+  pthread_mutex_unlock(&gdkm);
+
+}
+
 int main (int argc, char *argv[]){
   int ret;
 
   gtk_init (&argc, &argv);
   g_thread_init (NULL);
+
+  // correct an annoying default of gdk (use of non-recursive mutexes)
+  // otherwise we'd need seperate versions of each widget method that
+  // would be called outside the main thread
+  pthread_mutexattr_init(&gdkma);
+  pthread_mutexattr_settype(&gdkma,PTHREAD_MUTEX_RECURSIVE);
+  pthread_mutex_init(&gdkm,&gdkma);
+  gdk_threads_set_lock_functions(recursive_gdk_lock,recursive_gdk_unlock);
+  
   gdk_threads_init ();
   gtk_rc_parse_string(gtkrc_string());
   gtk_rc_add_default_file("sushi-gtkrc");

Modified: trunk/sushivision/panel-2d.c
===================================================================
--- trunk/sushivision/panel-2d.c	2006-10-27 23:07:12 UTC (rev 11964)
+++ trunk/sushivision/panel-2d.c	2006-10-28 00:58:49 UTC (rev 11965)
@@ -397,14 +397,14 @@
 int _sushiv_panel_cooperative_compute_2d(sushiv_panel_t *p){
   sushiv_panel2d_t *p2 = (sushiv_panel2d_t *)p->internal;
   Plot *plot;
-
+  
   int w,h,i,d;
   int serialno;
   double x_min, x_max;
   double y_min, y_max;
   double invh;
   int x_d=-1, y_d=-1;
-
+  int render_scale_flag = 0;
   // lock during setup
   gdk_threads_enter ();
   w = p2->data_w;
@@ -466,10 +466,7 @@
   }
 
   // update scales if we're just starting
-  if(p2->last_line==0){
-    plot_set_x_scale(PLOT(p2->graph),x_min,x_max);
-    plot_set_y_scale(PLOT(p2->graph),y_min,y_max); 
-  }
+  if(p2->last_line==0) render_scale_flag = 1;
 
   /* iterate */
   /* by line */
@@ -482,6 +479,13 @@
 
     /* unlock for computation */
     gdk_threads_leave ();
+
+    if(render_scale_flag){
+      plot_set_x_scale(plot,x_min,x_max);
+      plot_set_y_scale(plot,y_min,y_max); 
+      render_scale_flag = 0;
+    }
+
     y = v_swizzle(last,h);
     dim_vals[y_d]= (y_max - y_min) * h * y;
 

Modified: trunk/sushivision/plot.c
===================================================================
--- trunk/sushivision/plot.c	2006-10-27 23:07:12 UTC (rev 11964)
+++ trunk/sushivision/plot.c	2006-10-28 00:58:49 UTC (rev 11965)
@@ -33,9 +33,10 @@
 
 static GtkWidgetClass *parent_class = NULL;
 
-static void draw_scales(Plot *p){
-  GtkWidget *widget = GTK_WIDGET(p);
-  cairo_t *c = cairo_create(p->fore);
+static void draw_scales_work(cairo_surface_t *s, scalespace xs, scalespace ys){
+  int w = cairo_image_surface_get_width(s);
+  int h = cairo_image_surface_get_height(s);
+  cairo_t *c = cairo_create(s);
   int i=0,x,y;
   char buffer[80];
 
@@ -53,19 +54,19 @@
   cairo_set_source_rgba(c,.7,.7,1.,.3);
 
   i=0;
-  x=scalespace_mark(&p->x,i++);
-  while(x < widget->allocation.width){
+  x=scalespace_mark(&xs,i++);
+  while(x < w){
     cairo_move_to(c,x+.5,0);
-    cairo_line_to(c,x+.5,widget->allocation.height);
-    x=scalespace_mark(&p->x,i++);
+    cairo_line_to(c,x+.5,h);
+    x=scalespace_mark(&xs,i++);
   }
 
   i=0;
-  y=scalespace_mark(&p->y,i++);
-  while(y < widget->allocation.height){
-    cairo_move_to(c,0,widget->allocation.height-y+.5);
-    cairo_line_to(c,widget->allocation.width,widget->allocation.height-y+.5);
-    y=scalespace_mark(&p->y,i++);
+  y=scalespace_mark(&ys,i++);
+  while(y < h){
+    cairo_move_to(c,0,h-y+.5);
+    cairo_line_to(c,w,h-y+.5);
+    y=scalespace_mark(&ys,i++);
   }
   cairo_stroke(c);
   cairo_restore(c);
@@ -78,16 +79,16 @@
   cairo_set_line_width(c,2);
 
   i=0;
-  y=scalespace_mark(&p->y,i);
-  scalespace_label(&p->y,i++,buffer);
+  y=scalespace_mark(&ys,i);
+  scalespace_label(&ys,i++,buffer);
 
-  while(y < widget->allocation.height){
+  while(y < h){
     cairo_text_extents_t extents;
     cairo_text_extents (c, buffer, &extents);
 
     if(y - extents.height > 0){
       
-      double yy = widget->allocation.height-y+.5-(extents.height/2 + extents.y_bearing);
+      double yy = h-y+.5-(extents.height/2 + extents.y_bearing);
 
       cairo_move_to(c,2, yy);
       cairo_set_source_rgba(c,0,0,0,.5);
@@ -99,20 +100,20 @@
       cairo_show_text (c, buffer);
     }
 
-    y=scalespace_mark(&p->y,i);
-    scalespace_label(&p->y,i++,buffer);
+    y=scalespace_mark(&ys,i);
+    scalespace_label(&ys,i++,buffer);
   }
 
   i=0;
-  x=scalespace_mark(&p->x,i);
-  scalespace_label(&p->x,i++,buffer);
+  x=scalespace_mark(&xs,i);
+  scalespace_label(&xs,i++,buffer);
   
   {
-    cairo_matrix_t m = {0.,-1., 1.,0.,  0.,widget->allocation.height};
+    cairo_matrix_t m = {0.,-1., 1.,0.,  0.,h};
     cairo_set_matrix(c,&m);
   }
 
-  while(x < widget->allocation.width){
+  while(x < w){
     cairo_text_extents_t extents;
     cairo_text_extents (c, buffer, &extents);
 
@@ -128,13 +129,33 @@
       cairo_show_text (c, buffer);
     }
 
-    x=scalespace_mark(&p->x,i);
-    scalespace_label(&p->x,i++,buffer);
+    x=scalespace_mark(&xs,i);
+    scalespace_label(&xs,i++,buffer);
   }
 
   cairo_destroy(c);
 }
 
+// enter with lock; releases lock before exit
+static void draw_scales(Plot *p){
+  // render into a temporary surface; do it [potentially] outside the global Gtk lock.
+  scalespace x = p->x;
+  scalespace y = p->y;
+  int w = GTK_WIDGET(p)->allocation.width;
+  int h = GTK_WIDGET(p)->allocation.height;
+  cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,w,h);
+  gdk_threads_leave();
+  
+  draw_scales_work(s,x,y);
+  
+  gdk_threads_enter();
+  // swap fore/temp
+  cairo_surface_t *temp = p->fore;
+  p->fore = s;
+  cairo_surface_destroy(temp);
+  plot_expose_request(p);
+  gdk_threads_leave();
+}
 
 static void plot_init (Plot *p){
   // instance initialization
@@ -169,7 +190,7 @@
 
 }
 
-void plot_draw (Plot *p,
+static void plot_draw (Plot *p,
 		int x, int y, int w, int h){
 
   GtkWidget *widget = GTK_WIDGET(p);
@@ -302,7 +323,8 @@
   widget->allocation = *allocation;
   p->x = scalespace_linear(p->x.lo,p->x.hi,widget->allocation.width,p->scalespacing);
   p->y = scalespace_linear(p->y.lo,p->y.hi,widget->allocation.height,p->scalespacing);
-  draw_scales(p);
+  gdk_threads_enter();
+  draw_scales(p); // releases one lock level
   if(p->recompute_callback)p->recompute_callback(p->app_data);
 
 }
@@ -414,6 +436,8 @@
 }
 
 void plot_expose_request(Plot *p){
+  gdk_threads_enter();
+
   GtkWidget *widget = GTK_WIDGET(p);
   GdkRectangle r;
   
@@ -423,9 +447,11 @@
   r.height=widget->allocation.height;
   
   gdk_window_invalidate_rect (widget->window, &r, FALSE);
+  gdk_threads_leave();
 }
 
 void plot_expose_request_line(Plot *p, int num){
+  gdk_threads_enter();
   GtkWidget *widget = GTK_WIDGET(p);
   GdkRectangle r;
   
@@ -435,42 +461,44 @@
   r.height=1;
   
   gdk_window_invalidate_rect (widget->window, &r, FALSE);
+  gdk_threads_leave();
 }
 
-void plot_draw_line(Plot *p, int num){
-  GtkWidget *widget = GTK_WIDGET(p);
-  //GdkRectangle r;
-  
-  plot_draw(p,0,num,widget->allocation.width,1);
-}
-
 void plot_set_x_scale(Plot *p, double low, double high){
+  gdk_threads_enter();
   GtkWidget *widget = GTK_WIDGET(p);
   scalespace temp = p->x;
   p->x = scalespace_linear(low,high,widget->allocation.width,p->scalespacing);
   p->selx = scalespace_pixel(&p->x,p->selx_val);
   if(memcmp(&temp,&p->x,sizeof(temp)))
-    draw_scales(p);
+    draw_scales(p); // releases one lock level
+  else
+    gdk_threads_leave();
 }
 
 void plot_set_y_scale(Plot *p, double low, double high){
+  gdk_threads_enter();
   GtkWidget *widget = GTK_WIDGET(p);
   scalespace temp = p->y;
   p->y = scalespace_linear(low,high,widget->allocation.height,p->scalespacing);
   p->sely = widget->allocation.height - scalespace_pixel(&p->y,p->sely_val);
 
   if(memcmp(&temp,&p->y,sizeof(temp)))
-    draw_scales(p);
+    draw_scales(p); // releases one lock level
+  else
+    gdk_threads_leave();
 }
 
 void plot_set_x_name(Plot *p, char *name){
+  gdk_threads_enter();
   p->namex = name;
-  draw_scales(p);
+  draw_scales(p); // releases one lock level
 }
 
 void plot_set_y_name(Plot *p, char *name){
+  gdk_threads_enter();
   p->namey = name;
-  draw_scales(p);
+  draw_scales(p); // releases one lock level
 }
 
 u_int32_t *plot_get_background_line(Plot *p, int num){
@@ -479,14 +507,19 @@
 }
 
 cairo_t *plot_get_background_cairo(Plot *p){
-  return cairo_create(p->back);
+  gdk_threads_enter();
+  cairo_t *ret= cairo_create(p->back);
+  gdk_threads_leave();
+  return ret;
 }
 
 void plot_set_crosshairs(Plot *p, double x, double y){
+  gdk_threads_enter();
   p->selx_val = x;
   p->sely_val = y;
   p->selx = scalespace_pixel(&p->x,x);
   p->sely = GTK_WIDGET(p)->allocation.height - scalespace_pixel(&p->y,y);
 
   plot_expose_request(p);
+  gdk_threads_leave();
 }



More information about the commits mailing list