[xiph-commits] r12409 - trunk/sushivision

xiphmont at svn.xiph.org xiphmont at svn.xiph.org
Wed Jan 31 20:53:53 PST 2007


Author: xiphmont
Date: 2007-01-31 20:53:51 -0800 (Wed, 31 Jan 2007)
New Revision: 12409

Modified:
   trunk/sushivision/panel-2d.c
   trunk/sushivision/panel-2d.h
   trunk/sushivision/plot.c
   trunk/sushivision/plot.h
   trunk/sushivision/scale.c
Log:
Implement *much* finer locking around remap operations on 2d panels;
this was absolutely necessary for UI responsiveness with massively
oversampled panels, or discrete dimensions with the same effect.

This also results in much better CPU utilization on multiprocessor
boxes when map updates are taking appreciable amounts of time.



Modified: trunk/sushivision/panel-2d.c
===================================================================
--- trunk/sushivision/panel-2d.c	2007-02-01 04:50:34 UTC (rev 12408)
+++ trunk/sushivision/panel-2d.c	2007-02-01 04:53:51 UTC (rev 12409)
@@ -86,7 +86,6 @@
     }
   }
   gdk_threads_leave ();
-
 }
 
 // call with lock
@@ -130,7 +129,7 @@
     dim_vals[i]=dim->val;
   }
 
-  gdk_threads_leave();
+  gdk_threads_leave ();
 
   dim_vals[x_d] = x;
   dim_vals[y_d] = y;
@@ -183,26 +182,31 @@
       }
     }
   }
-  gdk_threads_enter();
+  gdk_threads_enter ();
 
 }
 
 /* functions that perform actual graphical rendering */
 
