3 __global__ void genere_snake_rectangle_4nodes_gpu(snake_node_gpu * d_snake, int dist_bords, int i_dim, int j_dim){
7 d_snake[n].posi = dist_bords ;
8 d_snake[n].posj = dist_bords ;
11 d_snake[n].posi = i_dim - dist_bords ;
12 d_snake[n].posj = dist_bords ;
15 d_snake[n].posi = i_dim - dist_bords ;
16 d_snake[n].posj = j_dim - dist_bords ;
19 d_snake[n].posi = dist_bords ;
20 d_snake[n].posj = j_dim - dist_bords ;
22 for (int i=0; i<4; i++)
24 d_snake[i].freeman_in = 0;
25 d_snake[i].freeman_out = 0;
26 d_snake[i].centre_i = 0;
27 d_snake[i].centre_j = 0;
28 d_snake[i].last_move = 0;
29 d_snake[i].nb_pixels = 123;
30 d_snake[i].code_segment = 0;
36 __global__ void genere_diagos_rectangle(uint4 * d_diagos, int h, int l, int q, int * n_diagos){
41 // boucle double pour les positions du point NO de la diagonale
42 for ( iM = 0; iM < q-1; iM++){
43 for (jM = 0 ; jM < q-1 ; jM++){
44 //boucle double pour les positions du point SE de la diagonale
45 for (iN = iM+1; iN < q; iN++){
46 for (jN = jM+1; jN < q; jN++){
47 d_diagos[idxDiago].x = iM*inci;
48 d_diagos[idxDiago].y = jM*incj;
49 d_diagos[idxDiago].z = iN*inci;
50 d_diagos[idxDiago].w = jN*incj;
56 *n_diagos = --idxDiago ;
59 __global__ void genere_snake_rectangle_Nnodes_gpu(snake_node_gpu * d_snake, int dist_bords, int i_dim, int j_dim){
63 int i , h= i_dim-2*dist_bords, l= j_dim-2*dist_bords ;
64 int inch = h/(nb_node_seg+1), incl= l/(nb_node_seg+1) ;
65 if (threadIdx.x == 0){
68 d_snake[n].posi = dist_bords ;
69 d_snake[n].posj = dist_bords ;
71 /*entre sommet 0 et 1*/
73 while (i < nb_node_seg)
75 if ( (d_snake[n-1].posi + inch)-(i_dim - dist_bords) > limite )
76 d_snake[n].posi = d_snake[n-1].posi + inch ;
78 d_snake[n].posi = d_snake[n-1].posi + inch/2 ;
79 d_snake[n].posj = dist_bords ;
80 d_snake[n-1].nb_pixels = d_snake[n].posi - d_snake[n-1].posi ;
84 d_snake[n].posi = i_dim - dist_bords ;
85 d_snake[n].posj = dist_bords ;
86 d_snake[n-1].nb_pixels = d_snake[n].posi - d_snake[n-1].posi ;
90 while (i< nb_node_seg)
92 if ( (j_dim - dist_bords) - (d_snake[n-1].posj + incl) > limite )
93 d_snake[n].posj = d_snake[n-1].posj + incl ;
95 d_snake[n].posj = d_snake[n-1].posj + incl/2 ;
96 d_snake[n].posi = i_dim - dist_bords ;
97 d_snake[n-1].nb_pixels = d_snake[n].posj - d_snake[n-1].posj ;
101 d_snake[n].posi = i_dim - dist_bords ;
102 d_snake[n].posj = j_dim - dist_bords ;
103 d_snake[n-1].nb_pixels = d_snake[n].posj - d_snake[n-1].posj ;
107 while (i< nb_node_seg)
109 if ( (d_snake[n-1].posi - inch) - dist_bords > limite )
110 d_snake[n].posi = d_snake[n-1].posi - inch ;
112 d_snake[n].posi = d_snake[n-1].posi - inch/2 ;
113 d_snake[n].posj = j_dim - dist_bords ;
114 d_snake[n-1].nb_pixels = d_snake[n-1].posi - d_snake[n].posi ;
118 d_snake[n].posi = dist_bords ;
119 d_snake[n].posj = j_dim - dist_bords ;
120 d_snake[n-1].nb_pixels = d_snake[n-1].posi - d_snake[n].posi ;
124 while (i< nb_node_seg)
126 if ( (d_snake[n-1].posj - incl) - dist_bords > limite)
127 d_snake[n].posj = d_snake[n-1].posj - incl ;
129 d_snake[n].posj = d_snake[n-1].posj - incl/2 ;
130 d_snake[n].posi = dist_bords ;
131 d_snake[n-1].nb_pixels = d_snake[n-1].posj - d_snake[n].posj ;
134 d_snake[n-1].nb_pixels = d_snake[n-1].posj - d_snake[0].posj ;
137 d_snake[i].freeman_in = 0;
138 d_snake[i].freeman_out = 0;
139 d_snake[i].centre_i = 0;
140 d_snake[i].centre_j = 0;
141 d_snake[i].last_move = 1;
142 d_snake[i].code_segment = 0;
148 __global__ void calcul_contribs_segments_snake(snake_node_gpu * d_snake, int nb_nodes,
149 t_cumul_x * cumul_x, t_cumul_x2 * cumul_x2,
150 int l, uint2 * liste_pix, t_sum_x2 * gsombloc, int * d_table_freeman)
152 // indices des elements
153 int blockSize = blockDim.x ;
154 int tib = threadIdx.x ;
155 int nblocs_seg = gridDim.x / nb_nodes ;
156 int idx = blockDim.x*blockIdx.x + threadIdx.x ;
157 int segment = blockIdx.x / nblocs_seg ;
158 int tis = idx - segment*nblocs_seg*blockDim.x ;
160 //tab pour coordonnées pixels & contribs pixels de taille = (blockDim.x+offset(dec,dec2) )*(sizeof(t_sum_1+t_sum_x+t_sum_x2))
161 extern __shared__ t_sum_1 scumuls_1[] ; // blockDim varie selon la longueur des segments => taille smem dynamique
162 t_sum_x* scumuls_x = (t_sum_x*) &scumuls_1[CFI(blockDim.x)] ;
163 t_sum_x2* scumuls_x2 = (t_sum_x2*) &scumuls_x[CFI(blockDim.x)] ;
166 uint x1, y1, x2, y2 ;
171 //gestion du bouclage du snake
172 if (n2 >= nb_nodes) n2 = 0 ;
174 //affectation des differentes positions aux différents segments 'blocs de threads'
175 x1 = d_snake[n1].posj ;
176 y1 = d_snake[n1].posi ;
177 x2 = d_snake[n2].posj ;
178 y2 = d_snake[n2].posi ;
180 //params des deplacements
183 uint abs_dx = ABS(dx);
184 uint abs_dy = ABS(dy);
185 uint nb_pix = abs_dy>abs_dx?(abs_dy+1):(abs_dx+1); // alternative -> lecture ds liste_points[]
190 //calcul liste des pixels du segment (x1,y1)-(x2,y2)
191 if (dy > 0) incy=1; else incy=-1 ;
192 if (dx > 0) incx=1; else incx=-1 ;
195 if (abs_dy > abs_dx){
197 double k = (double)dx/dy ;
198 p.x = y1 + incy*tis ;
199 p.y = x1 + floor((double)incy*k*tis+0.5) ;
200 //enreg. coords. pixels en global mem pour freemans
202 if ((tis < 2)||(tis > nb_pix - 3)||(tis == nb_pix/2))
204 liste_pix[idx].x = p.x ;
205 liste_pix[idx].y = p.y ;
209 //1 thread par colonne
210 double k=(double)dy/dx ;
211 p.x = y1 + floor((double)(incx*k*tis)+0.5) ;
212 p.y = x1 + incx*tis ;
214 xsuiv = y1 + floor((double)(incx*k*(tis+1))+0.5) ;
215 xprec = y1 + floor((double)(incx*k*(tis-1))+0.5) ;
217 //enreg. coords. pixels en global mem pour freeman
219 //on peut calculer les freemans des segments
220 //sans stocker l'ensemble des valeurs des pixels
221 //juste avec les derivees aux extremites a calculer ici
223 if ((tis < 2)||(tis > nb_pix - 3)||(tis == nb_pix/2))
225 liste_pix[idx].x = p.x ;
226 liste_pix[idx].y = p.y ;
233 //calcul contribs individuelles des pixels
235 if ( (tis >0) && (tis < nb_pix-1)
236 && ( (abs_dy <= abs_dx)
237 && ( (xprec > p.x) || (xsuiv > p.x))
238 || (abs_dy > abs_dx) ) )
240 int pos = p.x * l + p.y ;
241 scumuls_1[ CFI(tib)] = 1+p.y;
242 scumuls_x[ CFI(tib)] = cumul_x[ pos ] ;
243 scumuls_x2[CFI(tib)] = cumul_x2[ pos ];
245 scumuls_1[ CFI(tib)] = 0;
246 scumuls_x[ CFI(tib)] = 0;
247 scumuls_x2[CFI(tib)] = 0;
251 //somme des contribs individuelles
252 // unroll des sommes partielles en smem
254 if (blockSize >= 512) {
256 scumuls_1[ CFI(tib)] += scumuls_1[ CFI(tib + 256) ];
257 scumuls_x[ CFI(tib)] += scumuls_x[ CFI(tib + 256) ];
258 scumuls_x2[CFI(tib)] += scumuls_x2[CFI(tib + 256) ];
263 if (blockSize >= 256) {
265 scumuls_1[ CFI(tib)] += scumuls_1[ CFI(tib + 128) ];
266 scumuls_x[ CFI(tib)] += scumuls_x[ CFI(tib + 128) ];
267 scumuls_x2[CFI(tib)] += scumuls_x2[CFI(tib + 128) ];
271 if (blockSize >= 128) {
273 scumuls_1[ CFI(tib)] += scumuls_1[ CFI(tib + 64) ];
274 scumuls_x[ CFI(tib)] += scumuls_x[ CFI(tib + 64) ];
275 scumuls_x2[CFI(tib)] += scumuls_x2[CFI(tib + 64) ];
280 //32 threads <==> 1 warp
284 scumuls_1[ CFI(tib)] += scumuls_1[ CFI(tib + 32) ];
285 scumuls_x[ CFI(tib)] += scumuls_x[ CFI(tib + 32) ];
286 scumuls_x2[CFI(tib)] += scumuls_x2[CFI(tib + 32) ];
289 scumuls_1[ CFI(tib)] += scumuls_1[ CFI(tib + 16) ];
290 scumuls_x[ CFI(tib)] += scumuls_x[ CFI(tib + 16) ];
291 scumuls_x2[CFI(tib)] += scumuls_x2[CFI(tib + 16) ];
294 scumuls_1[ CFI(tib)] += scumuls_1[ CFI(tib + 8) ];
295 scumuls_x[ CFI(tib)] += scumuls_x[ CFI(tib + 8) ];
296 scumuls_x2[CFI(tib)] += scumuls_x2[CFI(tib + 8) ];
298 scumuls_1[ CFI(tib)] += scumuls_1[ CFI(tib + 4) ];
299 scumuls_x[ CFI(tib)] += scumuls_x[ CFI(tib + 4) ];
300 scumuls_x2[CFI(tib)] += scumuls_x2[CFI(tib + 4) ];
302 scumuls_1[ CFI(tib)] += scumuls_1[ CFI(tib + 2) ];
303 scumuls_x[ CFI(tib)] += scumuls_x[ CFI(tib + 2) ];
304 scumuls_x2[CFI(tib)] += scumuls_x2[CFI(tib + 2) ];
306 scumuls_1[ CFI(tib)] += scumuls_1[ CFI(tib + 1) ];
307 scumuls_x[ CFI(tib)] += scumuls_x[ CFI(tib + 1) ];
308 scumuls_x2[CFI(tib)] += scumuls_x2[CFI(tib + 1) ];
311 // resultat sommes partielles en gmem
313 gsombloc[ blockIdx.x ] = (t_sum_x2) scumuls_1[0];
314 gsombloc[ blockIdx.x + gridDim.x ] = (t_sum_x2) scumuls_x[0];
315 gsombloc[ blockIdx.x + 2*gridDim.x ] = (t_sum_x2) scumuls_x2[0];
318 //calculs freemans, centre et code segment
319 //1 uint4 par segment
323 Di = 1 + liste_pix[idx+1].x - liste_pix[idx].x ;
324 Dj = 1 + liste_pix[idx+1].y - liste_pix[idx].y ;
325 d_snake[segment].freeman_out = d_table_freeman[3*Di + Dj] ;
327 if (dy > 0 ) d_snake[segment].code_segment = -1 ;
328 if (dy < 0 ) d_snake[segment].code_segment = 1 ;
329 if (dy == 0) d_snake[segment].code_segment = 0 ;
332 if (tis == nb_pix-1){
333 Di = 1 + liste_pix[idx].x - liste_pix[idx-1].x ;
334 Dj = 1 + liste_pix[idx].y - liste_pix[idx-1].y;
335 d_snake[segment].freeman_in = d_table_freeman[3*Di + Dj] ;
338 if (tis == (nb_pix/2)){
339 d_snake[segment].centre_i = liste_pix[idx].x ;
340 d_snake[segment].centre_j = liste_pix[idx].y ;
345 sommme des contribs par bloc -> contribs segment, pour le snake
347 execution sur : 1bloc / 1 thread par segment
350 __global__ void somsom_snake(t_sum_x2 * somblocs, int nb_nodes, unsigned int nb_bl_seg, snake_node_gpu * d_snake){
353 unsigned int seg = blockIdx.x ;
355 //un thread par segment
362 for (int b=0; b < nb_bl_seg ; b++){
363 sdata[0] += somblocs[seg*nb_bl_seg + b];
364 sdata[1] += somblocs[(seg + nb_nodes)*nb_bl_seg + b];
365 sdata[2] += somblocs[(seg + 2*nb_nodes)*nb_bl_seg + b];
370 d_snake[seg].sum_1 = sdata[0];
371 d_snake[seg].sum_x = sdata[1];
372 d_snake[seg].sum_x2 = sdata[2];
376 __device__ double codage_gl_gauss(uint64 stat_sum_1, uint64 stat_sum_x, uint64 stat_sum_x2,
377 uint64 n_dim, uint64 SUM_X, uint64 SUM_X2){
378 uint64 stat_sum_xe ; /* somme des xn region exterieure */
379 uint32 ne ; /* nombre de pixel region exterieure */
380 double sigi2, sige2; /* variance region interieure et exterieure */
382 /* variance des valeurs des niveaux de gris a l'interieur du snake */
384 ((double)stat_sum_x2/(double)stat_sum_1) -
385 ((double)stat_sum_x/(uint64)stat_sum_1)*((double)stat_sum_x/(uint64)stat_sum_1) ;
387 /* variance des valeurs des niveaux de gris a l'exterieur du snake */
388 ne = n_dim-stat_sum_1 ;
389 stat_sum_xe = SUM_X - stat_sum_x ;
391 ((double)SUM_X2-stat_sum_x2)/(double)ne -
392 ((double)stat_sum_xe/(uint64)ne)*((double)stat_sum_xe/(uint64)ne) ;
394 if ((sigi2 > 0)|(sige2 > 0))
395 return 0.5*((double)stat_sum_1*log(sigi2) + (double)ne*log(sige2)) ;
400 __global__ void calcul_stats_snake(snake_node_gpu * d_snake, int nnodes, int64 * d_stats_snake, double * vrais_min,
401 t_cumul_x * cumul_x, t_cumul_x2 * cumul_x2, int * TABLE_CODAGE, uint32 l
405 int id_nx, id_nprec, id_nprecprec ;
406 int code_noeud, code_segment, pos ;
407 __shared__ int64 s_stats_snake[3] ;
409 //init stats en shared mem
410 s_stats_snake[0] = 0 ;
411 s_stats_snake[1] = 0 ;
412 s_stats_snake[2] = 0 ;
415 for (id_nx = 0; id_nx < nnodes; id_nx++)
417 if (id_nx == 0) id_nprec = nnodes - 1;
418 else id_nprec = id_nx - 1;
419 if (id_nprec == 0) id_nprecprec = nnodes -1 ;
420 else id_nprecprec = id_nprec - 1 ;
421 /* gestion des segments partant du noeud */
422 /* vers le noeud suivant dans l'ordre trigo */
423 code_segment = d_snake[id_nprec].code_segment ;
424 if (code_segment > 0)
426 /* on somme les contributions */
427 s_stats_snake[0] += d_snake[id_nprec].sum_1 ;
428 s_stats_snake[1] += d_snake[id_nprec].sum_x ;
429 s_stats_snake[2] += d_snake[id_nprec].sum_x2 ;
431 else if (code_segment < 0)
433 /* on soustrait les contributions */
434 s_stats_snake[0] -= d_snake[id_nprec].sum_1 ;
435 s_stats_snake[1] -= d_snake[id_nprec].sum_x ;
436 s_stats_snake[2] -= d_snake[id_nprec].sum_x2 ;
438 // else (code_segment == 0), on ne fait rien
439 /* gestion des pixels connectant les segments */
440 /* pixel de depart du segment actuel np --> np->noeud_suiv */
441 /* freeman_out = np->freeman_out ; */
442 /* freeman_in = np->noeud_prec->freeman_in ; */
443 pos = d_snake[id_nprecprec].freeman_in*8 + d_snake[id_nprec].freeman_out ;
444 code_noeud = TABLE_CODAGE[pos] ;
445 pos = d_snake[id_nprec].posi*l + d_snake[id_nprec].posj ;
449 /* on somme les contributions */
450 s_stats_snake[0] += 1 + d_snake[id_nprec].posj ;
451 s_stats_snake[1] += cumul_x[pos] ;
452 s_stats_snake[2] += cumul_x2[pos] ;
454 else if (code_noeud < 0)
456 /* on soustrait les contributions */
457 s_stats_snake[0] -= 1 + d_snake[id_nprec].posj ;
458 s_stats_snake[1] -= cumul_x[pos] ;
459 s_stats_snake[2] -= cumul_x2[pos] ;
461 // else (code_pixel == 0), on ne fait rien
463 d_stats_snake[0] = s_stats_snake[0] ;
464 d_stats_snake[1] = s_stats_snake[1] ;
465 d_stats_snake[2] = s_stats_snake[2] ;
467 *vrais_min = codage_gl_gauss(s_stats_snake[0], s_stats_snake[1], s_stats_snake[2],
468 d_stats_snake[3], d_stats_snake[4], d_stats_snake[5]);
471 // kernel d'init rectangulaire au niveau snake
472 // un block par point de base et un point opposé par thread du bloc
474 __global__ void calcul_contribs_snake4(snake_node_gpu * snake, t_cumul_x * cumul_x, t_cumul_x2 * cumul_x2, int h, int l,
475 int64 * sums, t_rectangle_snake * critere)
477 // nb de diagonales testees par bloc (ie. par point de base NO)
478 int blockSize = blockDim.x ;
479 // indice du second point de chaque diagonale (=Opposite Point, = point SE)
480 int OPib = threadIdx.x ;
481 // coordonnees de chaque point de base (NO)
482 int BPi = blockIdx.x ;
483 int BPj = blockIdx.y ;
484 //coordonnees de chaque Opposite Point (SE)
485 double incThread = ((h-BPi)*(l-BPj) + blockSize -1)/(double)blockSize ;
486 int OPi = (double)(OPib*incThread)/(l - BPj) ;
487 int OPj = OPib*incThread - OPi*(l-BPj) ;
490 if (OPi >= h) OPi = h-1 ;
491 if (OPj >= l) OPj = l-1 ;
492 //indices des pixels dans les images cumulees
495 int C1 = (OPi - BPi)*(OPj - BPj) ;
497 //pour stocker contribs de chaque snake d'un block
498 //TODO on peut utiliser une structure restreinte (sans le c1)
499 extern __shared__ tcontribs scumuls[];
501 //calcul contribs du snake
502 scumuls[CFI(OPib)].cx = 0;
503 scumuls[CFI(OPib)].cx2 = 0;
504 for (int k=BPi ; k < OPi ; k++)
506 posG = (BPi+k)*l + BPj ;
507 posD = posG - BPj + OPj ;
508 scumuls[CFI(OPib)].cx += (cumul_x[ posD ] - cumul_x[ posG ]) ;
509 scumuls[CFI(OPib)].cx2 += (cumul_x2[ posD ] - cumul_x2[ posG ]);
512 //calcul de critère pour chaque snake
513 uint64 stat_sum_xe ; /* somme des xn region exterieure */
514 uint32 ne ; /* nombre de pixel region exterieure */
515 double sigi2, sige2; /* variance region interieure et exterieure */
518 /* variance des valeurs des niveaux de gris a l'interieur du snake */
520 ((double)scumuls[CFI(OPib)].cx2/(double)C1) -
521 ((double)scumuls[CFI(OPib)].cx/(uint64)C1)*((double)scumuls[CFI(OPib)].cx/(uint64)C1) ;
523 /* variance des valeurs des niveaux de gris a l'exterieur du snake */
526 stat_sum_xe = sums[4] - scumuls[CFI(OPib)].cx ;
528 ((double)sums[5]-scumuls[CFI(OPib)].cx2)/(double)ne -
529 ((double)stat_sum_xe/(uint64)ne)*((double)stat_sum_xe/(uint64)ne) ;
531 index_crit = blockSize*(BPi*gridDim.y + BPj) + OPib ;
534 if ((sigi2 > 0)|(sige2 > 0))
536 critere[ index_crit ].bpi = BPi;
537 critere[ index_crit ].bpj = BPj;
538 critere[ index_crit ].opi = OPi;
539 critere[ index_crit ].opj = OPj;
540 critere[ index_crit ].crit = 0.5*((double)C1*log(sigi2) + (double)ne*log(sige2)) ;
544 critere[ index_crit ].bpi = BPi;
545 critere[ index_crit ].bpj = BPj;
546 critere[ index_crit ].opi = OPi;
547 critere[ index_crit ].opj = OPj;
548 critere[ index_crit ].crit = -1 ;
551 // identification meilleur snake du bloc
552 // laissé au CPU pour test mais le principe de ce kernel n'est pas efficace.