[xiph-commits] r12498 - trunk/sushivision

xiphmont at svn.xiph.org xiphmont at svn.xiph.org
Tue Feb 20 02:17:05 PST 2007


Author: xiphmont
Date: 2007-02-20 02:17:02 -0800 (Tue, 20 Feb 2007)
New Revision: 12498

Modified:
   trunk/sushivision/example_fractal.c
   trunk/sushivision/gtksucks.c
   trunk/sushivision/internal.h
   trunk/sushivision/main.c
   trunk/sushivision/panel-2d.c
   trunk/sushivision/panel-2d.h
   trunk/sushivision/panel.c
   trunk/sushivision/plot.c
   trunk/sushivision/plot.h
   trunk/sushivision/slice.c
Log:
2d panel rendering infrstructure now optimized to the logical extreme;
all ops are fully parallelized, including remap.



Modified: trunk/sushivision/example_fractal.c
===================================================================
--- trunk/sushivision/example_fractal.c	2007-02-20 04:17:27 UTC (rev 12497)
+++ trunk/sushivision/example_fractal.c	2007-02-20 10:17:02 UTC (rev 12498)
@@ -54,12 +54,12 @@
 
   s=sushiv_new_instance();
 
-  sushiv_new_dimension_discrete(s,0,"Re(c)",
+  sushiv_new_dimension(s,0,"Re(c)",
 		       5,(double []){-2.25,-0.75,0,0.25,0.75},
-				NULL,1,1000,0);
-  sushiv_new_dimension_discrete(s,1,"Im(c)",
+		       NULL,0);
+  sushiv_new_dimension(s,1,"Im(c)",
 		       5,(double []){-2,-1,0,1,2},
-				NULL,1,1000,0);
+		       NULL,0);
 
   sushiv_new_dimension(s,2,"Re(z0)",
 		       5,(double []){-2.25,-1,0,1,2.25},

Modified: trunk/sushivision/gtksucks.c
===================================================================
--- trunk/sushivision/gtksucks.c	2007-02-20 04:17:27 UTC (rev 12497)
+++ trunk/sushivision/gtksucks.c	2007-02-20 10:17:02 UTC (rev 12498)
@@ -134,7 +134,7 @@
    handler to each and every button on a toplevel.  This is mad
    whack.  The below 'fixes' buttons at the class level by ramming a
    new button press handler into the GtkButtonClass structure (and,
-   unfortunately, button subclasses as thir classes have also already
+   unfortunately, button subclasses as their classes have also already
    initialized and made a copy of the Button's class structure and
    handlers */ 
 
@@ -216,7 +216,6 @@
 
 static void recursive_gdk_unlock(void){
   pthread_mutex_unlock(&gdkm);
-
 }
 
 void gtk_mutex_fixup(){

Modified: trunk/sushivision/internal.h
===================================================================
--- trunk/sushivision/internal.h	2007-02-20 04:17:27 UTC (rev 12497)
+++ trunk/sushivision/internal.h	2007-02-20 10:17:02 UTC (rev 12498)
@@ -110,6 +110,8 @@
 
 extern void _sushiv_realize_panel(sushiv_panel_t *p);
 extern void _sushiv_clean_exit(int sig);
+extern void _sushiv_wake_workers();
+
 extern int _sushiv_new_panel(sushiv_instance_t *s,
 			     int number,
 			     const char *name, 
@@ -119,6 +121,7 @@
 
 extern void set_map_throttle_time(sushiv_panel_t *p);
 extern void _sushiv_panel_dirty_map(sushiv_panel_t *p);
+extern void _sushiv_panel_dirty_map_immediate(sushiv_panel_t *p);
 extern void _sushiv_panel_dirty_map_throttled(sushiv_panel_t *p);
 extern void _sushiv_panel_dirty_legend(sushiv_panel_t *p);
 extern void _sushiv_panel_dirty_plot(sushiv_panel_t *p);

Modified: trunk/sushivision/main.c
===================================================================
--- trunk/sushivision/main.c	2007-02-20 04:17:27 UTC (rev 12497)
+++ trunk/sushivision/main.c	2007-02-20 10:17:02 UTC (rev 12498)
@@ -116,25 +116,28 @@
 	  gdk_threads_enter();
 	  if(p->private->realized && p->private->graph){
 
-	    if(p->private->map_active){
+	    // pending computation work?
+	    if(p->private->plot_active){
 	      spinner_set_busy(p->private->spinner);
-	      flag |= p->private->map_action(p,&c[j][i]); // may drop lock internally
-	      if(!p->private->map_active)
-		set_map_throttle_time(p);
+	      flag |= p->private->compute_action(p,&c[j][i]); // may drop lock internally
 	    }
 	    
+	    if(p->private->map_active){
+	      int ret = 1;
+	      while(ret){ // favor completing remaps over other ops
+		spinner_set_busy(p->private->spinner);
+		flag |= ret = p->private->map_action(p,&c[j][i]); // may drop lock internally
+		if(!p->private->map_active)
+		  set_map_throttle_time(p);
+	      }
+	    }
+	    
 	    // pending legend work?
 	    if(p->private->legend_active){
 	      spinner_set_busy(p->private->spinner);
 	      flag |= p->private->legend_action(p); // may drop lock internally
 	    }
 	    
-	    // pending computation work?
-	    if(p->private->plot_active){
-	      spinner_set_busy(p->private->spinner);
-	      flag |= p->private->compute_action(p,&c[j][i]); // may drop lock internally
-	    }
-	    
 	    if(!p->private->plot_active &&
 	       !p->private->legend_active &&
 	       !p->private->map_active)
@@ -199,10 +202,9 @@
 
   num_threads = num_proccies();
 
+  gtk_mutex_fixup();
+  g_thread_init (NULL);
   gtk_init (&argc, &argv);
-  g_thread_init (NULL);
-
-  gtk_mutex_fixup();
   gdk_threads_init ();
   gtk_rc_parse_string(gtkrc_string());
   gtk_rc_add_default_file("sushi-gtkrc");
@@ -211,6 +213,7 @@
   if(ret)return ret;
   
   sushiv_realize_all();
+  gtk_button3_fixup();
   
   {
     pthread_t dummy;
@@ -222,8 +225,9 @@
   signal(SIGINT,_sushiv_clean_exit);
   //signal(SIGSEGV,_sushiv_clean_exit);
 
-  gtk_button3_fixup();
+  gdk_threads_enter();
   gtk_main ();
+  gdk_threads_leave();
   
   {
     int (*optional_exit)(void) = dlsym(RTLD_DEFAULT, "sushiv_atexit");

Modified: trunk/sushivision/panel-2d.c
===================================================================
--- trunk/sushivision/panel-2d.c	2007-02-20 04:17:27 UTC (rev 12497)
+++ trunk/sushivision/panel-2d.c	2007-02-20 10:17:02 UTC (rev 12498)
@@ -99,12 +99,35 @@
 static void clear_pane(sushiv_panel_t *p){
 
   sushiv_panel2d_t *p2 = p->subtype->p2;
+  int pw = p2->x.pixels;
+  int ph = p2->y.pixels;
   int i;
-
+  Plot *plot = PLOT(p->private->graph);
+  
   for(i=0;i<p2->y_obj_num;i++){
-    free(p2->y_map[i]);
+    // map is freed and nulled to avoid triggering a fast-scale on an empty data pane
+    if(p2->y_map[i])
+      free(p2->y_map[i]);
     p2->y_map[i]=NULL;
+
+    // free y_planes so that initial remap doesn't waste time on mix
+    // op; they are recreated during remap at the point the y_todo
+    // vector indicates something to do
+    if(p2->y_planes[i])
+      free(p2->y_planes[i]);
+    p2->y_planes[i] = NULL;
+
+    // work vector is merely cleared
+    memset(p2->y_planetodo[i], 0, ph*sizeof(**p2->y_planetodo));
   }
+
+  // clear the background surface 
+  if(plot->datarect)
+    memset(plot->datarect, 0, ph*pw*sizeof(*plot->datarect));
+
+  // the bg is not marked to be refreshed; computation setup will do
+  // that as part of the fast_scale, even if the fast_scale is
+  // short-circuited to a noop.
 }
 
 typedef struct{
@@ -195,25 +218,21 @@
 
 /* functions that perform actual graphical rendering */
 
-static void render_checks(int w, int h, ucolor *c){
+static void render_checks(ucolor *c, int w, int y){
   /* default checked background */
   /* 16x16 'mid-checks' */ 
-  int x,y,j;
+  int x,j;
   
-  for(y=0;y<h;y++){
-    int phase = (y>>4)&1;
-    for(x=0;x<w;){
-      u_int32_t phaseval = 0xff505050UL;
-      if(phase) phaseval = 0xff808080UL;
-      for(j=0;j<16 && x<w;j++,x++)
-	c[x].u = phaseval;
-      phase=!phase;
-    }
-    c += w;
+  int phase = (y>>4)&1;
+  for(x=0;x<w;){
+    u_int32_t phaseval = 0xff505050UL;
+    if(phase) phaseval = 0xff808080UL;
+    for(j=0;j<16 && x<w;j++,x++)
+      c[x].u = phaseval;
+    phase=!phase;
   }
 }
 
-
 static float resample_helpers_init(scalespace *to, scalespace *from,
 				   unsigned char *delA, unsigned char *delB, 
 				   int *posA, int *posB,
@@ -338,7 +357,7 @@
 				   int alpha, 
 				   int mul, 
 				   lcolor *outc){
-  if(mul && !isnan(in) && in>=alpha){
+  if(mul && in>=alpha){
     int val = rint((in - low) * range);
     if(val<0)val=0;
     if(val>65536)val=65536;
@@ -348,242 +367,404 @@
 
 /* the data rectangle is data width/height mapped deltas.  we render
    and subsample at the same time. */
-/* enter unlocked */
-static int resample_render_y_plane(sushiv_panel_t *p, _sushiv_bythread_cache_2d *c,
-				   int plot_serialno, int map_serialno,
-				   mapping *map, float obj_alpha,
-				   ucolor *panel, int *in_data){
+/* return: -1 == abort
+            0 == more work to be done in this plane
+	    1 == plane fully dispatched (possibly not complete) */
+
+/* enter with lock */
+static int resample_render_y_plane_line(sushiv_panel_t *p, _sushiv_bythread_cache_2d *c, 
+					int plot_serialno, int map_serialno, int y_no){
+
   sushiv_panel2d_t *p2 = p->subtype->p2;
-  int i,j;
-  int ol_alpha = rint(obj_alpha * (256.f*256.f*256.f));
-  int ol_low = rint(map->low * (256.f*256.f*256.f));
+  int objnum = p2->y_obj_to_panel[y_no]; 
+  int *in_data = p2->y_map[y_no];
+  int ph = p2->y.pixels;
+
+  if(!in_data || !c){
+    p->private->map_complete_count -= ph;
+    return 1;
+  }
+
+  unsigned char *todo = p2->y_planetodo[y_no];
+  int i = p2->y_next_line;
+  int j;
+
+  /* find a row that needs to be updated */
+  while(i<ph && !todo[i]){
+    p->private->map_complete_count--;
+    p2->y_next_line++;
+    i++;
+  }
+
+  if(i == ph) return 1;
+
+  p2->y_next_line++;
+
+  /* row [i] needs to be updated; marshal */
+  mapping *map = p2->mappings+objnum;
+  void (*mapfunc)(int,int, lcolor *) = map->mapfunc;
+  int ol_alpha = rint(p2->alphadel[y_no] * 16777216.f);
+  ucolor *panel = p2->y_planes[y_no];
+  int ol_low = rint(map->low * 16777216.f);
   float ol_range = map->i_range * (1.f/256.f);
-  if(!in_data || !c)return 1;
 
-  int *data = NULL;
-  
-  gdk_threads_enter ();
-  if(plot_serialno != p->private->plot_serialno) goto abort;
-
   int pw = p2->x.pixels;
   int dw = p2->x_v.pixels;
-  int ph = p2->y.pixels;
   int dh = p2->y_v.pixels;
-  
-  data = malloc(dw*dh*sizeof(*data));
-  memcpy(data,in_data,dw*dh*sizeof(*data));
+  ccolor work[pw];
 
+  if(!panel)
+    panel = p2->y_planes[y_no] = calloc(pw*ph, sizeof(**p2->y_planes));
+
   if(ph!=dh || pw!=dw){
-    /* resampled row computation */
+    /* resampled row computation; may involve multiple data rows */
 
     resample_helpers_manage_y(p);
     resample_helpers_manage_x(p,c);
 
     float idel = p2->yscalemul * c->xscalemul;
 
-    gdk_threads_leave ();
+    /* by column */
+    int ydelA=p2->ydelA[i];
+    int ydelB=p2->ydelB[i];
+    int ystart=p2->ynumA[i];
+    int yend=p2->ynumB[i];
+    int lh = yend - ystart;
+    int data[lh*dw];
 
-    /* by column */
+    memcpy(data,in_data+ystart*dw,sizeof(data));
+
+    gdk_threads_leave();
+
     unsigned char *xdelA = c->xdelA;
     unsigned char *xdelB = c->xdelB;
     int *xnumA = c->xnumA;
     int *xnumB = c->xnumB;
+      
+    /* by panel col */
+    for(j=0;j<pw;j++){
+	
+      lcolor out = (lcolor){0,0,0,0}; 
+      int xstart = xnumA[j];
+      int xend = xnumB[j];
+      int dx = xstart;
+      int xA = xdelA[j];
+      int xB = xdelB[j];
+      int y = ystart;
 
-    ucolor *mix = panel;
-    int xy=0;
-
-    /* by panel row */
-    for(i=0;i<ph;i++){
-
-      gdk_threads_enter ();  
-      if(plot_serialno != p->private->plot_serialno ||
-	 map_serialno != p->private->map_serialno)
-	goto abort;
-      spinner_set_busy(p->private->spinner);
-
-      int ydelA=p2->ydelA[i];
-      int ydelB=p2->ydelB[i];
+      // first line
+      l_mapping_calc(mapfunc, ol_low, ol_range, data[dx++], ol_alpha, ydelA*xA, &out);
       
-      int ynumA=p2->ynumA[i];
-      int yend=p2->ynumB[i];
+      for(; dx < xend-1; dx++)
+	l_mapping_calc(mapfunc, ol_low, ol_range, data[dx], ol_alpha, ydelA*17, &out);
       
-      gdk_threads_leave();
+      if(dx<xend)
+	l_mapping_calc(mapfunc, ol_low, ol_range, data[dx], ol_alpha, ydelA*xB, &out);
+      y++;
       
-      /* by panel col */
-      for(j=0;j<pw;j++){
+	// mid lines
+      for(;y<yend-1;y++){
+	dx = xstart += dw;
+	xend += dw;
+	l_mapping_calc(mapfunc, ol_low, ol_range, data[dx++], ol_alpha, 15*xA, &out);
 	
-	lcolor out = (lcolor){0,0,0,0}; 
-	int ydel = ydelA;
-	int y = ynumA;
-
-	int xstart = y*dw + xnumA[j];
-	int xend = y*dw + xnumB[j];
-	int dx = xstart;
-	int xA = xdelA[j];
-	int xB = xdelB[j];
-
-	// first line
-	l_mapping_calc(map->mapfunc, ol_low, ol_range, data[dx++], ol_alpha, ydel*xA, &out);
-
 	for(; dx < xend-1; dx++)
-	  l_mapping_calc(map->mapfunc, ol_low, ol_range, data[dx], ol_alpha, ydel*17, &out);
+	  l_mapping_calc(mapfunc, ol_low, ol_range, data[dx], ol_alpha, 255, &out);
 	
 	if(dx<xend)
-	  l_mapping_calc(map->mapfunc, ol_low, ol_range, data[dx], ol_alpha, ydel*xB, &out);
-	y++;
+	  l_mapping_calc(mapfunc, ol_low, ol_range, data[dx], ol_alpha, 15*xB, &out);
+      }
+      
+      // last line
+      if(y<yend){
+	dx = xstart += dw;
+	xend += dw;
+	l_mapping_calc(mapfunc, ol_low, ol_range, data[dx++], ol_alpha, ydelB*xA, &out);
 	
-	// mid lines
-	for(;y<yend-1;y++){
-	  dx = xstart += dw;
-	  xend += dw;
-	  l_mapping_calc(map->mapfunc, ol_low, ol_range, data[dx++], ol_alpha, 15*xA, &out);
-
-	  for(; dx < xend-1; dx++)
-	    l_mapping_calc(map->mapfunc, ol_low, ol_range, data[dx], ol_alpha, 255, &out);
+	for(; dx < xend-1; dx++)
+	  l_mapping_calc(mapfunc, ol_low, ol_range, data[dx], ol_alpha, ydelB*17, &out);
 	
-	  if(dx<xend)
-	    l_mapping_calc(map->mapfunc, ol_low, ol_range, data[dx], ol_alpha, 15*xB, &out);
-	}
-	
-	// last line
-	if(y<yend){
-	  dx = xstart += dw;
-	  xend += dw;
-	  ydel = ydelB;
-	  l_mapping_calc(map->mapfunc, ol_low, ol_range, data[dx++], ol_alpha, ydel*xA, &out);
-	  
-	  for(; dx < xend-1; dx++)
-	    l_mapping_calc(map->mapfunc, ol_low, ol_range, data[dx], ol_alpha, ydel*17, &out);
-	  
-	  if(dx<xend)
-	    l_mapping_calc(map->mapfunc, ol_low, ol_range, data[dx], ol_alpha, ydel*xB, &out);
-	}
+	if(dx<xend)
+	  l_mapping_calc(mapfunc, ol_low, ol_range, data[dx], ol_alpha, ydelB*xB, &out);
+      }
 
-	mix[xy] = map->mixfunc( (ucolor)(((u_int32_t)(out.a*idel)<<24) +
-					 ((u_int32_t)(out.r*idel)<<16) +
-					 ((u_int32_t)(out.g*idel)<<8) +
-					 ((u_int32_t)(out.b*idel))),
-				mix[xy]);
-	xy++;
+      work[j].a = (u_int32_t)(out.a*idel);
+      work[j].r = (u_int32_t)(out.r*idel);
+      work[j].g = (u_int32_t)(out.g*idel);
+      work[j].b = (u_int32_t)(out.b*idel);
+      
+    }
 
-      }
-    }
   }else{
     /* non-resampling render */
 
-    gdk_threads_leave ();
-    for(i=0;i<ph;i++){
-      int *dline = data+i*dw;
+    int data[dw];
+    memcpy(data,in_data+i*dw,sizeof(data));
+    gdk_threads_leave();      
 
-      gdk_threads_enter ();  
-      if(plot_serialno != p->private->plot_serialno ||
-	 map_serialno != p->private->map_serialno)
-	goto abort;
-      spinner_set_busy(p->private->spinner);
-      gdk_threads_leave();
-      
-      for(j=0;j<pw;j++){
+    for(j=0;j<pw;j++){
 
-	lcolor out = (lcolor){0,0,0,0};
-	l_mapping_calc(map->mapfunc, ol_low, ol_range, dline[j], ol_alpha, 255, &out);
+      lcolor out = (lcolor){0,0,0,0};
+      l_mapping_calc(mapfunc, ol_low, ol_range, data[j], ol_alpha, 255, &out);
 	
-	*panel = map->mixfunc((ucolor)(((u_int32_t)(out.a)<<24) +
-				       ((u_int32_t)(out.r)<<16) +
-				       ((u_int32_t)(out.g)<<8) +
-				       ((u_int32_t)(out.b))),
-			      *panel);
-	panel++;
-
-      }
+      work[j].a = (u_int32_t)(out.a);
+      work[j].r = (u_int32_t)(out.r);
+      work[j].g = (u_int32_t)(out.g);
+      work[j].b = (u_int32_t)(out.b);
     }
   }
-  free(data);
-  return 1;
- abort:
-  gdk_threads_leave ();
-  if(data)free(data);
+
+  gdk_threads_enter ();  
+  if(plot_serialno != p->private->plot_serialno ||
+     map_serialno != p->private->map_serialno)
+    return -1;
+  memcpy(panel+i*pw,work,sizeof(work));
+  p2->bg_todo[i] = 1;
+  p2->y_planetodo[y_no][i] = 0;
+
+  // must be last; it indicates completion
+  p->private->map_complete_count--;
   return 0;
 }
 
 // enter with lock
-static int _sushiv_panel2d_remap(sushiv_panel_t *p, _sushiv_bythread_cache_2d *thread_cache){
+static int render_bg_line(sushiv_panel_t *p, int plot_serialno, int map_serialno){
   sushiv_panel2d_t *p2 = p->subtype->p2;
   Plot *plot = PLOT(p->private->graph);
-  int i;
+  if(plot_serialno != p->private->plot_serialno ||
+     map_serialno != p->private->map_serialno) return -1;
+  
+  int ph = p2->y.pixels;
+  int pw = p2->x.pixels;
+  unsigned char *todo = p2->bg_todo;
+  int i = p2->bg_next_line,j;
+  ucolor work_bg[pw];
+  ucolor work_pl[pw];
 
-  if(!plot) return 0;
+  /* find a row that needs to be updated */
+  while(i<ph && !todo[i]){
+    p->private->map_complete_count--;
+    p2->bg_next_line++;
+    i++;
+  }
 
-  int pw = plot->x.pixels;
-  int ph = plot->y.pixels;
-  ucolor *c = malloc(pw*ph*sizeof(*c));
+  if(i < p2->bg_first_line) p2->bg_first_line = i;
+  if(i+1 > p2->bg_last_line) p2->bg_last_line = i+1;
 
-  double alphadel[p->objectives];
-  mapping mappings[p->objectives];
-  int plot_serialno = p->private->plot_serialno; 
-  int map_serialno = p->private->map_serialno; 
-  int *y_rects[p2->y_obj_num];
+  if(i == ph)
+    goto done;
 
-  memcpy(alphadel, p2->alphadel, sizeof(alphadel));
-  memcpy(mappings, p2->mappings, sizeof(mappings));
-  memcpy(y_rects, p2->y_map, sizeof(y_rects));
-  
-  /* exit for computation */
-  gdk_threads_leave();
-  
-  /* background checks */
-  render_checks(pw,ph,c);
+  p2->bg_next_line++;
 
-  gdk_threads_enter ();  
-  if(plot_serialno != p->private->plot_serialno ||
-     map_serialno != p->private->map_serialno)
-    goto abort;
+  /* gray background checks */
   gdk_threads_leave();
+  render_checks(work_bg,pw,i);
 
   /* by objective */
-  for(i=0;i<p->objectives;i++){
+  for(j=0;j<p->objectives;j++){
+    int o_ynum = p2->y_obj_from_panel[j];
+    
+    gdk_threads_enter();
+    if(plot_serialno != p->private->plot_serialno ||
+       map_serialno != p->private->map_serialno) return -1;
 
-    /**** render Y plane */
-    int o_ynum = p2->y_obj_from_panel[i];
-    if (!resample_render_y_plane(p, thread_cache, 
-				 plot_serialno, map_serialno, 
-				 mappings+i, alphadel[i],
-				 c, y_rects[o_ynum])){
-      gdk_threads_enter ();  
-      goto abort;
-    }
+    /**** mix Y plane */
+    
+    if(p2->y_planes[o_ynum]){
+      int x;
+      ucolor (*mixfunc)(ucolor,ucolor) = p2->mappings[j].mixfunc;
+      ucolor *rect = p2->y_planes[o_ynum] + i*pw;
+      memcpy(work_pl,rect,sizeof(work_pl));
+      
+      gdk_threads_leave();
+      for(x=0;x<pw;x++)
+	work_bg[x] = mixfunc(work_pl[x],work_bg[x]);
+    }else
+      gdk_threads_leave();
 
-    /**** render Z plane */
+    /**** mix Z plane */
     
-    /**** render vector plane */
+    /**** mix vector plane */
 
   }
 
-  gdk_threads_enter ();  
+  gdk_threads_enter();
   if(plot_serialno != p->private->plot_serialno ||
-     map_serialno != p->private->map_serialno)
-    goto abort;
+     map_serialno != p->private->map_serialno) return -1;
 
-  u_int32_t *dr = plot->datarect;
-  u_int32_t *cp = (u_int32_t *)c;
-  for(i=0;i<pw*ph;i++)
-    dr[i] = cp[i];
+    // rendered a line, get it on the screen */
+  
+  memcpy(plot->datarect+pw*i, work_bg, sizeof(work_bg));
 
-  free(c);
-  set_map_throttle_time(p); // done by worker threads too, but
-			    // delaying first throttled remap after
-			    // forced remap is useful too
-  return 1;
+  p->private->map_complete_count--;
 
- abort:
-  free(c);
+ done:
+  if(p->private->map_complete_count)
+    return 1; // not done yet
+
+  // remap completed; flush background to screen
+  plot_expose_request_partial (plot,0,p2->bg_first_line,
+			       pw,p2->bg_last_line - p2->bg_first_line);
+  gdk_flush();
   return 0;
 }
 
+// enter with lock; returns zero if thread should sleep / get distracted
+static int _sushiv_panel2d_remap(sushiv_panel_t *p, _sushiv_bythread_cache_2d *thread_cache){
+  sushiv_panel2d_t *p2 = p->subtype->p2;
+  Plot *plot = PLOT(p->private->graph);
+
+  if(!plot) goto abort;
+  int ph = plot->y.pixels;
+  
+  int plot_serialno = p->private->plot_serialno; 
+  int map_serialno = p->private->map_serialno; 
+
+  /* brand new remap indicated by the generic progress indicator being set to 0 */
+  if(p->private->map_progress_count == 0){
+
+    p->private->map_progress_count = 1; // 'in progress'
+    p->private->map_complete_count = p2->y_obj_num * ph; // count down to 0; 0 indicates completion
+
+    // set up Y plane rendering
+    p2->y_next_plane = 0;
+    p2->y_next_line = 0;
+
+    // bg mix
+    p2->bg_next_line = 0;
+    p2->bg_first_line = ph;
+    p2->bg_last_line = 0;
+  }
+
+  /* by plane, by line; each plane renders independently */
+  /* Y planes */
+  if(p2->y_planetodo){
+    if(p2->y_next_plane < p2->y_obj_num){
+      int status = resample_render_y_plane_line(p, thread_cache, 
+						plot_serialno, map_serialno, 
+						p2->y_next_plane);
+      if(status == -1) goto abort;
+      if(status == 1){
+	p2->y_next_plane++;
+	p2->y_next_line = 0;
+      }
+      return 1;
+    }
+  }else{
+    p->private->map_complete_count = 0;
+  }
+
+  /* renders have been completely dispatched, but are they complete? */
+  /* the below is effectively a a thread join */
+  if(p2->bg_next_line == 0){
+
+    // join still needs to complete....
+    if(p->private->map_complete_count){
+      // nonzero complete count, not finished.  returning zero will cause
+      // this worker thread to sleep or go on to do other things.
+      return 0; 
+    }else{
+      // zero complete count, the planes are done; we can begin
+      // background render.  At least one thread is guaranteed to get
+      // here, which is enough; we can now wake the others [if they were
+      // asleep] and have them look for work here. */
+      p->private->map_complete_count = ph; // [ph] lines to render in bg plane
+      p2->bg_next_line = 0;
+
+      _sushiv_wake_workers();
+    }
+  }
+
+  /* mix new background, again line by line */
+  if(p2->bg_next_line < ph){
+    int status = render_bg_line(p, plot_serialno, map_serialno);
+    if(status == -1) goto abort;
+    if(p->private->map_complete_count)return status;
+  }else
+    return 0; // nothing left to dispatch
+
+  // entirely finished.
+  // clean bg todo list
+  memset(p2->bg_todo,0,ph*sizeof(*p2->bg_todo));
+
+  // clear 'panel in progress' flag
+  _sushiv_panel_clean_map(p);
+  return 0;
+
+ abort:
+  // reset progress to 'start over'
+  p->private->map_progress_count=0;
+  p->private->map_complete_count=0;
+  return 1;
+}
+
+// call while locked
+static void _dirty_map_one_plane(sushiv_panel_t *p, int onum, int y, int z, int v){
+  sushiv_panel2d_t *p2 = p->subtype->p2;
+  int ph = p2->y.pixels;
+
+  if(y && p2->y_planetodo){
+    int y_no = p2->y_obj_from_panel[onum];
+    if(y_no>=0 && p2->y_planetodo[y_no])
+      memset(p2->y_planetodo[y_no],1,ph * sizeof(**p2->y_planetodo));
+  }
+}
+
+// call while locked 
+static void _dirty_map_one_data_line_y(sushiv_panel_t *p, int line){
+  // determine all panel lines this y data line affects
+  sushiv_panel2d_t *p2 = p->subtype->p2;
+  int ph = p2->y.pixels;
+  int pw = p2->x.pixels;
+  int dw = p2->x_v.pixels;
+  int dh = p2->y_v.pixels;
+  int i,j;
+
+  if(ph!=dh || pw!=dw){
+    /* resampled row computation; may involve multiple data rows */
+    if(p2->y_planetodo){
+      resample_helpers_manage_y(p);
+      
+      for(i=0;i<ph;i++)
+	if(p2->ynumA[i]<=line &&
+	   p2->ynumB[i]>line){
+	  
+	  for(j=0;j<p2->y_obj_num;j++)
+	    if(p2->y_planetodo[j])
+	      p2->y_planetodo[j][i]=1;
+      }
+    }
+  }else{
+    if(p2->y_planetodo)
+      if(line>0 && line<ph)
+	for(j=0;j<p2->y_obj_num;j++)
+	  if(p2->y_planetodo[j])
+	    p2->y_planetodo[j][line]=1;
+  }
+}
+
+// call while locked
+static void _dirty_map_full(sushiv_panel_t *p){
+  sushiv_panel2d_t *p2 = p->subtype->p2;
+  int ph = p2->y.pixels;
+  int i,j;
+
+  if(p2->y_planetodo){
+    for(j=0;j<p2->y_obj_num;j++){
+      if(p2->y_planetodo[j]){
+	for(i=0;i<ph;i++){
+	  p2->y_planetodo[j][i]=1;
+	}
+      }
+    }
+  }
+}
+
+// enter with lock
 static void update_legend(sushiv_panel_t *p){  
   sushiv_panel2d_t *p2 = p->subtype->p2;
   Plot *plot = PLOT(p->private->graph);
 
-  gdk_threads_enter ();
   if(plot){
     int i;
     char buffer[320];
@@ -623,7 +804,6 @@
       }
     }
   }
-  gdk_threads_leave ();
 }
 
 static void mapchange_callback_2d(GtkWidget *w,gpointer in){
@@ -646,6 +826,7 @@
   _sushiv_panel_dirty_legend(p);
 
   //redraw the plot
+  _dirty_map_one_plane(p,onum,1,0,0);
   _sushiv_panel_dirty_map(p);
   _sushiv_panel_undo_resume(p);
 }
@@ -668,8 +849,10 @@
 		      slider_get_value(p2->range_scales[onum],1));
 
   // redraw the plot on motion
-  if(buttonstate == 1)
+  if(buttonstate == 1){
+    _dirty_map_one_plane(p,onum,1,0,0);
     _sushiv_panel_dirty_map(p);
+  }
   if(buttonstate == 2)
     _sushiv_panel_undo_resume(p);
 }
@@ -779,12 +962,12 @@
     double xval = (x)*newscale+new_lo;
     double map = ((xval-old_lo)*oldscale);
     int base = (int)floor(map);
-    int del = rint((map - floor(map))*128.f);
+    int del = rint((map - floor(map))*64.f);
     /* hack to overwhelm roundoff error; this is inside a purely
        temporary cosmetic approximation anyway*/
     if(base>0 && del==0){
       mapbase[x]=base-1;
-      mapdel[x]=128;
+      mapdel[x]=64;
     }else{
       mapbase[x]=base;
       mapdel[x]=del;
@@ -804,7 +987,7 @@
 	if(A<0 || B<0)
 	  work[x]=-1;
 	else
-	  work[x]= A + (((B - A)*mapdel[x])>>7);
+	  work[x]= A + (((B - A)*mapdel[x])>>6);
 	
       }
     }
@@ -839,12 +1022,12 @@
     double yval = (y)*newscale+new_lo;
     double map = ((yval-old_lo)*oldscale);
     int base = (int)floor(map);
-    int del = rint((map - floor(map))*127.);
+    int del = rint((map - floor(map))*64.);
     /* hack to overwhelm roundoff error; this is inside a purely
        temporary cosmetic approximation anyway */
     if(base>0 && del==0){
       mapbase[y]=base-1;
-      mapdel[y]=128;
+      mapdel[y]=64;
     }else{
       mapbase[y]=base;
       mapdel[y]=del;
@@ -870,7 +1053,7 @@
 	if(A<0 || B<0)
 	  new_column[x]=-1;
 	else
-	  new_column[x]= A + (((B-A)*del)>>7);
+	  new_column[x]= A + (((B-A)*del)>>6);
       }
     }
   }
@@ -1075,14 +1258,7 @@
 
 // subtype entry point for plot remaps; lock held
 static int _sushiv_panel2d_map_redraw(sushiv_panel_t *p, _sushiv_bythread_cache *c){
-  Plot *plot = PLOT(p->private->graph);
-
-  if(p->private->map_progress_count)return 0;
-  p->private->map_progress_count++;
-  if(_sushiv_panel2d_remap(p,&c->p2))
-    _sushiv_panel_clean_map(p);
-  plot_expose_request(plot);
-  return 1;
+  return _sushiv_panel2d_remap(p,&c->p2);
 }
 
 // subtype entry point for legend redraws; lock held
@@ -1121,7 +1297,10 @@
 
   // beginning of computation init
   if(p->private->plot_progress_count==0){
-    
+    int remapflag = 0;
+
+    scalespace old_x = p2->x;
+    scalespace old_y = p2->y;
     scalespace old_xv = p2->x_v;
     scalespace old_yv = p2->y_v;
 
@@ -1160,6 +1339,7 @@
     p->private->plot_progress_count++;
     p->private->plot_serialno++; // we're about to free the old data rectangles
 
+    // realloc/fast scale the current data contents if appropriate
     if(memcmp(&sx_v,&old_xv,sizeof(sx_v)) || memcmp(&sy_v,&old_yv,sizeof(sy_v))){
       
       // maintain data planes
@@ -1178,15 +1358,39 @@
 		     oldmap,old_xv, old_yv);
 	  free(oldmap);
 	}
-
 	p2->y_map[i] = newmap; 
       }
-      // wrap the remap so that it does not give up the lock and allow
-      // itself to be interrupted
-      gdk_threads_enter ();
-      _sushiv_panel2d_remap(p,&c->p2); // do it now, don't queue it
-      gdk_threads_leave ();      
+      remapflag = 1;
+    }
 
+    // realloc render planes if appropriate
+    if(memcmp(&sx,&old_x,sizeof(sx)) || memcmp(&sy,&old_y,sizeof(sy))){
+      for(i=0;i<p2->y_obj_num;i++){
+
+	// y planes
+	if(p2->y_planes[i])
+	  free(p2->y_planes[i]);
+	p2->y_planes[i] = calloc(sx.pixels*sy.pixels,sizeof(**p2->y_planes));
+
+	// todo lists
+	if(p2->y_planetodo[i])
+	  free(p2->y_planetodo[i]);
+	p2->y_planetodo[i] = calloc(sy.pixels,sizeof(**p2->y_planetodo));
+	
+      }
+
+      if(p2->bg_todo)
+	free(p2->bg_todo);
+      p2->bg_todo=calloc(ph,sizeof(*p2->bg_todo));
+      
+      remapflag = 1;
+    }
+
+    if(remapflag){
+      _dirty_map_full(p);
+
+      _sushiv_panel_dirty_map_immediate(p);
+
       gdk_threads_leave ();      
       plot_draw_scales(plot); // this should happen outside lock
       gdk_threads_enter ();      
@@ -1240,22 +1444,35 @@
 
   if(p->private->plot_serialno == serialno){
     p->private->plot_complete_count++;
+    _dirty_map_one_data_line_y(p,y);
     if(p->private->plot_complete_count>=dh){ 
       _sushiv_panel_dirty_map(p);
       _sushiv_panel_dirty_legend(p);
       _sushiv_panel_clean_plot(p);
-    }else{
-      _sushiv_panel_dirty_map_throttled(p);
-    }
+    }else
+      _sushiv_panel_dirty_map_throttled(p); 
   }
 
   return 1;
 }
 
+// only called for resize events
 static void recompute_callback_2d(void *ptr){
   sushiv_panel_t *p = (sushiv_panel_t *)ptr;
+  int i;
+
+  gdk_threads_enter ();
   _mark_recompute_2d(p);
   _sushiv_panel2d_compute(p,NULL); // initial scale setup
+
+  // temporary: blank background to checks
+  Plot *plot = PLOT(p->private->graph);
+  int pw = plot->x.pixels;
+  int ph = plot->y.pixels;
+  for(i=0;i<ph;i++)
+    render_checks((ucolor *)plot->datarect+pw*i, pw, i);
+  
+  gdk_threads_leave();
 }
 
 static void panel2d_undo_log(sushiv_panel_undo_t *u, sushiv_panel_t *p){
@@ -1766,6 +1983,8 @@
   }
 
   p2->y_map = calloc(p2->y_obj_num,sizeof(*p2->y_map));
+  p2->y_planetodo = calloc(p2->y_obj_num,sizeof(*p2->y_planetodo));
+  p2->y_planes = calloc(p2->y_obj_num,sizeof(*p2->y_planes));
 
   return 0;
 }

Modified: trunk/sushivision/panel-2d.h
===================================================================
--- trunk/sushivision/panel-2d.h	2007-02-20 04:17:27 UTC (rev 12497)
+++ trunk/sushivision/panel-2d.h	2007-02-20 10:17:02 UTC (rev 12498)
@@ -30,15 +30,25 @@
   int used_functions;
   sushiv_function_t **used_function_list;
 
+  unsigned char *bg_todo;
+  int bg_next_line;
+  int bg_first_line;
+  int bg_last_line;
+
   /**** Y PLANES ******/
   int y_obj_num;
   int **y_map; // indirected, dw*dh
+  ucolor **y_planes; // indirected, dw*dh
+  unsigned char **y_planetodo; // indirected, dh
 
+  int y_next_plane; // which y plane to issue next render
+  int y_next_line; // incremented when a line is claimed, per plane [0-ph)
+
   sushiv_objective_t **y_obj_list; // list of objectives with a y plane
   int *y_obj_to_panel; /* maps from position in condensed list to position in full list */
   int *y_obj_from_panel; /* maps from position in full list to position in condensed list */
   int *y_fout_offset; 
-
+  
   /* cached resampling helpers */
   int resample_serialno;
   unsigned char *ydelA;

Modified: trunk/sushivision/panel.c
===================================================================
--- trunk/sushivision/panel.c	2007-02-20 04:17:27 UTC (rev 12497)
+++ trunk/sushivision/panel.c	2007-02-20 10:17:02 UTC (rev 12498)
@@ -110,10 +110,15 @@
   gdk_threads_leave ();
 }
 
+void _sushiv_panel_dirty_map_immediate(sushiv_panel_t *p){
+  _idle_map_fire(p);
+}
+
 void _sushiv_panel_dirty_map_throttled(sushiv_panel_t *p){
   gdk_threads_enter ();
-  if(!p->private->map_active && test_throttle_time(p))
-     g_idle_add(_idle_map_fire,p);
+  if(!p->private->map_active && test_throttle_time(p)){
+     _idle_map_fire(p);
+  }
   gdk_threads_leave ();
 }
 

Modified: trunk/sushivision/plot.c
===================================================================
--- trunk/sushivision/plot.c	2007-02-20 04:17:27 UTC (rev 12497)
+++ trunk/sushivision/plot.c	2007-02-20 10:17:02 UTC (rev 12498)
@@ -282,7 +282,7 @@
   cairo_surface_t *temp = p->fore;
   p->fore = s;
   cairo_surface_destroy(temp);
-  plot_expose_request(p);
+  //plot_expose_request(p);
   gdk_threads_leave();
 }
 
@@ -536,8 +536,8 @@
   p->x = scalespace_linear(p->x.lo,p->x.hi,widget->allocation.width,p->scalespacing,p->x.legend);
   p->y = scalespace_linear(p->y.lo,p->y.hi,widget->allocation.height,p->scalespacing,p->y.legend);
   plot_unset_box(p);
-  plot_draw_scales(p);
   if(p->recompute_callback)p->recompute_callback(p->app_data);
+  //plot_draw_scales(p); geenrally done in callback after scale massaging
 
 }
 

Modified: trunk/sushivision/plot.h
===================================================================
--- trunk/sushivision/plot.h	2007-02-20 04:17:27 UTC (rev 12497)
+++ trunk/sushivision/plot.h	2007-02-20 10:17:02 UTC (rev 12498)
@@ -40,7 +40,6 @@
 struct _Plot{
   GtkWidget w;
   cairo_t         *wc;
-  cairo_t         *bc;
   cairo_surface_t *back;
   cairo_surface_t *fore;
   cairo_surface_t *stage;

Modified: trunk/sushivision/slice.c
===================================================================
--- trunk/sushivision/slice.c	2007-02-20 04:17:27 UTC (rev 12497)
+++ trunk/sushivision/slice.c	2007-02-20 10:17:02 UTC (rev 12498)
@@ -246,7 +246,7 @@
     s->thumb_val=v;
     slider_vals_bound(s->slider,s->slicenum);
     
-    if(s->callback)s->callback(s->callback_data,5);
+    if(s->callback)s->callback(s->callback_data,1);
     draw_and_expose(w);
   }
 }



More information about the commits mailing list