-static void render_checks(int w, int y, u_int32_t *render){
-  int x,j;
+static void render_checks(int w, int h, u_int32_t *render){
   /* default checked background */
   /* 16x16 'mid-checks' */ 
-  int phase = (y>>4)&1;
-  for(x=0;x<w;){
-    u_int32_t phaseval = 0x505050;
-    if(phase) phaseval = 0x808080;
-    for(j=0;j<16 && x<w;j++,x++)
-      render[x] = phaseval;
-    phase=!phase;
+  int x,y,j;
+
+  for(y=0;y<h;y++){
+    int phase = (y>>4)&1;
+    for(x=0;x<w;){
+      u_int32_t phaseval = 0x505050;
+      if(phase) phaseval = 0x808080;
+      for(j=0;j<16 && x<w;j++,x++)
+	render[x] = phaseval;
+      phase=!phase;
+    }
+    render += w;
   }
 }
 
+// called without any locks; all passed in data is locally replicated 
 static void resample_render_y_plane_line(mapping *map, float obj_alpha,
 					 float *r, float *g, float *b, float linedel,
 					 u_int32_t *panel, scalespace panelx,
@@ -220,12 +224,11 @@
   for(i=0;i<pw;i++){
     float alpha=x_scaledel;
     float x_del2 = x_del + x_scaledel;
-      
+    
     while(x_del2>=1.f){
-      float addel = (1.f - x_del);
-      float pixdel = addel*linedel;
-
       if(x_bin >= 0 && x_bin < dw){
+	float addel = (1.f - x_del);
+	float pixdel = addel*linedel;
 	float val = data[x_bin];
 	if(!isnan(val) && val >= obj_alpha){
 	  u_int32_t partial = mapping_calc(map,val,panel[i]);
@@ -242,10 +245,9 @@
     }
     
     if(x_del2>0.f){
-      float addel = (x_del2 - x_del);
-      float pixdel = addel*linedel;
-      
       if(x_bin >= 0 && x_bin < dw){
+	float addel = (x_del2 - x_del);
+	float pixdel = addel*linedel;
 	float val = data[x_bin];
 	if(!isnan(val) && val >= obj_alpha){
 	  u_int32_t partial = mapping_calc(map,val,panel[i]);
@@ -271,24 +273,32 @@
 
 /* the data rectangle is data width/height mapped deltas.  we render
    and subsample at the same time. */
-static void resample_render_y_plane(mapping *map, float obj_alpha,
+/* enter with no locks; all arguments are replicated local storage
+   except for the contents of data, which must be locked and checked
+   against serialno */
+static void resample_render_y_plane(sushiv_panel2d_t *p2, int serialno, 
+				    mapping *map, float obj_alpha,
 				    u_int32_t *panel, scalespace panelx, scalespace panely,
 				    float *data, scalespace datax, scalespace datay){
   int pw = panelx.pixels;
   int dw = datax.pixels;
   int ph = panely.pixels;
   int dh = datay.pixels;
+  u_int32_t *line;
+  float dline[dw];
   int i,j;
 
+  if(!data)return;
+
   if(ph!=dh || pw!=dw){
     /* resampled row computation */
-    
+
     /* by line */
     float y_scaledel = scalespace_scaledel(&panely,&datay);
     float y_del = scalespace_pixel(&datay,scalespace_value(&panely,-.5))+.5;
     int y_bin = floor(y_del);
     y_del -= y_bin; 
-    
+
     for(i=0;i<ph;i++){
       /* render is done into a temporary line because of the way alpha
 	 blending is done; the background for the blend must be taken
@@ -296,27 +306,32 @@
       float r[pw]; 
       float g[pw]; 
       float b[pw]; 
-      float alpha = y_scaledel;
+      float alpha = 1.;
       float idel = 1./y_scaledel;
       float y_del2 = y_del + y_scaledel;
-      u_int32_t *line = panel+i*pw;
-      
-      /* the x resample may have blends as well */
+
       memset(r,0,sizeof(r)); 
       memset(g,0,sizeof(g)); 
       memset(b,0,sizeof(b)); 
+
+      line=panel+i*pw;
       
       while(y_del2>=1.f){
 	float addel = (1.f - y_del);
-	
 	if(y_bin >= 0 && y_bin < dh){
+
+	  gdk_threads_enter ();
+	  if(serialno != p2->serialno) goto abort;
+	  memcpy(dline,data+y_bin*dw,sizeof(dline));
+	  gdk_threads_leave ();
+
 	  resample_render_y_plane_line(map,obj_alpha,
 				       r,g,b,addel * idel,
 				       line,
 				       panelx,
 				       data+y_bin*dw,
 				       datax);
-	  alpha -= addel;
+	  alpha -= addel * idel;
 	}
 	
 	y_del2--;
@@ -328,71 +343,120 @@
 	float addel = (y_del2 - y_del);
 	
 	if(y_bin >= 0 && y_bin < dh){
+
+	  gdk_threads_enter ();
+	  if(serialno != p2->serialno) goto abort;
+	  memcpy(dline,data+y_bin*dw,sizeof(dline));
+	  gdk_threads_leave ();
+
 	  resample_render_y_plane_line(map,obj_alpha,
 				       r,g,b,addel * idel,
 				       line,
 				       panelx,
 				       data+y_bin*dw,
 				       datax);
-	  alpha -= addel;
+	  alpha -= addel * idel;
 	}
 	y_del += addel;
       }
 
       /* work is finished; replace panel line with it */
-      if(alpha<0.f)alpha=0.f; // guard rounding error;
-
-      for(j=0;j<pw;j++){
-	int ri = rint(r[j]*0xff0000.p0f +  (line[j]&0xff0000) * alpha);
-	int gi = rint(g[j]*0xff00.p0f +  (line[j]&0xff00) * alpha);
-	int bi = rint(b[j]*0xff.p0f +  (line[j]&0xff) * alpha);
-	
-	line[j] = (ri&0xff0000) + (gi&0xff00) + (bi&0xff);
+      if(alpha>.0001){ // less than a color step of rounding error
+	for(j=0;j<pw;j++){
+	  int ri = rint(r[j]*0xff0000.p0f +  (line[j]&0xff0000) * alpha);
+	  int gi = rint(g[j]*0xff00.p0f +  (line[j]&0xff00) * alpha);
+	  int bi = rint(b[j]*0xff.p0f +  (line[j]&0xff) * alpha);
+	  
+	  line[j] = (ri&0xff0000) + (gi&0xff00) + (bi&0xff);
+	}
+      }else{
+	for(j=0;j<pw;j++){
+	  int ri = rint(r[j]*0xff0000.p0f);
+	  int gi = rint(g[j]*0xff00.p0f);
+	  int bi = rint(b[j]*0xff.p0f);
+	  
+	  line[j] = (ri&0xff0000) + (gi&0xff00) + (bi&0xff);
+	}
       }
     }      
   }else{
     /* non-resampling render */
     for(i=0;i<ph;i++){
-      u_int32_t *pline = panel+i*pw;
       float *dline = data+i*pw;
+      line=panel+i*pw;
+
+      gdk_threads_enter ();
+      if(serialno != p2->serialno) goto abort;
+      memcpy(dline,data+i*dw,sizeof(dline));
+      gdk_threads_leave ();
+      
       for(j=0;j<pw;j++){
 	float val = dline[j];
 	if(!isnan(val) && val >= obj_alpha)
-	  pline[j] = mapping_calc(map,val,pline[j]);
+	  line[j] = mapping_calc(map,val,line[j]);
       }
     }
   }
+  return;
+ abort:
+  gdk_threads_leave ();
 }
 
 static void _sushiv_panel2d_remap(sushiv_panel_t *p){
   sushiv_panel2d_t *p2 = p->subtype->p2;
   Plot *plot = PLOT(p->private->graph);
+  int pw,ph,i;
 
-  int pw,ph,y,i;
-  pw = p2->x.pixels;
-  ph = p2->y.pixels;
+  if(!plot) return;
 
-  if(plot){
-    /* background checks */
-    for(y = 0; y<ph; y++)
-      render_checks(pw,y,plot->datarect + y*pw);
-      
-    /* by objective */
-    for(i=0;i<p->objectives;i++){
+  gdk_threads_enter ();
+    
+  // marshall all the locked data we'll need
+  scalespace x = p2->x;
+  scalespace y = p2->y;
+  scalespace x_v = p2->x_v;
+  scalespace y_v = p2->y_v;
+  u_int32_t *doublebuff = malloc(x.pixels*y.pixels*sizeof(*doublebuff));
 
-      /**** render Y plane */
-      int o_ynum = p2->y_obj_from_panel[i];
-      if(p2->y_map[o_ynum])
-	resample_render_y_plane(p2->mappings+i, p2->alphadel[i],
-				plot->datarect, p2->x, p2->y,
-				p2->y_map[o_ynum], p2->x_v, p2->y_v);
-      
-      /**** render Z plane */
-      
-      /**** render vector plane */
+  double alphadel[p->objectives];
+  mapping mappings[p->objectives];
+  int serialno = p2->serialno;
+  float *y_rects[p2->y_obj_num];
 
-    }
+  memcpy(alphadel, p2->alphadel, sizeof(alphadel));
+  memcpy(mappings, p2->mappings, sizeof(mappings));
+  memcpy(y_rects, p2->y_map, sizeof(y_rects));
+  
+  pw = plot->x.pixels;
+  ph = plot->y.pixels;
+  
+  /* background checks */
+  render_checks(pw,ph,doublebuff);
+  gdk_threads_leave();
+  
+  /* by objective */
+  for(i=0;i<p->objectives;i++){
+    
+    /**** render Y plane */
+    int o_ynum = p2->y_obj_from_panel[i];
+    resample_render_y_plane(p2, serialno, 
+			    mappings+i, alphadel[i],
+			    doublebuff, x, y,
+			    y_rects[o_ynum], x_v, y_v);
+    
+    /**** render Z plane */
+    
+    /**** render vector plane */
+
   }
+
+  gdk_threads_enter ();
+  if(serialno == p2->serialno){
+    plot_replace_data(plot,doublebuff);
+  }else{
+    free(doublebuff);
+  }
+  gdk_threads_leave();
 }
 
 static void update_legend(sushiv_panel_t *p){  
@@ -400,7 +464,6 @@
   Plot *plot = PLOT(p->private->graph);
 
   gdk_threads_enter ();
-
   if(plot){
     int i;
     char buffer[320];
@@ -439,30 +502,27 @@
 	}
       }
     }
-    gdk_threads_leave ();
   }
+  gdk_threads_leave ();
 }
 
 static void _sushiv_panel2d_map_redraw(sushiv_panel_t *p){
   Plot *plot = PLOT(p->private->graph);
 
-  gdk_threads_enter (); // misuse me as a global mutex
-  
   _sushiv_panel2d_remap(p);
+
   if(plot)
     plot_expose_request(plot);
- 
-  gdk_threads_leave (); // misuse me as a global mutex
+
 }
 
 static void _sushiv_panel2d_legend_redraw(sushiv_panel_t *p){
   Plot *plot = PLOT(p->private->graph);
 
-  gdk_threads_enter (); // misuse me as a global mutex
-    update_legend(p);
+  update_legend(p);
+
   if(plot)
     plot_draw_scales(plot);
-  gdk_threads_leave (); // misuse me as a global mutex
 }
 
 static void mapchange_callback_2d(GtkWidget *w,gpointer in){
@@ -779,6 +839,7 @@
     p2->serialno++;
     p2->last_line = 0;
     p2->completed_lines = 0;
+    p2->scaling_in_progress = 0; 
     
     _sushiv_panel1d_mark_recompute_linked(p);   
     _sushiv_wake_workers();
@@ -958,12 +1019,12 @@
   double x_min, x_max;
   double y_min, y_max;
   int x_d=-1, y_d=-1;
-  int render_scale_flag = 0;
   scalespace sx,sx_v,sx_i;
   scalespace sy,sy_v,sy_i;
 
   // lock during setup
   gdk_threads_enter ();
+  serialno = p2->serialno;
   plot = PLOT(p->private->graph);
   pw = plot->x.pixels;
   ph = plot->y.pixels;
@@ -974,6 +1035,9 @@
   // beginning of computation init
   if(p2->last_line==0){
 
+    scalespace old_xv = p2->x_v;
+    scalespace old_yv = p2->y_v;
+
     // generate new scales
     _sushiv_dimension_scales(p2->x_d, 
 			     p2->x_d->bracket[0],
@@ -994,24 +1058,6 @@
 			     &sy_v,
 			     &sy_i);
     
-    // maintain data planes
-    for(i=0;i<p2->y_obj_num;i++){
-      // allocate new storage
-      float *newmap = calloc(sx_v.pixels*sy_v.pixels,sizeof(*newmap));
-      float *oldmap = p2->y_map[i];
-      int j;
-      for(j=0;j<sx_v.pixels*sy_v.pixels;j++)
-	newmap[j]=NAN;
-
-      // zoom scale data in map planes as placeholder for render
-      if(oldmap)
-	fast_scale(newmap, sx_v, sy_v,
-		   oldmap,p2->x_v, p2->y_v);
-      
-      p2->y_map[i] = newmap;
-      if(oldmap) free(oldmap);
-    }
-
     p2->x = sx;
     p2->x_v = sx_v;
     p2->x_i = sx_i;
@@ -1022,13 +1068,54 @@
     plot->x = sx;
     plot->y = sy;
 
-    _sushiv_panel2d_remap(p);
     p2->last_line++;
-    gdk_threads_leave ();
-    plot_draw_scales(plot);
+    
+    if(memcmp(&sx_v,&old_xv,sizeof(sx_v)) || memcmp(&sy_v,&old_yv,sizeof(sy_v))){
+      p2->scaling_in_progress = 1;
+      
+      // maintain data planes
+      for(i=0;i<p2->y_obj_num;i++){
+	// allocate new storage
+	float *newmap = calloc(sx_v.pixels*sy_v.pixels,sizeof(*newmap));
+	float *oldmap = p2->y_map[i];
+	int j;
+	
+	p2->y_map[i] = NULL;
+	gdk_threads_leave ();
+	
+	for(j=0;j<sx_v.pixels*sy_v.pixels;j++)
+	  newmap[j]=NAN;
+	
+	// zoom scale data in map planes as placeholder for render
+	if(oldmap){
+	  fast_scale(newmap, sx_v, sy_v,
+		     oldmap,old_xv, old_yv);
+	  free(oldmap);
+	}
+	
+	gdk_threads_enter ();
+	if(p2->serialno != serialno){
+	  gdk_threads_leave();
+	  return 1;
+	}
+	p2->y_map[i] = newmap;
+      }
+      
+      p2->scaling_in_progress = 0;
+      gdk_threads_leave ();
+      _sushiv_wake_workers();   
+      _sushiv_panel2d_remap(p);
+      plot_draw_scales(plot);
 
+    }else
+      gdk_threads_leave ();
+
     return 1;
   }else{
+    if(p2->scaling_in_progress){
+      gdk_threads_leave();
+      return 0;
+    }
     sx = p2->x;
     sx_v = p2->x_v;
     sx_i = p2->x_i;
@@ -1047,7 +1134,6 @@
 
   _maintain_cache_2d(p,&c->p2,dw);
   
-  serialno = p2->serialno;
   d = p->dimensions;
 
   /* render using local dimension array; several threads will be
@@ -1101,9 +1187,10 @@
 
 static void recompute_callback_2d(void *ptr){
   sushiv_panel_t *p = (sushiv_panel_t *)ptr;
+  Plot *plot = PLOT(p->private->graph);
+  render_checks(plot->x.pixels, plot->y.pixels, plot->datarect);
   _mark_recompute_2d(p);
-  // force the remap scaling to happen before an expose blanks the pane
-  _sushiv_panel_cooperative_compute_2d(p,NULL);
+  _sushiv_panel_cooperative_compute_2d(p,NULL); // initial scale setup
 }
 
 static void panel2d_undo_log(sushiv_panel_undo_t *u, sushiv_panel_t *p){
@@ -1604,7 +1691,7 @@
   }
 
   p2->y_map = calloc(p2->y_obj_num,sizeof(*p2->y_map));
-  
+
   return 0;
 }
 

Modified: trunk/sushivision/panel-2d.h
===================================================================
--- trunk/sushivision/panel-2d.h	2007-02-01 04:50:34 UTC (rev 12408)
+++ trunk/sushivision/panel-2d.h	2007-02-01 04:53:51 UTC (rev 12409)
@@ -26,8 +26,9 @@
   GtkWidget *popmenu;
   GtkWidget *graphmenu;
 
-  int serialno;
-  
+  int serialno;              // timestamps access to map planes, widget pixels
+  int scaling_in_progress;
+
   /* only run those functions used by this panel */
   int used_functions;
   sushiv_function_t **used_function_list;

Modified: trunk/sushivision/plot.c
===================================================================
--- trunk/sushivision/plot.c	2007-02-01 04:50:34 UTC (rev 12408)
+++ trunk/sushivision/plot.c	2007-02-01 04:53:51 UTC (rev 12409)
@@ -487,6 +487,8 @@
       cairo_surface_destroy(p->fore);
     if (p->back)
       cairo_surface_destroy(p->back);
+    if(p->datarect)
+      free(p->datarect);
     if (p->stage)
       cairo_surface_destroy(p->stage);
     
@@ -962,7 +964,6 @@
 }
 
 int plot_get_crosshair_ypixel(Plot *p){
-  GtkWidget *widget = GTK_WIDGET(p);
   scalespace y;
   double v;
 
@@ -1039,3 +1040,22 @@
     p->legend_list[p->legend_entries-1] = strdup("");
   p->legend_colors[p->legend_entries-1] = color;
 }
+
+void plot_replace_data(Plot *p, u_int32_t *data){
+  gdk_threads_enter();
+  GtkWidget *widget = GTK_WIDGET(p);
+
+  if (p->back)
+    cairo_surface_destroy(p->back);
+  if(p->datarect)
+    free(p->datarect);
+  
+  p->datarect = data;  
+  p->back = cairo_image_surface_create_for_data ((unsigned char *)p->datarect,
+						 CAIRO_FORMAT_RGB24,
+						 widget->allocation.width,
+						 widget->allocation.height,
+						 widget->allocation.width*4);
+  gdk_threads_leave();
+}
+

Modified: trunk/sushivision/plot.h
===================================================================
--- trunk/sushivision/plot.h	2007-02-01 04:50:34 UTC (rev 12408)
+++ trunk/sushivision/plot.h	2007-02-01 04:53:51 UTC (rev 12409)
@@ -111,6 +111,7 @@
 void plot_legend_clear(Plot *p);
 int plot_get_crosshair_xpixel(Plot *p);
 int plot_get_crosshair_ypixel(Plot *p);
+void plot_replace_data(Plot *p, u_int32_t *d);
 
 void plot_do_enter(Plot *p);
 void plot_do_escape(Plot *p);

Modified: trunk/sushivision/scale.c
===================================================================
--- trunk/sushivision/scale.c	2007-02-01 04:50:34 UTC (rev 12408)
+++ trunk/sushivision/scale.c	2007-02-01 04:53:51 UTC (rev 12409)
@@ -246,6 +246,8 @@
 
   if(pixels<1)pixels=1;
 
+  memset(&ret,0,sizeof(ret)); // otherwise packing may do us in!
+
   ret.lo = lowpoint;
   ret.hi = highpoint;
   ret.init = 1;



More information about the commits mailing list