+ scontrib[ CFI(tib) ].cx = 0 ;
+ scontrib[ CFI(tib) ].cx2= 0 ;
+ }
+ __syncthreads();
+
+ // somme des contribs individuelles par bloc
+ // unroll des sommes partielles en smem
+ if (bs >= 1024) {
+ if (tib < 512) {
+ scontrib[ CFI(tib) ].cx += scontrib[ CFI(tib + 512) ].cx;
+ scontrib[ CFI(tib) ].cx2 += scontrib[CFI(tib + 512) ].cx2;
+ }
+ __syncthreads();
+ }
+
+ if (bs >= 512) {
+ if (tib < 256) {
+ scontrib[ CFI(tib) ].cx += scontrib[ CFI(tib + 256) ].cx;
+ scontrib[ CFI(tib) ].cx2 += scontrib[CFI(tib + 256) ].cx2;
+ }
+ __syncthreads();
+ }
+
+ if (bs >= 256) {
+ if (tib < 128) {
+ scontrib[ CFI(tib) ].cx += scontrib[ CFI(tib + 128) ].cx;
+ scontrib[ CFI(tib) ].cx2 += scontrib[CFI(tib + 128) ].cx2;
+ }
+ __syncthreads();
+ }
+ if (bs >= 128) {
+ if (tib < 64) {
+ scontrib[ CFI(tib) ].cx += scontrib[ CFI(tib + 64) ].cx;
+ scontrib[ CFI(tib) ].cx2 += scontrib[CFI(tib + 64) ].cx2;
+ }
+ __syncthreads();
+ }
+
+ //32 threads <==> 1 warp
+ if (tib < 32)
+ {
+ scontrib[ CFI(tib) ].cx += scontrib[ CFI(tib + 32) ].cx;
+ scontrib[ CFI(tib) ].cx2 += scontrib[CFI(tib + 32) ].cx2;
+ }
+ if (tib < 16)
+ {
+ scontrib[ CFI(tib) ].cx += scontrib[ CFI(tib + 16) ].cx;
+ scontrib[ CFI(tib) ].cx2 += scontrib[CFI(tib + 16) ].cx2;
+ }
+ if (tib < 8)
+ {
+ scontrib[ CFI(tib) ].cx += scontrib[ CFI(tib + 8) ].cx;
+ scontrib[ CFI(tib) ].cx2 += scontrib[CFI(tib + 8) ].cx2;
+ }
+ if (tib < 4)
+ {
+ scontrib[ CFI(tib) ].cx += scontrib[ CFI(tib + 4) ].cx;
+ scontrib[ CFI(tib) ].cx2 += scontrib[CFI(tib + 4) ].cx2;
+ }
+ if (tib < 2)
+ {
+ scontrib[ CFI(tib) ].cx += scontrib[ CFI(tib + 2) ].cx;
+ scontrib[ CFI(tib) ].cx2 += scontrib[CFI(tib + 2) ].cx2;
+ }
+ if (tib < 1)
+ {
+ scontrib[ CFI(tib) ].cx += scontrib[ CFI(tib + 1) ].cx;
+ scontrib[ CFI(tib) ].cx2 += scontrib[CFI(tib + 1) ].cx2;
+ }
+
+ __syncthreads();
+
+ // resultat contribs partielles ( par bloc) en gmem
+ if (tib == 0) {
+ // c1 s'obtient directement car les sommes sont à j constant ( j=idC )
+ sums[ idC*bpc +idB ].cx = scontrib[0].cx ;
+ sums[ idC*bpc +idB ].cx2 = scontrib[0].cx2 ;
+ }
+}
+
+/*
+ sommme des contribs par bloc -> contribs colonnes
+ execution sur : (1 bloc de 1 thread) par colonne
+ */
+
+__global__ void somsom_contribs(tcontribs * somblocs, int bpc, tcontribs * somcols){
+
+ tcontribs scontrib ;
+ int col = blockIdx.x ;
+ int base = col*bpc ;
+
+ //un thread par colonne
+ {
+ scontrib.cx = 0;
+ scontrib.cx2 = 0;
+ }
+
+ for (int b=0; b < bpc ; b++){
+ scontrib.cx += somblocs[ base +b ].cx ;
+ scontrib.cx2 += somblocs[ base +b ].cx2 ;
+ }
+
+ //totaux en gmem
+ {
+ somcols[ col ].cx = scontrib.cx ;
+ somcols[ col ].cx2 = scontrib.cx2;
+ }
+
+}
+
+/*
+ recherche des criteres minis dans les blocs
+ */
+__device__ void mini_critere_bloc(double2 *critere, int bs){
+
+ int tib = threadIdx.x ;
+
+ critere[ CFI(tib) ].y = tib ; //initialisation des indices pour les minima
+
+ if ( (bs >= 1024) && (tib < 512) ) {
+ if ( critere[ CFI(tib + 512) ].x < critere[ CFI(tib) ].x ){
+ critere[ CFI(tib) ] = critere[ CFI(tib + 512) ] ;
+ __syncthreads() ;
+ }
+ }
+
+ if ( (bs >= 512) && (tib < 256) ) {
+ if ( critere[ CFI(tib + 256) ].x < critere[ CFI(tib) ].x ){
+ critere[ CFI(tib) ] = critere[ CFI(tib + 256) ] ;
+ __syncthreads() ;
+ }
+ }
+
+ if ( (bs >= 256) && (tib < 128) ) {
+ if ( critere[ CFI(tib + 128) ].x < critere[ CFI(tib) ].x ){
+ critere[ CFI(tib) ] = critere[ CFI(tib + 128) ] ;
+ __syncthreads() ;
+ }
+ }
+
+ if ( (bs >= 128) && (tib < 64) ) {
+ if ( critere[ CFI(tib + 64) ].x < critere[ CFI(tib) ].x ){
+ critere[ CFI(tib) ] = critere[ CFI(tib + 64) ] ;
+ __syncthreads() ;
+ }
+ }
+
+ //32 threads <==> 1 warp
+ if (tib < 32){
+ if ( critere[ CFI(tib + 32) ].x < critere[ CFI(tib) ].x ){
+ critere[ CFI(tib) ] = critere[ CFI(tib + 32) ] ;
+ }
+ }
+
+ if (tib < 16){
+ if ( critere[ CFI(tib + 16) ].x < critere[ CFI(tib) ].x ){
+ critere[ CFI(tib) ] = critere[ CFI(tib + 16) ] ;
+ }
+ }
+
+ if (tib < 8){
+ if ( critere[ CFI(tib + 8) ].x < critere[ CFI(tib) ].x ){
+ critere[ CFI(tib) ] = critere[ CFI(tib + 8) ] ;
+ }
+ }
+
+ if (tib < 4){
+ if ( critere[ CFI(tib + 4) ].x < critere[ CFI(tib) ].x ){
+ critere[ CFI(tib) ] = critere[ CFI(tib + 4) ] ;
+ }
+ }
+
+ if (tib < 2){
+ if ( critere[ CFI(tib + 2) ].x < critere[ CFI(tib) ].x ){
+ critere[ CFI(tib) ] = critere[ CFI(tib + 2) ] ;
+ }
+ }
+
+ if (tib < 1){
+ if ( critere[ CFI(tib + 1) ].x < critere[ CFI(tib) ].x ){
+ critere[ CFI(tib) ] = critere[ CFI(tib + 1) ] ;
+ }
+ }
+ __syncthreads() ;
+}
+
+
+/*
+ calcule, pour l'ensemble des permutations possibles
+ des colonnes j1 et j2 (j1<J2) :
+ - le critère correspondant
+ */
+__global__ void calcul_contribs_permutations(tcontribs * somcols, int bpc, int h, int l, uint64 * stats_img, double2 * miniblocs){
+
+ int bs = blockDim.x ;
+ int j1 = blockIdx.x ;
+ int j2 = threadIdx.x ;
+
+ //shared mem dynamique 'critere' et 'indice'
+ extern __shared__ double2 critere[] ;
+
+ critere[ CFI(j2) ].y = j2 ; //initialisation des indices pour les minima
+
+ __syncthreads() ;
+
+ if (j1 < j2){
+ int colj1 = j1*bpc ;
+ int colj2 = j2*bpc ;
+ int ni = h*(colj2 - colj1) ;
+ int ne = h*l - ni ; // h*l ou stats_img[3]
+ uint64 stat_sum_xi = somcols[j2].cx - somcols[j1].cx ;
+ uint64 stat_sum_xi2 = somcols[j2].cx2 - somcols[j1].cx2 ;
+ uint64 stat_sum_xe = stats_img[4] - stat_sum_xi ; /* somme des xn region exterieure */
+ uint64 stat_sum_xe2 = stats_img[5] - stat_sum_xi2 ;
+ double sigi2, sige2; /* variances regions interieure et exterieure */
+
+ /* variance des valeurs des niveaux de gris a l'interieur */
+ sigi2 =
+ ((double)stat_sum_xi2/ni) -
+ ((double)stat_sum_xi/ni)*((double)stat_sum_xi/ni) ;
+
+ /* variance des valeurs des niveaux de gris a l'exterieur */
+ sige2 =
+ ((double)stat_sum_xe2)/ne -
+ ((double)stat_sum_xe/ne)*((double)stat_sum_xe/ne) ;
+
+ if ((sigi2 > 0)|(sige2 > 0))
+ critere[CFI(j2)].x = 0.5*((double)ni*log(sigi2) + (double)ne*log(sige2)) ;
+ else critere[CFI(j2)].x = DBL_MAX;
+ }
+ else critere[CFI(j2)].x = DBL_MAX ;
+
+ __syncthreads(); // on s'assure que toutes les valeurs des criteres sont calculees avant de chercher le mini
+
+ /*
+ if ( (bs >= 1024) && (j2 < 512) ) {
+ if ( critere[ CFI(j2 + 512) ].x < critere[ CFI(j2) ].x ){
+ critere[ CFI(j2) ] = critere[ CFI(j2 + 512) ] ;
+ __syncthreads() ;
+ }
+ }
+
+ if ( (bs >= 512) && (j2 < 256) ) {
+ if ( critere[ CFI(j2 + 256) ].x < critere[ CFI(j2) ].x ){
+ critere[ CFI(j2) ] = critere[ CFI(j2 + 256) ] ;
+ __syncthreads() ;
+ }
+ }
+
+ if ( (bs >= 256) && (j2 < 128) ) {
+ if ( critere[ CFI(j2 + 128) ].x < critere[ CFI(j2) ].x ){
+ critere[ CFI(j2) ] = critere[ CFI(j2 + 128) ] ;
+ __syncthreads() ;
+ }
+ }
+
+ if ( (bs >= 128) && (j2 < 64) ) {
+ if ( critere[ CFI(j2 + 64) ].x < critere[ CFI(j2) ].x ){
+ critere[ CFI(j2) ] = critere[ CFI(j2 + 64) ] ;
+ __syncthreads() ;
+ }
+ }
+
+ //32 threads <==> 1 warp
+ if (j2 < 32){
+ if ( critere[ CFI(j2 + 32) ].x < critere[ CFI(j2) ].x ){
+ critere[ CFI(j2) ] = critere[ CFI(j2 + 32) ] ;
+ }
+ }
+
+ if (j2 < 16){
+ if ( critere[ CFI(j2 + 16) ].x < critere[ CFI(j2) ].x ){
+ critere[ CFI(j2) ] = critere[ CFI(j2 + 16) ] ;
+ }
+ }
+
+ if (j2 < 8){
+ if ( critere[ CFI(j2 + 8) ].x < critere[ CFI(j2) ].x ){
+ critere[ CFI(j2) ] = critere[ CFI(j2 + 8) ] ;
+ }
+ }
+
+ if (j2 < 4){
+ if ( critere[ CFI(j2 + 4) ].x < critere[ CFI(j2) ].x ){
+ critere[ CFI(j2) ] = critere[ CFI(j2 + 4) ] ;
+ }
+ }
+
+ if (j2 < 2){
+ if ( critere[ CFI(j2 + 2) ].x < critere[ CFI(j2) ].x ){
+ critere[ CFI(j2) ] = critere[ CFI(j2 + 2) ] ;
+ }
+ }
+
+ if (j2 < 1){
+ if ( critere[ CFI(j2 + 1) ].x < critere[ CFI(j2) ].x ){
+ critere[ CFI(j2) ] = critere[ CFI(j2 + 1) ] ;
+ }
+ //critere[0] contient maintenant les params du mini du bloc
+ miniblocs[ j1 ] = critere[0] ;
+ }
+ */
+ mini_critere_bloc(critere, bs) ;
+ if (j2 == 0) miniblocs[ j1 ] = critere[0] ;
+}
+
+
+__device__ void somme_contribs_blocs(tcontribs * scontrib, int bs){
+ int tib = threadIdx.x ;
+ // somme des contribs individuelles par bloc
+ // unroll des sommes partielles en smem
+ if (bs >= 1024) {
+ if (tib < 512) {
+ scontrib[ CFI(tib) ].cx += scontrib[ CFI(tib + 512) ].cx;
+ scontrib[ CFI(tib) ].cx2 += scontrib[CFI(tib + 512) ].cx2;
+ }
+ __syncthreads();
+ }
+
+ if (bs >= 512) {
+ if (tib < 256) {
+ scontrib[ CFI(tib) ].cx += scontrib[ CFI(tib + 256) ].cx;
+ scontrib[ CFI(tib) ].cx2 += scontrib[CFI(tib + 256) ].cx2;
+ }
+ __syncthreads();
+ }
+
+ if (bs >= 256) {
+ if (tib < 128) {
+ scontrib[ CFI(tib) ].cx += scontrib[ CFI(tib + 128) ].cx;
+ scontrib[ CFI(tib) ].cx2 += scontrib[CFI(tib + 128) ].cx2;
+ }
+ __syncthreads();
+ }
+ if (bs >= 128) {
+ if (tib < 64) {
+ scontrib[ CFI(tib) ].cx += scontrib[ CFI(tib + 64) ].cx;
+ scontrib[ CFI(tib) ].cx2 += scontrib[CFI(tib + 64) ].cx2;
+ }
+ __syncthreads();
+ }
+
+ //32 threads <==> 1 warp
+ if (tib < 32)
+ {
+ scontrib[ CFI(tib) ].cx += scontrib[ CFI(tib + 32) ].cx;
+ scontrib[ CFI(tib) ].cx2 += scontrib[CFI(tib + 32) ].cx2;
+ }
+ if (tib < 16)
+ {
+ scontrib[ CFI(tib) ].cx += scontrib[ CFI(tib + 16) ].cx;
+ scontrib[ CFI(tib) ].cx2 += scontrib[CFI(tib + 16) ].cx2;
+ }
+ if (tib < 8)
+ {
+ scontrib[ CFI(tib) ].cx += scontrib[ CFI(tib + 8) ].cx;
+ scontrib[ CFI(tib) ].cx2 += scontrib[CFI(tib + 8) ].cx2;
+ }
+ if (tib < 4)
+ {
+ scontrib[ CFI(tib) ].cx += scontrib[ CFI(tib + 4) ].cx;
+ scontrib[ CFI(tib) ].cx2 += scontrib[CFI(tib + 4) ].cx2;
+ }
+ if (tib < 2)
+ {
+ scontrib[ CFI(tib) ].cx += scontrib[ CFI(tib + 2) ].cx;
+ scontrib[ CFI(tib) ].cx2 += scontrib[CFI(tib + 2) ].cx2;
+ }
+ if (tib < 1)
+ {
+ scontrib[ CFI(tib) ].cx += scontrib[ CFI(tib + 1) ].cx;
+ scontrib[ CFI(tib) ].cx2 += scontrib[CFI(tib + 1) ].cx2;
+ }
+
+ __syncthreads();
+}
+
+/*
+ effectue la somme (pix par pix) ds un bloc des contribs sur les colonnes j1 et j2 (j1 < j2)
+ Grille de calcul GPU :
+ -> threads = bs selon capacités/perfs
+ -> grid = div = (h+bs-1)/bs (h = nb lignes)
+ */
+__global__ void calcul_contrib_conjuguee_colonnes(t_cumul_x * cumul_x, t_cumul_x2 * cumul_x2, int h, int l, int j1, int j2, tcontribs * vect_contrib)
+{
+ int bs = blockDim.x ;
+ int id_bloc = blockIdx.x ;
+ int tib = threadIdx.x ;
+ int idx = id_bloc * bs + tib ;
+
+ extern __shared__ tcontribs sh_contrib[] ;
+
+ if (idx < h){
+ sh_contrib[CFI(tib)].cx = cumul_x[ idx * l + j2 ] - cumul_x[ idx * l + j1 ] ;
+ sh_contrib[CFI(tib)].cx2= cumul_x2[ idx * l + j2 ] - cumul_x2[ idx * l + j1 ] ;
+ } else {
+ sh_contrib[CFI(tib)].cx = 0 ;
+ sh_contrib[CFI(tib)].cx2= 0 ;
+ }
+ __syncthreads(); // synchro avant de sommer
+
+ /*sommes par bloc*/
+ somme_contribs_blocs(sh_contrib, bs);
+
+ /*enregistrement somme des blocs*/
+ if (tib == 0) vect_contrib[ id_bloc ] = sh_contrib[0] ;
+
+}
+
+/*
+ evalue les hauteurs les plus probables des horizontales
+ du rectangle 'englobant' (qui ne l'est pas nécessairement en fait)
+ Grille de calcul GPU :
+ -> threads = div = nb de blocs de lignes (Cf. calcul_contrib_conjuguee_colonnes() )
+ -> grid = div x div x 1
+*/
+__global__ void calcul_contribs_snake_rectangle(tcontribs * vect_contribs, tcontribs * soms)
+{
+ int bs = blockDim.x ;
+ int div = gridDim.x ;
+ int tib = threadIdx.x ;
+ int i1 = blockIdx.x ;
+ int i2 = blockIdx.y ;
+
+ extern __shared__ tcontribs scontribs[] ;
+
+ if (i2 >= i1){
+ if ( (tib >= i1) && (tib <= i2) ) {
+ scontribs[CFI(tib)].cx = vect_contribs[tib].cx ;
+ scontribs[CFI(tib)].cx2= vect_contribs[tib].cx2;
+ } else {
+ scontribs[CFI(tib)].cx = 0;
+ scontribs[CFI(tib)].cx2 = 0;
+ }
+ __syncthreads() ;
+ /*sommes par bloc*/
+ somme_contribs_blocs(scontribs, bs);
+
+ /*ranger les sommes ds un vecteur en gmem*/
+ if (tib == 0) soms[ i1*div + i2 ] = scontribs[0] ;
+ } else {
+ if (tib == 0) {
+ soms[ i1*div + i2 ].cx = 0 ;
+ soms[ i1*div + i2 ].cx = 0 ;
+ }
+ }
+}
+
+/*
+ Evalue la valeur du critere pour chaque combinaison possible
+ des blocs de lignes définis par calcul_contrib_conjuguee_colonnes()
+ grille de calcul GPU :
+ threads -> nextPow2 (div)
+ grid -> div x 1 x1
+
+ TODO voir a inverser les indices i1/i2
+ */
+
+__global__ void calcul_critere_permutations_verticales(tcontribs *soms, int lpb, int j1, int j2, int h, int l, uint64 sigX, uint64 sigX2, double2 *miniblocs){
+
+ int n = h*l ;
+ int bs = blockDim.x ;
+ int div = gridDim.x ;
+ int i2 = threadIdx.x ;
+ int i1 = blockIdx.x ;
+
+ extern __shared__ double2 sh_mini[];
+
+ if ( (i2 < div) && (i2 >= i1) )
+ sh_mini[ CFI(i2) ].x = critere_gauss(n, (i2-i1+1)*lpb*(j2 - j1), soms[ i1*div +i2 ].cx, soms[ i1*div + i2 ].cx2, sigX, sigX2);
+ else sh_mini[ CFI(i2) ].x = DBL_MAX ;
+ __syncthreads() ;
+
+ mini_critere_bloc(sh_mini, bs) ;
+
+ if (i2==0) {
+ //miniblocs[i1] = sh_mini[0] ;
+ miniblocs[i1].x = sh_mini[0].x ;
+ miniblocs[i1].y = sh_mini[0].y ;