From: perrot Date: Tue, 15 Feb 2011 12:29:51 +0000 (+0100) Subject: Initial commit X-Git-Url: https://bilbo.iut-bm.univ-fcomte.fr/and/gitweb/snake_gpu.git/commitdiff_plain/935bdd1c8b99ce5d70b6e4a53ca29f06353e8baa Initial commit Snake gpu for sm20 --- 935bdd1c8b99ce5d70b6e4a53ca29f06353e8baa diff --git a/exec/SNAKE2D b/exec/SNAKE2D new file mode 100755 index 0000000..67f3437 Binary files /dev/null and b/exec/SNAKE2D differ diff --git a/lib/lib_alloc.o b/lib/lib_alloc.o new file mode 100644 index 0000000..a7408ec Binary files /dev/null and b/lib/lib_alloc.o differ diff --git a/lib/lib_contour.o b/lib/lib_contour.o new file mode 100644 index 0000000..26fc29d Binary files /dev/null and b/lib/lib_contour.o differ diff --git a/lib/lib_images.o b/lib/lib_images.o new file mode 100644 index 0000000..120abff Binary files /dev/null and b/lib/lib_images.o differ diff --git a/lib/lib_math.o b/lib/lib_math.o new file mode 100644 index 0000000..a9ff110 Binary files /dev/null and b/lib/lib_math.o differ diff --git a/lib/lib_snake_common.o b/lib/lib_snake_common.o new file mode 100644 index 0000000..a7abed2 Binary files /dev/null and b/lib/lib_snake_common.o differ diff --git a/makefile b/makefile new file mode 100644 index 0000000..70d42b5 --- /dev/null +++ b/makefile @@ -0,0 +1,82 @@ +# chemin des librairies + + +PATH_GCC = $(PWD) + +PATH_LIB = $(PATH_GCC)/lib/ +PATH_SRC = $(PATH_GCC)/src/ +PATH_EXEC = $(PATH_GCC)/exec/ + +# repertoires pour les headers +PATH_INCLUDE = $(PATH_GCC)/src/ + +# compilateur +CC = gcc +NVCC = /usr/local/cuda/bin/nvcc +CXX = g++ + +# options de compilation +# -Wall : Warning all +# -g : debug (ex : gdb sas) +# -pg : profile memoire et cpu pour chaque fonctions (ex : gprof name | less) +# -O3 : optimisation code -O0 (rien) ~ -O3 (maxi) +# -fstrict-aliasing : aligne la memoire sur 32 bits + +# gcc +OPTION_CC1 = -Wall -O3 -static #-pg #-g -fprofile-arcs -ftest-coverage +OPTION_CC2 = $(OPTION_CC1) -funroll-all-loops -fstrict-aliasing + +OPTION_CC = $(OPTION_CC2) -I$(PATH_INCLUDE) -I$(PATH_SRC) + + +# librairies pour la compilation +LIB_CC = -lm +LIBSNV = -L/usr/local/cuda/lib64 -lcuda -lcudart + +# sources utiles a la compilation des main +SRCS = lib_alloc.c lib_images.c lib_math.c lib_snake_common.c lib_contour.c + +SRCS_NV = lib_test_gpu.cu lib_snake_2_gpu.cu lib_gpu.cu snake2D_gpu.cu + +OBJS = $(SRCS:%.c=$(PATH_LIB)%.o) $(SRCS_NV:%.cu=$(PATH_LIB)%.o) + +# dependances supplementaires +DEPS = $(PATH_SRC)/constantes.h $(PATH_SRC)/structures.h $(PATH_GCC)/makefile +help : + @echo "cibles : snake2D doc clean" + +all : snake2D doc +clean : + -rm -f $(PATH_LIB)*.o + -rm -rf $(PATH_GCC)/docs/ + + +# regle pour les .o +# --use_fast_math +# --ptxas-options=-v +$(PATH_LIB)%_gpu.o : $(PATH_SRC)%_gpu.cu + $(NVCC) -arch=sm_20 --use_fast_math -c $< -o $@ + +$(PATH_LIB)%.o : $(PATH_SRC)%.c $(DEPS) + $(CC) $(OPTION_CC) -c $< -o $@ + +# regle pour l'exec + +$(PATH_EXEC)SNAKE2D : $(PATH_SRC)snake2D_gpu.cu $(OBJS) $(DEPS) + $(CXX) $(OBJS) $(LIBSNV) \ + -o $(PATH_EXEC)SNAKE2D + +# compilation main + +snake2D : $(PATH_EXEC)SNAKE2D + @echo "" + @echo "***** fin compil snake2D *****" + @echo "" + +# generation des doc + +doc : + doxygen doxygen.conf + @echo "" + @echo "***** fin compil doc *****" + @echo "" diff --git a/src/constantes.h b/src/constantes.h new file mode 100644 index 0000000..38ad9db --- /dev/null +++ b/src/constantes.h @@ -0,0 +1,52 @@ +/** + * \file constantes.h + * \brief Definition des parametres de l'algo snake + * \author NB - PhyTI + * \version x.x + * \date 20 decembre 2009 + * + * + */ + + +#ifndef _CONSTANTES_H + +#define _CONSTANTES_H + + +/** + * \def COEF_DECROI pourcentage de decroissance pour accepter les modifications + * \def INV_COEF_DECROI pourcentage de decroissance pour accepter les modifications + */ +#define COEF_DECROI 0.99999 +#define INV_COEF_DECROI 1.00001 + + +/** + * \def ALIGN_SSE attribut d'alignement memoire pour sse2 (128 bits) + */ +//#define ATT_ALIGN_SSE __attribute__ ((aligned (16))) + + +/** + * \def ALIGN_SSE alignement memoire pour sse2 (128 bits) + */ +//#define ALIGN_SSE 16 + + +/** + * \def NBBIT_SUM1 longueur du champ de bits associe a sum_1 + * \def NBBIT_SUMX longueur du champ de bits associe a sum_x + */ +/*#define NBBIT_SUM1 24 sur 64 */ +/*#define NBBIT_SUMX 40 sur 64 (complement) */ + +/** + * \def SIZE_NAME_FILE longueur maxi associee aux noms de fichiers + * \def SIZE_LINE_TEXT longueur maxi associee a une ligne de texte + */ +#define SIZE_NAME_FILE 256 +#define SIZE_LINE_TEXT 256 + + +#endif //_CONSTANTES_H diff --git a/src/constantes.h~ b/src/constantes.h~ new file mode 100644 index 0000000..38ad9db --- /dev/null +++ b/src/constantes.h~ @@ -0,0 +1,52 @@ +/** + * \file constantes.h + * \brief Definition des parametres de l'algo snake + * \author NB - PhyTI + * \version x.x + * \date 20 decembre 2009 + * + * + */ + + +#ifndef _CONSTANTES_H + +#define _CONSTANTES_H + + +/** + * \def COEF_DECROI pourcentage de decroissance pour accepter les modifications + * \def INV_COEF_DECROI pourcentage de decroissance pour accepter les modifications + */ +#define COEF_DECROI 0.99999 +#define INV_COEF_DECROI 1.00001 + + +/** + * \def ALIGN_SSE attribut d'alignement memoire pour sse2 (128 bits) + */ +//#define ATT_ALIGN_SSE __attribute__ ((aligned (16))) + + +/** + * \def ALIGN_SSE alignement memoire pour sse2 (128 bits) + */ +//#define ALIGN_SSE 16 + + +/** + * \def NBBIT_SUM1 longueur du champ de bits associe a sum_1 + * \def NBBIT_SUMX longueur du champ de bits associe a sum_x + */ +/*#define NBBIT_SUM1 24 sur 64 */ +/*#define NBBIT_SUMX 40 sur 64 (complement) */ + +/** + * \def SIZE_NAME_FILE longueur maxi associee aux noms de fichiers + * \def SIZE_LINE_TEXT longueur maxi associee a une ligne de texte + */ +#define SIZE_NAME_FILE 256 +#define SIZE_LINE_TEXT 256 + + +#endif //_CONSTANTES_H diff --git a/src/defines.h b/src/defines.h new file mode 100644 index 0000000..d6dc963 --- /dev/null +++ b/src/defines.h @@ -0,0 +1,45 @@ +#ifndef __DEFINES_H__ +#define __DEFINES_H__ + + +const unsigned int CORRESPONDANCE_Di_Dj_FREEMAN[3][3] = + {{3,2,1}, + {4,8,0}, + {5,6,7}} ; + + +const int TABLE_CODAGE[8][8] = + {{ 0, 0, 0, 0, 0,-1,-1,-1}, /* 0 */ + { 1, 1, 1, 1, 1, 0, 0, 0}, /* 1 */ + { 1, 1, 1, 1, 1, 0, 0, 0}, /* 2 */ + { 1, 1, 1, 1, 1, 0, 0, 0}, /* 3 */ + { 0, 0, 0, 0, 0,-1,-1,-1}, /* 4 */ + { 0, 0, 0, 0, 0,-1,-1,-1}, /* 5 */ + { 0, 0, 0, 0, 0,-1,-1,-1}, /* 6 */ + { 0, 0, 0, 0, 0,-1,-1,-1}}; /* 7 */ +/* 0 1 2 3 4 5 6 7 */ + +const int TABLE_CODAGE1[8][8] = + {{ 0, 1, 1, 1, 1, 0, 0, 0}, /* 0 */ + { 0, 1, 1, 1, 1, 2, 0, 0}, /* 1 */ + { 0, 1, 1, 1, 1, 2, 2, 0}, /* 2 */ + { 0, 1, 1, 1, 1, 2, 2, 2}, /* 3 */ + {-1, 0, 0, 0, 0,-1,-1,-1}, /* 4 */ + {-1, 2, 0, 0, 0,-1,-1,-1}, /* 5 */ + {-1, 2, 2, 0, 0,-1,-1,-1}, /* 6 */ + {-1, 2, 2, 2, 0,-1,-1,-1}}; /* 7 */ +/* 0 1 2 3 4 5 6 7 */ + +#define BSMAX 128 +#define MAX_PIX 20000 +#define MAX_NODES 1000 +#define MAX_LISTE_PIX 10000000 +#define MAX(x,y) ( ( (x)>=(y) )?(x):(y) ) +#define ABS(x) ( ((x)>0)?(x):-(x)) +#define DEC 4 +#define DEC2 8 +#define CONFLICT_FREE_OFFSET(index) ( ((index) >>(DEC)) + ((index) >>(DEC2) ) ) +#define CFO(index) ( ( (index) >>(DEC) ) + ( (index) >>(DEC2) ) ) +#define CFI(index) ( (index) + (CFO(index)) ) + +#endif diff --git a/src/defines.h~ b/src/defines.h~ new file mode 100644 index 0000000..5bfa254 --- /dev/null +++ b/src/defines.h~ @@ -0,0 +1,45 @@ +#ifndef __DEFINES_H__ +#define __DEFINES_H__ + + +const unsigned int CORRESPONDANCE_Di_Dj_FREEMAN[3][3] = + {{3,2,1}, + {4,8,0}, + {5,6,7}} ; + + +const int TABLE_CODAGE[8][8] = + {{ 0, 0, 0, 0, 0,-1,-1,-1}, /* 0 */ + { 1, 1, 1, 1, 1, 0, 0, 0}, /* 1 */ + { 1, 1, 1, 1, 1, 0, 0, 0}, /* 2 */ + { 1, 1, 1, 1, 1, 0, 0, 0}, /* 3 */ + { 0, 0, 0, 0, 0,-1,-1,-1}, /* 4 */ + { 0, 0, 0, 0, 0,-1,-1,-1}, /* 5 */ + { 0, 0, 0, 0, 0,-1,-1,-1}, /* 6 */ + { 0, 0, 0, 0, 0,-1,-1,-1}}; /* 7 */ +/* 0 1 2 3 4 5 6 7 */ + +const int TABLE_CODAGE1[8][8] = + {{ 0, 1, 1, 1, 1, 0, 0, 0}, /* 0 */ + { 0, 1, 1, 1, 1, 2, 0, 0}, /* 1 */ + { 0, 1, 1, 1, 1, 2, 2, 0}, /* 2 */ + { 0, 1, 1, 1, 1, 2, 2, 2}, /* 3 */ + {-1, 0, 0, 0, 0,-1,-1,-1}, /* 4 */ + {-1, 2, 0, 0, 0,-1,-1,-1}, /* 5 */ + {-1, 2, 2, 0, 0,-1,-1,-1}, /* 6 */ + {-1, 2, 2, 2, 0,-1,-1,-1}}; /* 7 */ +/* 0 1 2 3 4 5 6 7 */ + +#define BS 512 +#define MAX_PIX 20000 +#define MAX_NODES 1000 +#define MAX_LISTE_PIX 10000000 +#define MAX(x,y) ( ( (x)>=(y) )?(x):(y) ) +#define ABS(x) ( ((x)>0)?(x):-(x)) +#define DEC 4 +#define DEC2 8 +#define CONFLICT_FREE_OFFSET(index) ( ((index) >>(DEC)) + ((index) >>(DEC2) ) ) +#define CFO(index) ( ( (index) >>(DEC) ) + ( (index) >>(DEC2) ) ) +#define CFI(index) ( (index) + (CFO(index)) ) + +#endif diff --git a/src/lib_alloc.c b/src/lib_alloc.c new file mode 100644 index 0000000..21bc735 --- /dev/null +++ b/src/lib_alloc.c @@ -0,0 +1,110 @@ +/** + * \file lib_alloc.c + * \brief routines d'allocation des differentes datas du snake2D3D + * \author NB - PhyTI + * \version x.x + * \date 20 decembre 2009 + * + */ + +#include + +#include "lib_alloc.h" + +/** + * \fn int **new_matrix_int(int i_dim, int j_dim) + * \brief allocation d'un tableau 2D (tab[i][j]) avec data en ligne (tab[0][n]) + * + * \param[in] i_dim dimension verticale du tableau + * \param[in] j_dim dimension horizontale du tableau + * + * \return pointeur sur le tableau + * + */ +int **new_matrix_int(int i_dim, int j_dim) +{ + // allocation en ligne + int **matrice ; + int *vecteur ; + int i ; + + vecteur = malloc(sizeof(int)*i_dim*j_dim) ; + matrice = malloc(sizeof(int*)*i_dim) ; + for (i=0;i + +#include "lib_alloc.h" + +/** + * \fn int **new_matrix_int(int i_dim, int j_dim) + * \brief allocation d'un tableau 2D (tab[i][j]) avec data en ligne (tab[0][n]) + * + * \param[in] i_dim dimension verticale du tableau + * \param[in] j_dim dimension horizontale du tableau + * + * \return pointeur sur le tableau + * + */ +int **new_matrix_int(int i_dim, int j_dim) +{ + // allocation en ligne + int **matrice ; + int *vecteur ; + int i ; + + vecteur = malloc(sizeof(int)*i_dim*j_dim) ; + matrice = malloc(sizeof(int*)*i_dim) ; + for (i=0;i P2] + * Utilise l'algo de Bresenham en version int (recupere sur Wikipedia) + * + */ +uint32 calcul_liste_pixel_segment(uint32 y1,uint32 x1,uint32 y2,uint32 x2, uint32 *liste_pixel_segment, int ind_offset) +{ + int dx, dy ; + int e ; + uint32 *liste ; + + liste = liste_pixel_segment + ind_offset ; + + if ( (dx=x2-x1) != 0) + { + if ( dx > 0 ) + { + if ( (dy=y2-y1) != 0 ) + { + if ( dy > 0 ) + { + // vecteur oblique dans le 1er quadran + if ( dx >= dy ) + { + // vecteur diagonal ou oblique proche de l'horizontale, dans le 1er octant + dx = (e=dx) * 2 ; dy = dy * 2 ; // e est positif + while( x1!=x2 ) //boucler sans fin: deplacements horizontaux + { + *liste++=y1; + *liste++=x1; + + x1++; + if ( (e-=dy) < 0 ) + { + y1++ ; // deplacement diagonal + e += dx ; + } + } + } + else + { + // vecteur oblique proche de la verticale, dans le 2nd octant + dy = (e=dy) * 2 ; dx = dx * 2 ; // e est positif + while ( y1 != y2 ) //boucler sans fin: deplacements verticaux + { + *liste++=y1; + *liste++=x1; + y1 += 1 ; + if ( (e -= dx) < 0 ) + { + x1++ ; // deplacement diagonal + e += dy ; + } + } + } + } + else // dy < 0 (et dx > 0) + { + // vecteur oblique dans le 4e cadran + if ( dx >= -dy ) + { + // vecteur diagonal ou oblique proche de l'horizontale, dans le 8e octant + dx = (e=dx) * 2 ; dy = dy * 2 ; // e est positif + while ( x1 != x2 ) //boucler sans fin // deplacements horizontaux + { + *liste++=y1; + *liste++=x1; + x1 ++; + if ( (e += dy) < 0 ) + { + y1--; // deplacement diagonal + e += dx ; + } + } + } + else // vecteur oblique proche de la verticale, dans le 7e octant + { + dy = (e=dy) * 2 ; dx = dx * 2 ; // e est negatif + while ( y1 != y2 ) // boucler sans fin: deplacements verticaux + { + *liste++=y1; + *liste++=x1; + y1--; + if ( (e += dx) > 0 ) + { + x1 ++; // deplacement diagonal + e += dy ; + } + } + } + } + } + else // dy = 0 (et dx > 0) + { + // vecteur horizontal vers la droite + while ( x1 != x2 ) + { + *liste++=y1; + *liste++=x1; + x1++ ; + } + } + } + else + { + // dx < 0 + if ( (dy=y2-y1) != 0 ) + { + if ( dy > 0 ) + { + // vecteur oblique dans le 2nd quadran + if ( -dx >= dy ) + { + // vecteur diagonal ou oblique proche de l'horizontale, dans le 4e octant + dx = (e=dx) * 2 ; dy = dy * 2 ; // e est negatif + while ( x1 != x2 ) //boucler sans fin // deplacements horizontaux + { + *liste++=y1; + *liste++=x1; + x1 -- ; + if ( (e += dy) >= 0 ) + { + y1++ ; // deplacement diagonal + e += dx ; + } + } + } + else + { + // vecteur oblique proche de la verticale, dans le 3e octant + dy = (e=dy) * 2 ; dx = dx * 2 ; // e est positif + while ( y1 != y2 ) //boucler sans fin // deplacements verticaux + { + *liste++=y1; + *liste++=x1; + y1++ ; + if ( (e += dx) <= 0 ) + { + x1--; // depacement diagonal + e += dy ; + } + } + } + } + + else // dy < 0 (et dx < 0) + { + // vecteur oblique dans le 3e cadran + if ( dx <= dy ) + { + // vecteur diagonal ou oblique proche de l'horizontale, dans le 5e octant + dx = (e=dx) * 2 ; dy = dy * 2 ; // e est negatif + while ( x1 != x2 ) //boucler sans fin // deplacements horizontaux + { + *liste++=y1; + *liste++=x1; + x1 -- ; + if ( (e -= dy) >= 0 ) + { + y1-- ; // deplacement diagonal + e += dx ; + } + } + } + else + { + // vecteur oblique proche de la verticale, dans le 6e octant + dy = (e=dy) * 2 ; dx = dx * 2 ; // e est negatif + while ( y1 != y2 ) //boucler sans fin // deplacements verticaux + { + *liste++=y1; + *liste++=x1; + y1-- ; + if ( (e-=dx) >= 0 ) + { + x1 --; // deplacement diagonal + e += dy ; + } + } + } + } + } + else // dy = 0 (et dx < 0) + { + // vecteur horizontal vers la gauche + while ( x1 != x2 ) + { + *liste++=y1; + *liste++=x1; + x1 -- ; + } + } + } + } + else // dx = 0 + { + if ( (dy=y2-y1) != 0 ) + { + if ( dy > 0 ) + { + // vecteur vertical croissant + while ( y1 != y2 ) + { + *liste++=y1; + *liste++=x1; + y1 ++ ; + } + } + else // dy < 0 (et dx = 0) + { + // vecteur vertical décroissant + while ( y1 != y2 ) + { + *liste++=y1; + *liste++=x1; + y1 -- ; + } + } + } + } + + *liste++=y2; + *liste++=x2; + + return (uint32)(liste-liste_pixel_segment)/2; +} diff --git a/src/lib_contour.h b/src/lib_contour.h new file mode 100644 index 0000000..12d2903 --- /dev/null +++ b/src/lib_contour.h @@ -0,0 +1,8 @@ +#ifndef _LIB_CONTOUR_H_ +#define _LIB_CONTOUR_H_ + +#include "structures.h" + +uint32 calcul_liste_pixel_segment(uint32 y1,uint32 x1,uint32 y2,uint32 x2, uint32 *liste_pixel_segment, int ind_offset) ; + +#endif //_LIB_CONTOUR_H_ diff --git a/src/lib_gpu.cu b/src/lib_gpu.cu new file mode 100644 index 0000000..d6df5ec --- /dev/null +++ b/src/lib_gpu.cu @@ -0,0 +1,623 @@ + +#include + + +extern "C"{ +#include "structures.h" +#include "lib_math.h" +#include "defines.h" +#include "lib_gpu.h" +#include "lib_snake_2_gpu.h" +} +#include "lib_test_gpu.h" +#include "lib_kernels_cumuls.cu" +#include "lib_kernel_snake_2_gpu.cu" + +#define DEBUG_IMG_CUMUL 1 +bool DISPLAY_ERR_IMG_CUMUL = 1; +//#define DEBUG_POSITIONS +//#define DEBUG_MOVE +//#define DEBUG_CRST +//#define DEBUG_MV +//#define DEBUG_SOMSOM +//#define DEBUG_SOMBLOCS +//#define DEBUG_LISTES +//#define DEBUG_STATS_REF + + + +void cuda_init_img_cumul(unsigned short ** img_in, int H, int L, int nb_nodes, + unsigned short ** d_img, t_cumul_x ** d_img_x, t_cumul_x2 ** d_img_x2, + int ** d_freemanDiDj, int ** d_codeNoeud, + snake_node_gpu ** d_snake, uint32 ** d_nb_pix_max, + uint4 ** d_positions, uint64 ** d_contribs_segments, uint4 ** d_freemans_centres, + int ** d_codes_segments, int64 ** d_stats_snake, + int64 ** d_stats, int64 ** d_stats_ref, double ** d_vrais, double ** d_vrais_snake, + uint2 ** d_liste_pixels, uint64 ** d_contribs_segments_blocs, + bool ** d_move + ) +{ + unsigned int taille = H*L; + timeval chrono; + + + //allocation cumuls en memoire GPU + tic(&chrono, NULL); + /* + MAX_PIX 20000 + MAX_NODES 10000 + MAX_LISTE_PIX 10000000 + */ + cudaMalloc( (void**) d_snake, MAX_NODES*sizeof(snake_node_gpu) ); + + cudaMalloc( (void**) d_img, taille*sizeof(unsigned short) ); + cudaMalloc( (void**) d_img_x, taille*sizeof(t_cumul_x) ); + cudaMalloc( (void**) d_img_x2, taille*sizeof(t_cumul_x2) ); + + cudaMalloc( (void**) d_freemanDiDj, 9*sizeof(int) ); + cudaMalloc( (void**) d_codeNoeud, 64*sizeof(int) ); + + cudaMalloc( (void**) d_stats_snake, 6*sizeof(int64)) ; + cudaMalloc( (void**) d_positions, 8*MAX_NODES*sizeof(uint4)) ; + cudaMalloc( (void**) d_contribs_segments, 3*16*MAX_NODES*sizeof(uint64)) ; + cudaMalloc( (void**) d_contribs_segments_blocs, (3*MAX_LISTE_PIX/32)*sizeof(uint64)) ; + cudaMalloc( (void**) d_freemans_centres, 16*MAX_NODES*sizeof(uint4)) ; + cudaMalloc( (void**) d_codes_segments, 16*MAX_NODES*sizeof(int)) ; + cudaMalloc( (void**) d_stats, 3*8*MAX_NODES*sizeof(int64)) ; + cudaMalloc( (void**) d_stats_ref, 3*MAX_NODES*sizeof(int64)) ; + cudaMalloc( (void**) d_vrais, 8*MAX_NODES*sizeof(double)) ; + cudaMalloc( (void**) d_move, MAX_NODES*sizeof(bool)) ; + cudaMalloc( (void**) d_nb_pix_max, sizeof(uint32)) ; + cudaMalloc( (void**) d_vrais_snake, sizeof(double)) ; + + cudaMalloc( (void**) d_liste_pixels, 16*5*(MAX_NODES)*sizeof(uint2) ); + + printf("TOTAL MEM = %ld octets\n", + (2*MAX_NODES*(sizeof(snake_node_gpu)+(8+16)*sizeof(uint4)+3*16*8+16*4+24*8+3*8+8*sizeof(double)+sizeof(bool)) + +(MAX_LISTE_PIX)*(sizeof(uint2)+1) + +taille*(8+sizeof(t_cumul_x)+sizeof(t_cumul_x2)) + +9*4+64*4+6*8+4+sizeof(double)) ); + + int64 * h_stats_snake = new int64[6]; + + toc(chrono, "temps alloc mem GPU"); + + /*detection-choix-initialisation de la carte GPU*/ + tic(&chrono, NULL) ; + cudaDeviceProp deviceProp; + deviceProp.major = 2; + deviceProp.minor = 0; + int dev; + cudaChooseDevice(&dev, &deviceProp); + cudaGetDeviceProperties(&deviceProp, dev); + if(deviceProp.major >= 2 ) + { + printf("Using Device %d: \"%s\"\n", dev, deviceProp.name); + cudaSetDevice(dev); + } + toc(chrono, "temps acces GPU") ; + + //copie tables correspondances freeman en mem GPU + tic(&chrono, NULL) ; + cudaMemcpy( *d_freemanDiDj, CORRESPONDANCE_Di_Dj_FREEMAN , 9*sizeof(int), cudaMemcpyHostToDevice); + cudaMemcpy( *d_codeNoeud, TABLE_CODAGE , 64*sizeof(unsigned int), cudaMemcpyHostToDevice); + toc(chrono, "temps transfert tables de codage") ; + + /*transfert image en global mem GPU*/ + tic(&chrono, NULL); + cudaMemcpy( *d_img, img_in[0], taille*sizeof(unsigned short), cudaMemcpyHostToDevice); + toc(chrono, "transfert image vers GPU"); + + //calculs images cumulees sur GPU + int blocs_max = 65536 ; + int bs = 256 ; //arbitraire, d'apres les observations c'est souvent l'optimu + unsigned int base = 0 ; + unsigned int bl_l = (L+bs-1)/bs ; + unsigned int nb_lines = blocs_max / bl_l ; + unsigned int lines ; + unsigned int tranches = ( 1 + H / nb_lines ) ; + nb_lines = (H +tranches -1)/ tranches ; // equilibre la taille des tranches + + dim3 threads(bs,1,1); + int smem = nextPow2(bl_l)*2; //smem pour le prefixscan des sommes de blocs (etape 2) + smem += smem >> DEC; + smem += smem >> DEC; + int smem_size = smem*sizeof(uint64); + uint64 * d_somblocs ; // sommes des cumuls par bloc de calcul + + + if(DEBUG_IMG_CUMUL) + { + printf("--- CALCULS IMAGES CUMULEES+STATS GPU ----\n"); + printf("\t%d threads par bloc -- %u blocs par ligne -- %u tranches -- %u lignes par tranche \n",bs, bl_l, tranches,nb_lines); + printf(" Smem totale pour cumuls : %d\n", CFI(bs)*(sizeof(t_cumul_x)+sizeof(t_cumul_x2)) ); + tic(&chrono, NULL); + } + //calculs cumuls generiques : necessitent 3 etapes / 3 kernels + cudaMalloc( (void**) &d_somblocs, 2*bl_l*nb_lines*sizeof(uint64) ); + cudaFuncSetCacheConfig(calcul_cumuls_gpu, cudaFuncCachePreferShared); + do + { + if ( H-base < nb_lines ) lines = H - base ; else lines = nb_lines ; + printf("base = ligne %d -- traitement de %d lignes \n", base, lines) ; + dim3 grid(bl_l*lines,1,1) ; + calcul_cumuls_gpu<<>>(*d_img, *d_img_x, *d_img_x2, H, L, d_somblocs, bl_l, base, lines) ; + scan_somblocs<<<2*lines, nextPow2(bl_l)/2, smem_size>>>(d_somblocs, bl_l) ; + add_soms_to_cumuls<<>>(*d_img_x, *d_img_x2, H, L, d_somblocs, bl_l, base, lines) ; + base += lines ; + } + while (base < H) ; + cudaFree(d_somblocs) ; + + //calcul des sommes totales N, sigX et sigX2 sur l'image + calcul_stats_image<<<1, 1>>>( *d_img_x, *d_img_x2, H, L, (uint64*)*d_stats_snake); + + + cudaThreadSynchronize() ; + toc(chrono, "\tTemps GPU"); + if(DEBUG_IMG_CUMUL) + { + + //allocation memoire CPU + t_cumul_x * img_x = new t_cumul_x [H*L]; + t_cumul_x2 * img_x2 = new t_cumul_x2 [H*L]; + + /*pour test comparaison*/ + t_cumul_x * img_xb = new t_cumul_x [H*L]; + t_cumul_x2 * img_x2b = new t_cumul_x2 [H*L]; + + cudaMemcpy( img_xb, *d_img_x, taille*sizeof(t_cumul_x), cudaMemcpyDeviceToHost); + cudaMemcpy( img_x2b, *d_img_x2, taille*sizeof(t_cumul_x2), cudaMemcpyDeviceToHost); + + //cumuls : etape 1 CPU + /* + for (int i=0; i>>(*d_snake, 140, H, L) ; + else if (nb_nodes == 40) genere_snake_rectangle_Nnodes_gpu<<< 1, 1>>>(*d_snake, (H+L)/20, H, L) ; + + int nnodes = nb_nodes ; + snake_node_gpu * h_snake = new snake_node_gpu[nnodes]; + snake_node * h_snake_ll = new snake_node[nnodes] ; + uint4 * h_liste_positions = new uint4[nnodes*8]; + double * h_vrais_snake = new double ; + //init les stats du snake + uint2 * d_liste_temp ; + t_sum_x2 * d_sompart ; + int tpb, bps, npixmax ; + + //calcul nb threads par bloc + npixmax = 2*(H+L-4*dist)/(nnodes-1) ; + tpb = nextPow2(npixmax) ; + if (tpb >= 256) tpb = 256 ;// /!\ le kernel <<< calcul_contrib...>>> ne supporte pas un bs>256 a cause de la shared-mem nécessaire + if (tpb < 32 ) tpb = 32 ; + tpb=128 ; + bps = (npixmax+tpb-1)/tpb ; + printf("PARAMS EXEC INIT : %d pix max, %d threads/bloc, %d blocs/seg, %d blocs/grille\n", npixmax, tpb, bps, nnodes*bps); + + //alloc + cudaMalloc((void**) &d_liste_temp, nnodes*bps*tpb*sizeof(uint2)); + cudaMalloc((void**) &d_sompart, 3*nnodes*bps*sizeof(t_sum_x2)); + cudaMalloc((void**) &d_stats_ref, 3*nnodes*sizeof(int64)); + + //DEBUG : pour forcer la mise à zero du tableau intermediaire d_stats_ref + int64 h_stats_ref[3*nnodes] ; + for (int a=0; a<3*nnodes ; a++) h_stats_ref[a] = 0 ; + cudaMemcpy( h_stats_ref, d_stats_ref, sizeof(int64), cudaMemcpyHostToDevice) ; + //fin forçage a 0 + + //DEBUG : pour forcer la mise à zero du tableau intermediaire d_sompart + t_sum_x2 h_sompart[ 3*nnodes*bps ] ; + for (int a=0; a<3*nnodes*bps ; a++) h_sompart[a] = 0 ; + cudaMemcpy( h_sompart, d_sompart, sizeof(t_sum_x2), cudaMemcpyHostToDevice) ; + //fin forçage a 0 + + calcul_contribs_segments_snake<<< nnodes*bps, tpb, (CFI(tpb))*(3*sizeof(t_sum_x2))>>> + (*d_snake, nnodes, + *d_img_x, *d_img_x2, + L, d_liste_temp, d_sompart, *d_freemanDiDj ); + + //TODO + //parametrer pour ne pas appeler qd tpb=1 + //oblige a modifier le kernel <<< calcul_contrib...>>> pour ecrire directement ds d_snake + // au lieu de d_sompart + somsom_snake<<< nnodes , 1 >>>(d_sompart, nnodes, bps, *d_snake); + + + calcul_stats_snake<<< 1 , 1 >>>(*d_snake, nnodes, *d_stats_snake, *d_vrais_snake, + *d_img_x, *d_img_x2, + *d_codeNoeud, L + ); + cudaThreadSynchronize() ; + toc(chrono, "\tTemps") ; + + /* + verif stats initiales du snake + */ + cudaMemcpy( h_vrais_snake, *d_vrais_snake, sizeof(double), cudaMemcpyDeviceToHost) ; + cudaMemcpy( h_stats_snake, *d_stats_snake, 6*sizeof(int64), cudaMemcpyDeviceToHost) ; + + printf("STATS SNAKE log vrais=%lf : c1=%lu - cx=%lu - cx2=%lu - N=%lu - SUMX=%lu - SUMX2=%lu\n", + *h_vrais_snake, + h_stats_snake[0], h_stats_snake[1], h_stats_snake[2], + h_stats_snake[3], h_stats_snake[4], h_stats_snake[5] ); + + /* + verif stats diminuees des contribs des 2 segments associes a chaque noeud + */ +#ifdef DEBUG_STATS_REF + cudaMemcpy( h_stats_ref, d_stats_ref, 3*nnodes*sizeof(int64), cudaMemcpyDeviceToHost) ; + cudaMemcpy( h_snake, *d_snake, nnodes*sizeof(snake_node_gpu), cudaMemcpyDeviceToHost) ; + + + printf("******* STATS DIMINUEES\n"); + for(int n=0; n0) ) + { + // /!\ penser a oter le test de prise en + // compte pour les pix sur la même ligne dans + // le kernel, sinon les comparaisons des + // sommes par colonne seront fausses + i = h_liste_pixels_segment[2*(b*bs + p)] ; + j = h_liste_pixels_segment[2*(b*bs + p) + 1] ; + c1 += img_1[i][j] ; + cx += img_x[i][j] ; + cx2+= img_x2[i][j]; + } + } + if ( ( c1 != h_sombloc[(16*n + s)*nblocs_seg + b ] ) || ( cx != h_sombloc[(16*n + s)*nblocs_seg + b + grid.x] ) + || ( cx2 != h_sombloc[ (16*n + s)*nblocs_seg + b + 2*grid.x] ) ) + printf("seg %d - %d pix : bloc %d -> CPU : %lu - %lu - %lu \t|| GPU : %lu - %lu - %lu \n", s, nb_pix, b, + c1, cx, cx2, h_sombloc[(16*n+s)*nblocs_seg + b], h_sombloc[(16*n+s)*nblocs_seg + b + grid.x], + h_sombloc[(16*n+s)*nblocs_seg + b + 2*grid.x]) ; + } + + } + for(int s=0; s<8; s++) + { + int nb_pix = calcul_liste_pixel_segment( h_liste_positions[8*idx_n+s].x, h_liste_positions[8*idx_n+s].y, + h_snake[idx_nsuiv].posi,h_snake[idx_nsuiv].posj, + h_liste_pixels_segment, 0); + for (int b=0; b0) ) + { + // /!\ penser a oter le test de prise en + // compte pour les pix sur la même ligne dans + // le kernel, sinon les comparaisons des + // sommes par colonne seront fausses + i = h_liste_pixels_segment[2*(b*bs + p)] ; + j = h_liste_pixels_segment[2*(b*bs + p) + 1] ; + c1 += img_1[i][j] ; + cx += img_x[i][j] ; + cx2+= img_x2[i][j]; + } + } + if ( ( c1 != h_sombloc[(16*n + s + 8)*nblocs_seg + b ] ) || ( cx != h_sombloc[(16*n + s + 8)*nblocs_seg + b + grid.x] ) + || ( cx2 != h_sombloc[ (16*n + s + 8)*nblocs_seg + b + 2*grid.x] ) ) + printf("seg %d - %d pix : bloc %d -> CPU : %lu - %lu - %lu \t|| GPU : %lu - %lu - %lu \n", s, nb_pix, b, + c1, cx, cx2, h_sombloc[(16*n+s+8)*nblocs_seg + b], h_sombloc[(16*n+s+8)*nblocs_seg + b + grid.x], + h_sombloc[(16*n+s+8)*nblocs_seg + b + 2*grid.x]) ; + } + + } + + } +#endif //DEBUG_SOMBLOCS + + + /* + + Test du calcul des sommes totales 'somsom' faites par le kernel 'somsom_full' + + */ + +#ifdef DEBUG_SOMSOM + printf("********* SOMMES TOTALES ***********\n"); + printf("bs = %d - grid = %d - intervalles = %d - nblocs_seg = %d - pairs = %d \n", bs, grid.x, n_interval, nblocs_seg, pairs); + for (int n=0; n< n_interval; n++) + { + idx_n = 2*n + !pairs ; + if (idx_n == 0) idx_nprec = nnodes - 1 ; + else idx_nprec = idx_n - 1 ; + if (idx_n == nnodes-1) idx_nsuiv = 0 ; + else idx_nsuiv = idx_n + 1 ; + printf("******** node %d\n", idx_n) ; + for(int s=0; s<8; s++) + { + int nb_pix = calcul_liste_pixel_segment(h_snake[idx_nprec].posi,h_snake[idx_nprec].posj, + h_liste_positions[8*idx_n+s].x, h_liste_positions[8*idx_n+s].y, + h_liste_pixels_segment, 0); + uint64 c1=0, cx=0, cx2=0 ; + for (int b=0; b0) ) + { + // /!\ penser a oter le test de prise en + // compte pour les pix sur la même ligne dans + // le kernel, sinon les comparaisons des + // sommes par colonne seront fausses + i = h_liste_pixels_segment[2*(b*bs + p)] ; + j = h_liste_pixels_segment[2*(b*bs + p) + 1] ; + c1 += img_1[i][j] ; + cx += img_x[i][j] ; + cx2+= img_x2[i][j]; + } + } + } + if ( ( c1 != h_somsom[3*(16*n + s)] ) || ( cx != h_somsom[3*(16*n + s) + 1] ) + || ( cx2 != h_somsom[3*(16*n + s) + 2] ) ) + printf("seg %d - %d pix -> CPU : %lu - %lu - %lu \t|| GPU : %lu - %lu - %lu \n", s, nb_pix, + c1, cx, cx2, h_somsom[3*(16*n + s)], h_somsom[3*(16*n + s) + 1], + h_somsom[3*(16*n + s) + 2]) ; + + } + + for(int s=0; s<8; s++) + { + int nb_pix = calcul_liste_pixel_segment( h_liste_positions[8*idx_n+s].x, h_liste_positions[8*idx_n+s].y, + h_snake[idx_nsuiv].posi,h_snake[idx_nsuiv].posj, + h_liste_pixels_segment, 0); + uint64 c1=0, cx=0, cx2=0 ; + for (int b=0; b0) ) + { + // /!\ penser a oter le test de prise en + // compte pour les pix sur la même ligne dans + // le kernel, sinon les comparaisons des + // sommes par colonne seront fausses + i = h_liste_pixels_segment[2*(b*bs + p)] ; + j = h_liste_pixels_segment[2*(b*bs + p) + 1] ; + c1 += img_1[i][j] ; + cx += img_x[i][j] ; + cx2+= img_x2[i][j]; + } + } + } + if ( ( c1 != h_somsom[3*(16*n + s + 8)] ) || ( cx != h_somsom[3*(16*n + s + 8) + 1] ) + || ( cx2 != h_somsom[3*(16*n + s + 8) + 2] ) ) + printf("seg %d - %d pix -> CPU : %lu - %lu - %lu \t|| GPU : %lu - %lu - %lu \n", s, nb_pix, + c1, cx, cx2, h_somsom[3*(16*n + s + 8)], h_somsom[3*(16*n + s + 8) + 1], + h_somsom[3*(16*n + s + 8) + 2]) ; + + } + + } + +#endif + + +#ifdef DEBUG_MV + printf("**** STATS - REF : %lf \n", *h_vrais_snake); + for(int n=0; n + + +extern "C"{ +#include "structures.h" +#include "lib_math.h" +#include "defines.h" +#include "lib_gpu.h" +#include "lib_snake_2_gpu.h" +} +#include "lib_test_gpu.h" +#include "lib_kernels_cumuls.cu" +#include "lib_kernel_snake_2_gpu.cu" + +#define DEBUG_IMG_CUMUL 1 +bool DISPLAY_ERR_IMG_CUMUL = 1; +//#define DEBUG_POSITIONS +//#define DEBUG_MOVE +//#define DEBUG_CRST +//#define DEBUG_MV +//#define DEBUG_SOMSOM +//#define DEBUG_SOMBLOCS +//#define DEBUG_LISTES +//#define DEBUG_STATS_REF + + +inline unsigned int nextPow2( unsigned int x ) { + --x; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return ++x; +} + + +void cuda_init_img_cumul(unsigned short ** img_in, int H, int L, int nb_nodes, + unsigned short ** d_img, t_cumul_x ** d_img_x, t_cumul_x2 ** d_img_x2, + int ** d_freemanDiDj, int ** d_codeNoeud, + snake_node_gpu ** d_snake, uint32 ** d_nb_pix_max, + uint4 ** d_positions, uint64 ** d_contribs_segments, uint4 ** d_freemans_centres, + int ** d_codes_segments, int64 ** d_stats_snake, + int64 ** d_stats, int64 ** d_stats_ref, double ** d_vrais, double ** d_vrais_snake, + uint2 ** d_liste_pixels, uint64 ** d_contribs_segments_blocs, + bool ** d_move + ) +{ + unsigned int taille = H*L; + timeval chrono; + + + //allocation cumuls en memoire GPU + tic(&chrono, NULL); + /* + MAX_PIX 20000 + MAX_NODES 10000 + MAX_LISTE_PIX 10000000 + */ + cudaMalloc( (void**) d_snake, MAX_NODES*sizeof(snake_node_gpu) ); + + cudaMalloc( (void**) d_img, taille*sizeof(unsigned short) ); + cudaMalloc( (void**) d_img_x, taille*sizeof(t_cumul_x) ); + cudaMalloc( (void**) d_img_x2, taille*sizeof(t_cumul_x2) ); + + cudaMalloc( (void**) d_freemanDiDj, 9*sizeof(int) ); + cudaMalloc( (void**) d_codeNoeud, 64*sizeof(int) ); + + cudaMalloc( (void**) d_stats_snake, 6*sizeof(int64)) ; + cudaMalloc( (void**) d_positions, 8*MAX_NODES*sizeof(uint4)) ; + cudaMalloc( (void**) d_contribs_segments, 3*16*MAX_NODES*sizeof(uint64)) ; + cudaMalloc( (void**) d_contribs_segments_blocs, (3*MAX_LISTE_PIX/32)*sizeof(uint64)) ; + cudaMalloc( (void**) d_freemans_centres, 16*MAX_NODES*sizeof(uint4)) ; + cudaMalloc( (void**) d_codes_segments, 16*MAX_NODES*sizeof(int)) ; + cudaMalloc( (void**) d_stats, 3*8*MAX_NODES*sizeof(int64)) ; + cudaMalloc( (void**) d_stats_ref, 3*MAX_NODES*sizeof(int64)) ; + cudaMalloc( (void**) d_vrais, 8*MAX_NODES*sizeof(double)) ; + cudaMalloc( (void**) d_move, MAX_NODES*sizeof(bool)) ; + cudaMalloc( (void**) d_nb_pix_max, sizeof(uint32)) ; + cudaMalloc( (void**) d_vrais_snake, sizeof(double)) ; + + cudaMalloc( (void**) d_liste_pixels, 16*5*(MAX_NODES)*sizeof(uint2) ); + + printf("TOTAL MEM = %ld octets\n", + (2*MAX_NODES*(sizeof(snake_node_gpu)+(8+16)*sizeof(uint4)+3*16*8+16*4+24*8+3*8+8*sizeof(double)+sizeof(bool)) + +(MAX_LISTE_PIX)*(sizeof(uint2)+1) + +taille*(8+sizeof(t_cumul_x)+sizeof(t_cumul_x2)) + +9*4+64*4+6*8+4+sizeof(double)) ); + + int64 * h_stats_snake = new int64[6]; + + toc(chrono, "temps alloc mem GPU"); + + /*detection-choix-initialisation de la carte GPU*/ + tic(&chrono, NULL) ; + cudaDeviceProp deviceProp; + deviceProp.major = 1; + deviceProp.minor = 0; + int desiredMinorRevision = 3; + int dev; + cudaChooseDevice(&dev, &deviceProp); + cudaGetDeviceProperties(&deviceProp, dev); + if(deviceProp.major > 1 || deviceProp.minor >= desiredMinorRevision) + { + printf("Using Device %d: \"%s\"\n", dev, deviceProp.name); + cudaSetDevice(dev); + } + toc(chrono, "temps acces GPU") ; + + //copie tables correspondances freeman en mem GPU + tic(&chrono, NULL) ; + cudaMemcpy( *d_freemanDiDj, CORRESPONDANCE_Di_Dj_FREEMAN , 9*sizeof(int), cudaMemcpyHostToDevice); + cudaMemcpy( *d_codeNoeud, TABLE_CODAGE , 64*sizeof(unsigned int), cudaMemcpyHostToDevice); + toc(chrono, "temps transfert tables de codage") ; + + /*transfert image en global mem GPU*/ + tic(&chrono, NULL); + cudaMemcpy( *d_img, img_in[0], taille*sizeof(unsigned short), cudaMemcpyHostToDevice); + toc(chrono, "transfert image vers GPU"); + + //calculs images cumulees sur GPU + int blocs_max = 65536 ; + int bs = 256 ; //arbitraire, d'apres les observations c'est souvent l'optimu + unsigned int base = 0 ; + unsigned int bl_l = (L+bs-1)/bs ; + unsigned int nb_lines = blocs_max / bl_l ; + unsigned int lines ; + unsigned int tranches = ( 1 + H / nb_lines ) ; + nb_lines = (H +tranches -1)/ tranches ; // equilibre la taille des tranches + unsigned blocs = bl_l*nb_lines ; + dim3 threads(bs,1,1); + int smem = nextPow2(bl_l)*2; //smem pour le prefixscan des sommes de blocs (etape 2) + smem += smem >> DEC; + smem += smem >> DEC; + int smem_size = smem*sizeof(uint64); + uint64 * d_somblocs ; // sommes des cumuls par bloc de calcul + + + if(DEBUG_IMG_CUMUL) + { + printf("--- CALCULS IMAGES CUMULEES+STATS GPU ----\n"); + printf("\t%d threads par bloc -- %u blocs par ligne -- %u tranches -- %u lignes par tranche \n",bs, bl_l, tranches,nb_lines); + printf(" Smem totale pour cumuls : %d\n", CFI(bs)*(sizeof(t_cumul_x)+sizeof(t_cumul_x2)) ); + tic(&chrono, NULL); + } + //calculs cumuls generiques : necessitent 3 etapes / 3 kernels + cudaMalloc( (void**) &d_somblocs, 2*bl_l*nb_lines*sizeof(uint64) ); + cudaFuncSetCacheConfig(calcul_cumuls_gpu, cudaFuncCachePreferShared); + do + { + if ( H-base < nb_lines ) lines = H - base ; else lines = nb_lines ; + printf("base = ligne %d -- traitement de %d lignes \n", base, lines) ; + dim3 grid(bl_l*lines,1,1) ; + calcul_cumuls_gpu<<>>(*d_img, *d_img_x, *d_img_x2, H, L, d_somblocs, bl_l, base, lines) ; + scan_somblocs<<<2*lines, nextPow2(bl_l)/2, smem_size>>>(d_somblocs, bl_l) ; + add_soms_to_cumuls<<>>(*d_img_x, *d_img_x2, H, L, d_somblocs, bl_l, base, lines) ; + base += lines ; + } + while (base < H) ; + cudaFree(d_somblocs) ; + + //calcul des sommes totales N, sigX et sigX2 sur l'image + calcul_stats_image<<<1, 1>>>( *d_img_x, *d_img_x2, H, L, (uint64*)*d_stats_snake); + + + cudaThreadSynchronize() ; + toc(chrono, "\tTemps GPU"); + if(DEBUG_IMG_CUMUL) + { + + //allocation memoire CPU + t_cumul_x * img_x = new t_cumul_x [H*L]; + t_cumul_x2 * img_x2 = new t_cumul_x2 [H*L]; + + /*pour test comparaison*/ + t_cumul_x * img_xb = new t_cumul_x [H*L]; + t_cumul_x2 * img_x2b = new t_cumul_x2 [H*L]; + + cudaMemcpy( img_xb, *d_img_x, taille*sizeof(t_cumul_x), cudaMemcpyDeviceToHost); + cudaMemcpy( img_x2b, *d_img_x2, taille*sizeof(t_cumul_x2), cudaMemcpyDeviceToHost); + + //cumuls : etape 1 CPU + /* + for (int i=0; i>>(*d_snake, 140, H, L) ; + else if (nb_nodes == 40) genere_snake_rectangle_Nnodes_gpu<<< 1, 1>>>(*d_snake, (H+L)/20, H, L) ; + + int nnodes = nb_nodes ; + snake_node_gpu * h_snake = new snake_node_gpu[nnodes]; + snake_node * h_snake_ll = new snake_node[nnodes] ; + uint4 * h_liste_positions = new uint4[nnodes*8]; + double * h_vrais_snake = new double ; + //init les stats du snake + uint2 * d_liste_temp ; + t_sum_x2 * d_sompart ; + int tpb, bps, npixmax ; + + //calcul nb threads par bloc + npixmax = 2*(H+L-4*dist)/(nnodes-1) ; + tpb = nextPow2(npixmax) ; + if (tpb >= 256) tpb = 256 ;// /!\ le kernel <<< calcul_contrib...>>> ne supporte pas un bs>256 a cause de la shared-mem nécessaire + if (tpb < 32 ) tpb = 32 ; + tpb=128 ; + bps = (npixmax+tpb-1)/tpb ; + printf("PARAMS EXEC INIT : %d pix max, %d threads/bloc, %d blocs/seg, %d blocs/grille\n", npixmax, tpb, bps, nnodes*bps); + + //alloc + cudaMalloc((void**) &d_liste_temp, nnodes*bps*tpb*sizeof(uint2)); + cudaMalloc((void**) &d_sompart, 3*nnodes*bps*sizeof(t_sum_x2)); + cudaMalloc((void**) &d_stats_ref, 3*nnodes*sizeof(int64)); + + //DEBUG : pour forcer la mise à zero du tableau intermediaire d_stats_ref + int64 h_stats_ref[3*nnodes] ; + for (int a=0; a<3*nnodes ; a++) h_stats_ref[a] = 0 ; + cudaMemcpy( h_stats_ref, d_stats_ref, sizeof(int64), cudaMemcpyHostToDevice) ; + //fin forçage a 0 + + //DEBUG : pour forcer la mise à zero du tableau intermediaire d_sompart + t_sum_x2 h_sompart[ 3*nnodes*bps ] ; + for (int a=0; a<3*nnodes*bps ; a++) h_sompart[a] = 0 ; + cudaMemcpy( h_sompart, d_sompart, sizeof(t_sum_x2), cudaMemcpyHostToDevice) ; + //fin forçage a 0 + + calcul_contribs_segments_snake<<< nnodes*bps, tpb, (CFI(tpb))*(3*sizeof(t_sum_x2))>>> + (*d_snake, nnodes, + *d_img_x, *d_img_x2, + L, d_liste_temp, d_sompart, *d_freemanDiDj ); + + //TODO + //parametrer pour ne pas appeler qd tpb=1 + //oblige a modifier le kernel <<< calcul_contrib...>>> pour ecrire directement ds d_snake + // au lieu de d_sompart + somsom_snake<<< nnodes , 1 >>>(d_sompart, nnodes, bps, *d_snake); + + + calcul_stats_snake<<< 1 , 1 >>>(*d_snake, nnodes, *d_stats_snake, *d_vrais_snake, + *d_img_x, *d_img_x2, + *d_codeNoeud, L + ); + cudaThreadSynchronize() ; + toc(chrono, "\tTemps") ; + + /* + verif stats initiales du snake + */ + cudaMemcpy( h_vrais_snake, *d_vrais_snake, sizeof(double), cudaMemcpyDeviceToHost) ; + cudaMemcpy( h_stats_snake, *d_stats_snake, 6*sizeof(int64), cudaMemcpyDeviceToHost) ; + + printf("STATS SNAKE log vrais=%lf : c1=%lu - cx=%lu - cx2=%lu - N=%lu - SUMX=%lu - SUMX2=%lu\n", + *h_vrais_snake, + h_stats_snake[0], h_stats_snake[1], h_stats_snake[2], + h_stats_snake[3], h_stats_snake[4], h_stats_snake[5] ); + + /* + verif stats diminuees des contribs des 2 segments associes a chaque noeud + */ +#ifdef DEBUG_STATS_REF + cudaMemcpy( h_stats_ref, d_stats_ref, 3*nnodes*sizeof(int64), cudaMemcpyDeviceToHost) ; + cudaMemcpy( h_snake, *d_snake, nnodes*sizeof(snake_node_gpu), cudaMemcpyDeviceToHost) ; + + + printf("******* STATS DIMINUEES\n"); + for(int n=0; n0) ) + { + // /!\ penser a oter le test de prise en + // compte pour les pix sur la même ligne dans + // le kernel, sinon les comparaisons des + // sommes par colonne seront fausses + i = h_liste_pixels_segment[2*(b*bs + p)] ; + j = h_liste_pixels_segment[2*(b*bs + p) + 1] ; + c1 += img_1[i][j] ; + cx += img_x[i][j] ; + cx2+= img_x2[i][j]; + } + } + if ( ( c1 != h_sombloc[(16*n + s)*nblocs_seg + b ] ) || ( cx != h_sombloc[(16*n + s)*nblocs_seg + b + grid.x] ) + || ( cx2 != h_sombloc[ (16*n + s)*nblocs_seg + b + 2*grid.x] ) ) + printf("seg %d - %d pix : bloc %d -> CPU : %lu - %lu - %lu \t|| GPU : %lu - %lu - %lu \n", s, nb_pix, b, + c1, cx, cx2, h_sombloc[(16*n+s)*nblocs_seg + b], h_sombloc[(16*n+s)*nblocs_seg + b + grid.x], + h_sombloc[(16*n+s)*nblocs_seg + b + 2*grid.x]) ; + } + + } + for(int s=0; s<8; s++) + { + int nb_pix = calcul_liste_pixel_segment( h_liste_positions[8*idx_n+s].x, h_liste_positions[8*idx_n+s].y, + h_snake[idx_nsuiv].posi,h_snake[idx_nsuiv].posj, + h_liste_pixels_segment, 0); + for (int b=0; b0) ) + { + // /!\ penser a oter le test de prise en + // compte pour les pix sur la même ligne dans + // le kernel, sinon les comparaisons des + // sommes par colonne seront fausses + i = h_liste_pixels_segment[2*(b*bs + p)] ; + j = h_liste_pixels_segment[2*(b*bs + p) + 1] ; + c1 += img_1[i][j] ; + cx += img_x[i][j] ; + cx2+= img_x2[i][j]; + } + } + if ( ( c1 != h_sombloc[(16*n + s + 8)*nblocs_seg + b ] ) || ( cx != h_sombloc[(16*n + s + 8)*nblocs_seg + b + grid.x] ) + || ( cx2 != h_sombloc[ (16*n + s + 8)*nblocs_seg + b + 2*grid.x] ) ) + printf("seg %d - %d pix : bloc %d -> CPU : %lu - %lu - %lu \t|| GPU : %lu - %lu - %lu \n", s, nb_pix, b, + c1, cx, cx2, h_sombloc[(16*n+s+8)*nblocs_seg + b], h_sombloc[(16*n+s+8)*nblocs_seg + b + grid.x], + h_sombloc[(16*n+s+8)*nblocs_seg + b + 2*grid.x]) ; + } + + } + + } +#endif //DEBUG_SOMBLOCS + + + /* + + Test du calcul des sommes totales 'somsom' faites par le kernel 'somsom_full' + + */ + +#ifdef DEBUG_SOMSOM + printf("********* SOMMES TOTALES ***********\n"); + printf("bs = %d - grid = %d - intervalles = %d - nblocs_seg = %d - pairs = %d \n", bs, grid.x, n_interval, nblocs_seg, pairs); + for (int n=0; n< n_interval; n++) + { + idx_n = 2*n + !pairs ; + if (idx_n == 0) idx_nprec = nnodes - 1 ; + else idx_nprec = idx_n - 1 ; + if (idx_n == nnodes-1) idx_nsuiv = 0 ; + else idx_nsuiv = idx_n + 1 ; + printf("******** node %d\n", idx_n) ; + for(int s=0; s<8; s++) + { + int nb_pix = calcul_liste_pixel_segment(h_snake[idx_nprec].posi,h_snake[idx_nprec].posj, + h_liste_positions[8*idx_n+s].x, h_liste_positions[8*idx_n+s].y, + h_liste_pixels_segment, 0); + uint64 c1=0, cx=0, cx2=0 ; + for (int b=0; b0) ) + { + // /!\ penser a oter le test de prise en + // compte pour les pix sur la même ligne dans + // le kernel, sinon les comparaisons des + // sommes par colonne seront fausses + i = h_liste_pixels_segment[2*(b*bs + p)] ; + j = h_liste_pixels_segment[2*(b*bs + p) + 1] ; + c1 += img_1[i][j] ; + cx += img_x[i][j] ; + cx2+= img_x2[i][j]; + } + } + } + if ( ( c1 != h_somsom[3*(16*n + s)] ) || ( cx != h_somsom[3*(16*n + s) + 1] ) + || ( cx2 != h_somsom[3*(16*n + s) + 2] ) ) + printf("seg %d - %d pix -> CPU : %lu - %lu - %lu \t|| GPU : %lu - %lu - %lu \n", s, nb_pix, + c1, cx, cx2, h_somsom[3*(16*n + s)], h_somsom[3*(16*n + s) + 1], + h_somsom[3*(16*n + s) + 2]) ; + + } + + for(int s=0; s<8; s++) + { + int nb_pix = calcul_liste_pixel_segment( h_liste_positions[8*idx_n+s].x, h_liste_positions[8*idx_n+s].y, + h_snake[idx_nsuiv].posi,h_snake[idx_nsuiv].posj, + h_liste_pixels_segment, 0); + uint64 c1=0, cx=0, cx2=0 ; + for (int b=0; b0) ) + { + // /!\ penser a oter le test de prise en + // compte pour les pix sur la même ligne dans + // le kernel, sinon les comparaisons des + // sommes par colonne seront fausses + i = h_liste_pixels_segment[2*(b*bs + p)] ; + j = h_liste_pixels_segment[2*(b*bs + p) + 1] ; + c1 += img_1[i][j] ; + cx += img_x[i][j] ; + cx2+= img_x2[i][j]; + } + } + } + if ( ( c1 != h_somsom[3*(16*n + s + 8)] ) || ( cx != h_somsom[3*(16*n + s + 8) + 1] ) + || ( cx2 != h_somsom[3*(16*n + s + 8) + 2] ) ) + printf("seg %d - %d pix -> CPU : %lu - %lu - %lu \t|| GPU : %lu - %lu - %lu \n", s, nb_pix, + c1, cx, cx2, h_somsom[3*(16*n + s + 8)], h_somsom[3*(16*n + s + 8) + 1], + h_somsom[3*(16*n + s + 8) + 2]) ; + + } + + } + +#endif + + +#ifdef DEBUG_MV + printf("**** STATS - REF : %lf \n", *h_vrais_snake); + for(int n=0; n> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return ++x; +} + + +void cuda_init_img_cumul(unsigned short ** img_in, int H, int L, int nb_nodes, + unsigned short ** d_img, t_cumul_x ** d_img_x, t_cumul_x2 ** d_img_x2, + int ** d_freemanDiDj, int ** d_codeNoeud, + snake_node_gpu ** d_snake, uint32 ** d_nb_pix_max, + uint4 ** d_positions, uint64 ** d_contribs_segments, uint4 ** d_freemans_centres, + int ** d_codes_segments, int64 ** d_stats_snake, + int64 ** d_stats, int64 ** d_stats_ref, double ** d_vrais, double ** d_vrais_snake, + uint2 ** d_liste_pixels, uint64 ** d_contribs_segments_blocs, + bool ** d_move + ); + +void affiche_snake_gpu(int **image, snake_node_gpu *snake, int nnodes_, int valseg, int valnoeud, + uint32 *liste_pixel_segment); + +#endif //_LIB_GPU_H_ diff --git a/src/lib_gpu.h~ b/src/lib_gpu.h~ new file mode 100644 index 0000000..9cfb894 --- /dev/null +++ b/src/lib_gpu.h~ @@ -0,0 +1,20 @@ +#ifndef _LIB_GPU_H_ +#define _LIB_GPU_H_ + +inline unsigned int nextPow2( unsigned int x ); + +void cuda_init_img_cumul(unsigned short ** img_in, int H, int L, int nb_nodes, + unsigned short ** d_img, t_cumul_x ** d_img_x, t_cumul_x2 ** d_img_x2, + int ** d_freemanDiDj, int ** d_codeNoeud, + snake_node_gpu ** d_snake, uint32 ** d_nb_pix_max, + uint4 ** d_positions, uint64 ** d_contribs_segments, uint4 ** d_freemans_centres, + int ** d_codes_segments, int64 ** d_stats_snake, + int64 ** d_stats, int64 ** d_stats_ref, double ** d_vrais, double ** d_vrais_snake, + uint2 ** d_liste_pixels, uint64 ** d_contribs_segments_blocs, + bool ** d_move + ); + +void affiche_snake_gpu(int **image, snake_node_gpu *snake, int nnodes_, int valseg, int valnoeud, + uint32 *liste_pixel_segment); + +#endif //_LIB_GPU_H_ diff --git a/src/lib_images.c b/src/lib_images.c new file mode 100644 index 0000000..0aaf81e --- /dev/null +++ b/src/lib_images.c @@ -0,0 +1,305 @@ +/** + * \file lib_images.c + * \brief Librairie de lecture/ecriture d'image ppm/pgm 8/16 bits + * \author NB - PhyTI + * \version x.x + * \date 20 decembre 2009 + * + */ + +#include +#include +#include +#include + +#include "lib_images.h" +#include "lib_math.h" + + +/** + * \fn int type_image_ppm(int *prof, int *i_dim, int *j_dim, int *level, char *file_name) + * \brief Fonction qui renvoie le type de l'image ppm et des caracteristiques + * + * \param[out] prof profondeur de l'image 1 pour pgm 3 pour ppm, 0 sinon + * \param[out] i_dim renvoie la dimension verticale de l'image (si NULL, renvoie que prof) + * \param[out] j_dim renvoie la dimension horizontale de l'image + * \param[out] level renvoie la dynamique de l'image + * \param[in] file_name fichier image + * + * \return 1 si ok O sinon + * + */ +int type_image_ppm(int *prof, uint32 *i_dim, uint32 *j_dim, int *level, char *file_name) +{ + char buffer[SIZE_LINE_TEXT] ; + FILE *file ; + + *prof = 0 ; + + file = fopen(file_name, "rb"); + if (file == NULL) + return 0 ; + + // lecture de la premiere ligne + fgets(buffer, SIZE_LINE_TEXT, file); + + /* pgm */ + if ((buffer[0] == 'P') & (buffer[1] == '5')) + *prof = 1 ; // GGG + /* ppm */ + if ((buffer[0] == 'P') & (buffer[1] == '6')) + *prof = 3 ; // RVBRVBRVB + + /* type non gere */ + if (*prof == 0) return 0 ; + + /* pour une utilisation du type */ + /* ret = type_image_ppm(&prof, NULL, NULL, NULL, file_name) */ + if (i_dim == NULL) + return 1 ; + + /* on saute les lignes de commentaires */ + fgets(buffer, SIZE_LINE_TEXT, file); + while ((buffer[0] == '#')|(buffer[0] == '\n')) + fgets(buffer, SIZE_LINE_TEXT, file); + + /* on lit les dimensions de l'image */ + sscanf(buffer, "%d %d", j_dim, i_dim) ; + fgets(buffer, SIZE_LINE_TEXT, file); + sscanf(buffer, "%d", level) ; + + + fclose(file); + return 1 ; +} + + + + +/** + * \fn void load_pgm2int(int **image, int i_dim, int j_dim, + * int nb_level, char *fichier_image) + * \brief lecture pgm 8 ou 16 bits + * + * \param[out] image + * \param[in] i_dim dimension verticale de l'image + * \param[in] j_dim dimension horizontale de l'image + * \param[in] nb_level dynamique de l'image + * \param[in] fichier_image fichier image + * + * + */ +void load_pgm2int(int **image, int i_dim, int j_dim, + int nb_level, char *fichier_image) +{ + int i, j ; + char buffer[SIZE_LINE_TEXT] ; + unsigned char *ligne; + unsigned short *ligne2; + FILE *file = fopen(fichier_image, "rb"); + + fgets(buffer, SIZE_LINE_TEXT, file); /* P5 */ + /* on saute les lignes de commentaires */ + fgets(buffer, SIZE_LINE_TEXT, file); + while ((buffer[0] == '#')|(buffer[0] == '\n')) + fgets(buffer, SIZE_LINE_TEXT, file); + /* derniere ligne lue : dimensions */ + fgets(buffer, SIZE_LINE_TEXT, file); /* dynamique */ + + /* data */ + + if (nb_level < 256) + { + // fichier en char, on converti au format int + ligne = malloc(sizeof(unsigned char)*j_dim) ; + + for (i=0;i +#include +#include +#include + +#include "lib_images.h" +#include "lib_math.h" + + +/** + * \fn int type_image_ppm(int *prof, int *i_dim, int *j_dim, int *level, char *file_name) + * \brief Fonction qui renvoie le type de l'image ppm et des caracteristiques + * + * \param[out] prof profondeur de l'image 1 pour pgm 3 pour ppm, 0 sinon + * \param[out] i_dim renvoie la dimension verticale de l'image (si NULL, renvoie que prof) + * \param[out] j_dim renvoie la dimension horizontale de l'image + * \param[out] level renvoie la dynamique de l'image + * \param[in] file_name fichier image + * + * \return 1 si ok O sinon + * + */ +int type_image_ppm(int *prof, uint32 *i_dim, uint32 *j_dim, int *level, char *file_name) +{ + char buffer[SIZE_LINE_TEXT] ; + FILE *file ; + + *prof = 0 ; + + file = fopen(file_name, "rb"); + if (file == NULL) + return 0 ; + + // lecture de la premiere ligne + fgets(buffer, SIZE_LINE_TEXT, file); + + /* pgm */ + if ((buffer[0] == 'P') & (buffer[1] == '5')) + *prof = 1 ; // GGG + /* ppm */ + if ((buffer[0] == 'P') & (buffer[1] == '6')) + *prof = 3 ; // RVBRVBRVB + + /* type non gere */ + if (*prof == 0) return 0 ; + + /* pour une utilisation du type */ + /* ret = type_image_ppm(&prof, NULL, NULL, NULL, file_name) */ + if (i_dim == NULL) + return 1 ; + + /* on saute les lignes de commentaires */ + fgets(buffer, SIZE_LINE_TEXT, file); + while ((buffer[0] == '#')|(buffer[0] == '\n')) + fgets(buffer, SIZE_LINE_TEXT, file); + + /* on lit les dimensions de l'image */ + sscanf(buffer, "%d %d", j_dim, i_dim) ; + fgets(buffer, SIZE_LINE_TEXT, file); + sscanf(buffer, "%d", level) ; + + + fclose(file); + return 1 ; +} + + + + +/** + * \fn void load_pgm2int(int **image, int i_dim, int j_dim, + * int nb_level, char *fichier_image) + * \brief lecture pgm 8 ou 16 bits + * + * \param[out] image + * \param[in] i_dim dimension verticale de l'image + * \param[in] j_dim dimension horizontale de l'image + * \param[in] nb_level dynamique de l'image + * \param[in] fichier_image fichier image + * + * + */ +void load_pgm2int(int **image, int i_dim, int j_dim, + int nb_level, char *fichier_image) +{ + int i, j ; + char buffer[SIZE_LINE_TEXT] ; + unsigned char *ligne; + unsigned short *ligne2; + FILE *file = fopen(fichier_image, "rb"); + + fgets(buffer, SIZE_LINE_TEXT, file); /* P5 */ + /* on saute les lignes de commentaires */ + fgets(buffer, SIZE_LINE_TEXT, file); + while ((buffer[0] == '#')|(buffer[0] == '\n')) + fgets(buffer, SIZE_LINE_TEXT, file); + /* derniere ligne lue : dimensions */ + fgets(buffer, SIZE_LINE_TEXT, file); /* dynamique */ + + /* data */ + + if (nb_level < 256) + { + // fichier en char, on converti au format int + ligne = malloc(sizeof(unsigned char)*j_dim) ; + + for (i=0;i limite ) + d_snake[n].posi = d_snake[n-1].posi + inch ; + else + d_snake[n].posi = d_snake[n-1].posi + inch/2 ; + d_snake[n].posj = dist_bords ; + d_snake[n-1].nb_pixels = d_snake[n].posi - d_snake[n-1].posi ; + n++ ; i++ ; + } + /* n1 */ + d_snake[n].posi = i_dim - dist_bords ; + d_snake[n].posj = dist_bords ; + d_snake[n-1].nb_pixels = d_snake[n].posi - d_snake[n-1].posi ; + n++ ; + /*entre S1 et S2*/ + i = 0 ; + while (i< nb_node_seg) + { + if ( (j_dim - dist_bords) - (d_snake[n-1].posj + incl) > limite ) + d_snake[n].posj = d_snake[n-1].posj + incl ; + else + d_snake[n].posj = d_snake[n-1].posj + incl/2 ; + d_snake[n].posi = i_dim - dist_bords ; + d_snake[n-1].nb_pixels = d_snake[n].posj - d_snake[n-1].posj ; + n++ ; i++ ; + } + /* n2 */ + d_snake[n].posi = i_dim - dist_bords ; + d_snake[n].posj = j_dim - dist_bords ; + d_snake[n-1].nb_pixels = d_snake[n].posj - d_snake[n-1].posj ; + n++ ; + /*entre S2 et S3*/ + i = 0 ; + while (i< nb_node_seg) + { + if ( (d_snake[n-1].posi - inch) - dist_bords > limite ) + d_snake[n].posi = d_snake[n-1].posi - inch ; + else + d_snake[n].posi = d_snake[n-1].posi - inch/2 ; + d_snake[n].posj = j_dim - dist_bords ; + d_snake[n-1].nb_pixels = d_snake[n-1].posi - d_snake[n].posi ; + n++ ; i++ ; + } + /* n3 */ + d_snake[n].posi = dist_bords ; + d_snake[n].posj = j_dim - dist_bords ; + d_snake[n-1].nb_pixels = d_snake[n-1].posi - d_snake[n].posi ; + n++ ; + /*entre S3 et S0*/ + i = 0 ; + while (i< nb_node_seg) + { + if ( (d_snake[n-1].posj - incl) - dist_bords > limite) + d_snake[n].posj = d_snake[n-1].posj - incl ; + else + d_snake[n].posj = d_snake[n-1].posj - incl/2 ; + d_snake[n].posi = dist_bords ; + d_snake[n-1].nb_pixels = d_snake[n-1].posj - d_snake[n].posj ; + n++ ; i++ ; + } + d_snake[n-1].nb_pixels = d_snake[n-1].posj - d_snake[0].posj ; + for (i=0; i taille smem dynamique + t_sum_x* scumuls_x = (t_sum_x*) &scumuls_1[CFI(blockDim.x)] ; + t_sum_x2* scumuls_x2 = (t_sum_x2*) &scumuls_x[CFI(blockDim.x)] ; + + //indices des noeuds + uint x1, y1, x2, y2 ; + int n1, n2 ; + + n1 = segment ; + n2 = segment +1 ; + //gestion du bouclage du snake + if (n2 >= nb_nodes) n2 = 0 ; + + //affectation des differentes positions aux différents segments 'blocs de threads' + x1 = d_snake[n1].posj ; + y1 = d_snake[n1].posi ; + x2 = d_snake[n2].posj ; + y2 = d_snake[n2].posi ; + + //params des deplacements + int dx=x2-x1; + int dy=y2-y1; + uint abs_dx = ABS(dx); + uint abs_dy = ABS(dy); + uint nb_pix = abs_dy>abs_dx?(abs_dy+1):(abs_dx+1); // alternative -> lecture ds liste_points[] + int incx=0, incy=0; + uint2 p ; + int xprec, xsuiv ; + + //calcul liste des pixels du segment (x1,y1)-(x2,y2) + if (dy > 0) incy=1; else incy=-1 ; + if (dx > 0) incx=1; else incx=-1 ; + + if (tis < nb_pix){ + if (abs_dy > abs_dx){ + //1 thread par ligne + double k = (double)dx/dy ; + p.x = y1 + incy*tis ; + p.y = x1 + floor((double)incy*k*tis+0.5) ; + //enreg. coords. pixels en global mem pour freemans + + if ((tis < 2)||(tis > nb_pix - 3)||(tis == nb_pix/2)) + { + liste_pix[idx].x = p.x ; + liste_pix[idx].y = p.y ; + } + + } else { + //1 thread par colonne + double k=(double)dy/dx ; + p.x = y1 + floor((double)(incx*k*tis)+0.5) ; + p.y = x1 + incx*tis ; + if ( tis > 0 ){ + xsuiv = y1 + floor((double)(incx*k*(tis+1))+0.5) ; + xprec = y1 + floor((double)(incx*k*(tis-1))+0.5) ; + } + //enreg. coords. pixels en global mem pour freeman + //TODO + //on peut calculer les freemans des segments + //sans stocker l'ensemble des valeurs des pixels + //juste avec les derivees aux extremites a calculer ici + + if ((tis < 2)||(tis > nb_pix - 3)||(tis == nb_pix/2)) + { + liste_pix[idx].x = p.x ; + liste_pix[idx].y = p.y ; + } + + } + } + __syncthreads(); + + //calcul contribs individuelles des pixels + + if ( (tis >0) && (tis < nb_pix-1) + && ( (abs_dy <= abs_dx) + && ( (xprec > p.x) || (xsuiv > p.x)) + || (abs_dy > abs_dx) ) ) + { + int pos = p.x * l + p.y ; + scumuls_1[ CFI(tib)] = 1+p.y; + scumuls_x[ CFI(tib)] = cumul_x[ pos ] ; + scumuls_x2[CFI(tib)] = cumul_x2[ pos ]; + } else { + scumuls_1[ CFI(tib)] = 0; + scumuls_x[ CFI(tib)] = 0; + scumuls_x2[CFI(tib)] = 0; + } + + __syncthreads(); + //somme des contribs individuelles + // unroll des sommes partielles en smem + + if (blockSize >= 512) { + if (tib < 256) { + scumuls_1[ CFI(tib)] += scumuls_1[ CFI(tib + 256) ]; + scumuls_x[ CFI(tib)] += scumuls_x[ CFI(tib + 256) ]; + scumuls_x2[CFI(tib)] += scumuls_x2[CFI(tib + 256) ]; + } + __syncthreads(); + } + + if (blockSize >= 256) { + if (tib < 128) { + scumuls_1[ CFI(tib)] += scumuls_1[ CFI(tib + 128) ]; + scumuls_x[ CFI(tib)] += scumuls_x[ CFI(tib + 128) ]; + scumuls_x2[CFI(tib)] += scumuls_x2[CFI(tib + 128) ]; + } + __syncthreads(); + } + if (blockSize >= 128) { + if (tib < 64) { + scumuls_1[ CFI(tib)] += scumuls_1[ CFI(tib + 64) ]; + scumuls_x[ CFI(tib)] += scumuls_x[ CFI(tib + 64) ]; + scumuls_x2[CFI(tib)] += scumuls_x2[CFI(tib + 64) ]; + } + __syncthreads(); + } + + //32 threads <==> 1 warp + if (tib < 32) + { + { + scumuls_1[ CFI(tib)] += scumuls_1[ CFI(tib + 32) ]; + scumuls_x[ CFI(tib)] += scumuls_x[ CFI(tib + 32) ]; + scumuls_x2[CFI(tib)] += scumuls_x2[CFI(tib + 32) ]; + } + { + scumuls_1[ CFI(tib)] += scumuls_1[ CFI(tib + 16) ]; + scumuls_x[ CFI(tib)] += scumuls_x[ CFI(tib + 16) ]; + scumuls_x2[CFI(tib)] += scumuls_x2[CFI(tib + 16) ]; + } + { + scumuls_1[ CFI(tib)] += scumuls_1[ CFI(tib + 8) ]; + scumuls_x[ CFI(tib)] += scumuls_x[ CFI(tib + 8) ]; + scumuls_x2[CFI(tib)] += scumuls_x2[CFI(tib + 8) ]; + } + scumuls_1[ CFI(tib)] += scumuls_1[ CFI(tib + 4) ]; + scumuls_x[ CFI(tib)] += scumuls_x[ CFI(tib + 4) ]; + scumuls_x2[CFI(tib)] += scumuls_x2[CFI(tib + 4) ]; + + scumuls_1[ CFI(tib)] += scumuls_1[ CFI(tib + 2) ]; + scumuls_x[ CFI(tib)] += scumuls_x[ CFI(tib + 2) ]; + scumuls_x2[CFI(tib)] += scumuls_x2[CFI(tib + 2) ]; + + scumuls_1[ CFI(tib)] += scumuls_1[ CFI(tib + 1) ]; + scumuls_x[ CFI(tib)] += scumuls_x[ CFI(tib + 1) ]; + scumuls_x2[CFI(tib)] += scumuls_x2[CFI(tib + 1) ]; + } + + // resultat sommes partielles en gmem + if (tib == 0) { + gsombloc[ blockIdx.x ] = (t_sum_x2) scumuls_1[0]; + gsombloc[ blockIdx.x + gridDim.x ] = (t_sum_x2) scumuls_x[0]; + gsombloc[ blockIdx.x + 2*gridDim.x ] = (t_sum_x2) scumuls_x2[0]; + } + + //calculs freemans, centre et code segment + //1 uint4 par segment + + int Di, Dj; + if (tis == 0){ + Di = 1 + liste_pix[idx+1].x - liste_pix[idx].x ; + Dj = 1 + liste_pix[idx+1].y - liste_pix[idx].y ; + d_snake[segment].freeman_out = d_table_freeman[3*Di + Dj] ; + //code seg + if (dy > 0 ) d_snake[segment].code_segment = -1 ; + if (dy < 0 ) d_snake[segment].code_segment = 1 ; + if (dy == 0) d_snake[segment].code_segment = 0 ; + } + + if (tis == nb_pix-1){ + Di = 1 + liste_pix[idx].x - liste_pix[idx-1].x ; + Dj = 1 + liste_pix[idx].y - liste_pix[idx-1].y; + d_snake[segment].freeman_in = d_table_freeman[3*Di + Dj] ; + } + + if (tis == (nb_pix/2)){ + d_snake[segment].centre_i = liste_pix[idx].x ; + d_snake[segment].centre_j = liste_pix[idx].y ; + } +} + +/* + sommme des contribs par bloc -> contribs segment, pour le snake + + execution sur : 1bloc / 1 thread par segment + */ + +__global__ void somsom_snake(t_sum_x2 * somblocs, int nb_nodes, unsigned int nb_bl_seg, snake_node_gpu * d_snake){ + + t_sum_x2 sdata[3]; + unsigned int seg = blockIdx.x ; + + //un thread par segment + { + sdata[0] = 0; + sdata[1] = 0; + sdata[2] = 0; + } + + for (int b=0; b < nb_bl_seg ; b++){ + sdata[0] += somblocs[seg*nb_bl_seg + b]; + sdata[1] += somblocs[(seg + nb_nodes)*nb_bl_seg + b]; + sdata[2] += somblocs[(seg + 2*nb_nodes)*nb_bl_seg + b]; + } + + //totaux en gmem + { + d_snake[seg].sum_1 = sdata[0]; + d_snake[seg].sum_x = sdata[1]; + d_snake[seg].sum_x2 = sdata[2]; + } +} + +__device__ double codage_gl_gauss(uint64 stat_sum_1, uint64 stat_sum_x, uint64 stat_sum_x2, + uint64 n_dim, uint64 SUM_X, uint64 SUM_X2){ + uint64 stat_sum_xe ; /* somme des xn region exterieure */ + uint32 ne ; /* nombre de pixel region exterieure */ + double sigi2, sige2; /* variance region interieure et exterieure */ + + /* variance des valeurs des niveaux de gris a l'interieur du snake */ + sigi2 = + ((double)stat_sum_x2/(double)stat_sum_1) - + ((double)stat_sum_x/(uint64)stat_sum_1)*((double)stat_sum_x/(uint64)stat_sum_1) ; + + /* variance des valeurs des niveaux de gris a l'exterieur du snake */ + ne = n_dim-stat_sum_1 ; + stat_sum_xe = SUM_X - stat_sum_x ; + sige2 = + ((double)SUM_X2-stat_sum_x2)/(double)ne - + ((double)stat_sum_xe/(uint64)ne)*((double)stat_sum_xe/(uint64)ne) ; + + if ((sigi2 > 0)|(sige2 > 0)) + return 0.5*((double)stat_sum_1*log(sigi2) + (double)ne*log(sige2)) ; + return -1 ; +} + + +__global__ void calcul_stats_snake(snake_node_gpu * d_snake, int nnodes, int64 * d_stats_snake, double * vrais_min, + t_cumul_x * cumul_x, t_cumul_x2 * cumul_x2, int * TABLE_CODAGE, uint32 l + ) +{ + + int id_nx, id_nprec, id_nprecprec ; + int code_noeud, code_segment, pos ; + __shared__ int64 s_stats_snake[3] ; + + //init stats en shared mem + s_stats_snake[0] = 0 ; + s_stats_snake[1] = 0 ; + s_stats_snake[2] = 0 ; + + + for (id_nx = 0; id_nx < nnodes; id_nx++) + { + if (id_nx == 0) id_nprec = nnodes - 1; + else id_nprec = id_nx - 1; + if (id_nprec == 0) id_nprecprec = nnodes -1 ; + else id_nprecprec = id_nprec - 1 ; + /* gestion des segments partant du noeud */ + /* vers le noeud suivant dans l'ordre trigo */ + code_segment = d_snake[id_nprec].code_segment ; + if (code_segment > 0) + { + /* on somme les contributions */ + s_stats_snake[0] += d_snake[id_nprec].sum_1 ; + s_stats_snake[1] += d_snake[id_nprec].sum_x ; + s_stats_snake[2] += d_snake[id_nprec].sum_x2 ; + } + else if (code_segment < 0) + { + /* on soustrait les contributions */ + s_stats_snake[0] -= d_snake[id_nprec].sum_1 ; + s_stats_snake[1] -= d_snake[id_nprec].sum_x ; + s_stats_snake[2] -= d_snake[id_nprec].sum_x2 ; + } + // else (code_segment == 0), on ne fait rien + /* gestion des pixels connectant les segments */ + /* pixel de depart du segment actuel np --> np->noeud_suiv */ + /* freeman_out = np->freeman_out ; */ + /* freeman_in = np->noeud_prec->freeman_in ; */ + pos = d_snake[id_nprecprec].freeman_in*8 + d_snake[id_nprec].freeman_out ; + code_noeud = TABLE_CODAGE[pos] ; + pos = d_snake[id_nprec].posi*l + d_snake[id_nprec].posj ; + + if (code_noeud > 0) + { + /* on somme les contributions */ + s_stats_snake[0] += 1 + d_snake[id_nprec].posj ; + s_stats_snake[1] += cumul_x[pos] ; + s_stats_snake[2] += cumul_x2[pos] ; + } + else if (code_noeud < 0) + { + /* on soustrait les contributions */ + s_stats_snake[0] -= 1 + d_snake[id_nprec].posj ; + s_stats_snake[1] -= cumul_x[pos] ; + s_stats_snake[2] -= cumul_x2[pos] ; + } + // else (code_pixel == 0), on ne fait rien + } + d_stats_snake[0] = s_stats_snake[0] ; + d_stats_snake[1] = s_stats_snake[1] ; + d_stats_snake[2] = s_stats_snake[2] ; + + *vrais_min = codage_gl_gauss(s_stats_snake[0], s_stats_snake[1], s_stats_snake[2], + d_stats_snake[3], d_stats_snake[4], d_stats_snake[5]); +} diff --git a/src/lib_kernel_snake_2_gpu.cu~ b/src/lib_kernel_snake_2_gpu.cu~ new file mode 100644 index 0000000..eba3a46 --- /dev/null +++ b/src/lib_kernel_snake_2_gpu.cu~ @@ -0,0 +1,447 @@ + + +__global__ void genere_snake_rectangle_4nodes_gpu(snake_node_gpu * d_snake, int dist_bords, int i_dim, int j_dim){ + if (threadIdx.x == 0){ + int n = 0; + /* n0 */ + d_snake[n].posi = dist_bords ; + d_snake[n].posj = dist_bords ; + n++ ; + /* n1 */ + d_snake[n].posi = i_dim - dist_bords ; + d_snake[n].posj = dist_bords ; + n++ ; + /* n2 */ + d_snake[n].posi = i_dim - dist_bords ; + d_snake[n].posj = j_dim - dist_bords ; + n++ ; + /* n3 */ + d_snake[n].posi = dist_bords ; + d_snake[n].posj = j_dim - dist_bords ; + + for (int i=0; i<4; i++) + { + d_snake[i].freeman_in = 0; + d_snake[i].freeman_out = 0; + d_snake[i].centre_i = 0; + d_snake[i].centre_j = 0; + d_snake[i].last_move = 0; + d_snake[i].nb_pixels = 0; + d_snake[i].code_segment = 0; + + } + } +} + + +__global__ void genere_snake_rectangle_Nnodes_gpu(snake_node_gpu * d_snake, int dist_bords, int i_dim, int j_dim){ + int nb_node_seg = 9 ; + int limite = 64 ; + + int i , h= i_dim-2*dist_bords, l= j_dim-2*dist_bords ; + int inch = h/(nb_node_seg+1), incl= l/(nb_node_seg+1) ; + if (threadIdx.x == 0){ + int n = 0; + /* n0 */ + d_snake[n].posi = dist_bords ; + d_snake[n].posj = dist_bords ; + n++ ; + /*entre sommet 0 et 1*/ + i = 0 ; + while (i < nb_node_seg) + { + if ( (d_snake[n-1].posi + inch)-(i_dim - dist_bords) > limite ) + d_snake[n].posi = d_snake[n-1].posi + inch ; + else + d_snake[n].posi = d_snake[n-1].posi + inch/2 ; + d_snake[n].posj = dist_bords ; + d_snake[n-1].nb_pixels = d_snake[n].posi - d_snake[n-1].posi ; + n++ ; i++ ; + } + /* n1 */ + d_snake[n].posi = i_dim - dist_bords ; + d_snake[n].posj = dist_bords ; + d_snake[n-1].nb_pixels = d_snake[n].posi - d_snake[n-1].posi ; + n++ ; + /*entre S1 et S2*/ + i = 0 ; + while (i< nb_node_seg) + { + if ( (j_dim - dist_bords) - (d_snake[n-1].posj + incl) > limite ) + d_snake[n].posj = d_snake[n-1].posj + incl ; + else + d_snake[n].posj = d_snake[n-1].posj + incl/2 ; + d_snake[n].posi = i_dim - dist_bords ; + d_snake[n-1].nb_pixels = d_snake[n].posj - d_snake[n-1].posj ; + n++ ; i++ ; + } + /* n2 */ + d_snake[n].posi = i_dim - dist_bords ; + d_snake[n].posj = j_dim - dist_bords ; + d_snake[n-1].nb_pixels = d_snake[n].posj - d_snake[n-1].posj ; + n++ ; + /*entre S2 et S3*/ + i = 0 ; + while (i< nb_node_seg) + { + if ( (d_snake[n-1].posi - inch) - dist_bords > limite ) + d_snake[n].posi = d_snake[n-1].posi - inch ; + else + d_snake[n].posi = d_snake[n-1].posi - inch/2 ; + d_snake[n].posj = j_dim - dist_bords ; + d_snake[n-1].nb_pixels = d_snake[n-1].posi - d_snake[n].posi ; + n++ ; i++ ; + } + /* n3 */ + d_snake[n].posi = dist_bords ; + d_snake[n].posj = j_dim - dist_bords ; + d_snake[n-1].nb_pixels = d_snake[n-1].posi - d_snake[n].posi ; + n++ ; + /*entre S3 et S0*/ + i = 0 ; + while (i< nb_node_seg) + { + if ( (d_snake[n-1].posj - incl) - dist_bords > limite) + d_snake[n].posj = d_snake[n-1].posj - incl ; + else + d_snake[n].posj = d_snake[n-1].posj - incl/2 ; + d_snake[n].posi = dist_bords ; + d_snake[n-1].nb_pixels = d_snake[n-1].posj - d_snake[n].posj ; + n++ ; i++ ; + } + d_snake[n-1].nb_pixels = d_snake[n-1].posj - d_snake[0].posj ; + for (i=0; i taille smem dynamique + t_sum_x* scumuls_x = (t_sum_x*) &scumuls_1[CFI(blockDim.x)] ; + t_sum_x2* scumuls_x2 = (t_sum_x2*) &scumuls_x[CFI(blockDim.x)] ; + + //indices des noeuds + uint x1, y1, x2, y2 ; + int n1, n2 ; + + n1 = segment ; + n2 = segment +1 ; + //gestion du bouclage du snake + if (n2 >= nb_nodes) n2 = 0 ; + + //affectation des differentes positions aux différents segments 'blocs de threads' + x1 = d_snake[n1].posj ; + y1 = d_snake[n1].posi ; + x2 = d_snake[n2].posj ; + y2 = d_snake[n2].posi ; + + //params des deplacements + int dx=x2-x1; + int dy=y2-y1; + uint abs_dx = ABS(dx); + uint abs_dy = ABS(dy); + uint nb_pix = abs_dy>abs_dx?(abs_dy+1):(abs_dx+1); // alternative -> lecture ds liste_points[] + int incx=0, incy=0; + uint2 p ; + int xprec, xsuiv ; + + //calcul liste des pixels du segment (x1,y1)-(x2,y2) + if (dy > 0) incy=1; else incy=-1 ; + if (dx > 0) incx=1; else incx=-1 ; + + if (tis < nb_pix){ + if (abs_dy > abs_dx){ + //1 thread par ligne + double k = (double)dx/dy ; + p.x = y1 + incy*tis ; + p.y = x1 + floor((double)incy*k*tis+0.5) ; + //enreg. coords. pixels en global mem pour freemans + + if ((tis < 2)||(tis > nb_pix - 3)||(tis == nb_pix/2)) + { + liste_pix[idx].x = p.x ; + liste_pix[idx].y = p.y ; + } + + } else { + //1 thread par colonne + double k=(double)dy/dx ; + p.x = y1 + floor((double)(incx*k*tis)+0.5) ; + p.y = x1 + incx*tis ; + if ( tis > 0 ){ + xsuiv = y1 + floor((double)(incx*k*(tis+1))+0.5) ; + xprec = y1 + floor((double)(incx*k*(tis-1))+0.5) ; + } + //enreg. coords. pixels en global mem pour freeman + //TODO + //on peut calculer les freemans des segments + //sans stocker l'ensemble des valeurs des pixels + //juste avec les derivees aux extremites a calculer ici + + if ((tis < 2)||(tis > nb_pix - 3)||(tis == nb_pix/2)) + { + liste_pix[idx].x = p.x ; + liste_pix[idx].y = p.y ; + } + + } + } + __syncthreads(); + + //calcul contribs individuelles des pixels + + if ( (tis >0) && (tis < nb_pix-1) + && ( (abs_dy <= abs_dx) + && ( (xprec > p.x) || (xsuiv > p.x)) + || (abs_dy > abs_dx) ) ) + { + int pos = p.x * l + p.y ; + scumuls_1[ CFI(tib)] = 1+p.y; + scumuls_x[ CFI(tib)] = cumul_x[ pos ] ; + scumuls_x2[CFI(tib)] = cumul_x2[ pos ]; + } else { + scumuls_1[ CFI(tib)] = 0; + scumuls_x[ CFI(tib)] = 0; + scumuls_x2[CFI(tib)] = 0; + } + + __syncthreads(); + //somme des contribs individuelles + // unroll des sommes partielles en smem + + if (blockSize >= 512) { + if (tib < 256) { + scumuls_1[ CFI(tib)] += scumuls_1[ CFI(tib + 256) ]; + scumuls_x[ CFI(tib)] += scumuls_x[ CFI(tib + 256) ]; + scumuls_x2[CFI(tib)] += scumuls_x2[CFI(tib + 256) ]; + } + __syncthreads(); + } + + if (blockSize >= 256) { + if (tib < 128) { + scumuls_1[ CFI(tib)] += scumuls_1[ CFI(tib + 128) ]; + scumuls_x[ CFI(tib)] += scumuls_x[ CFI(tib + 128) ]; + scumuls_x2[CFI(tib)] += scumuls_x2[CFI(tib + 128) ]; + } + __syncthreads(); + } + if (blockSize >= 128) { + if (tib < 64) { + scumuls_1[ CFI(tib)] += scumuls_1[ CFI(tib + 64) ]; + scumuls_x[ CFI(tib)] += scumuls_x[ CFI(tib + 64) ]; + scumuls_x2[CFI(tib)] += scumuls_x2[CFI(tib + 64) ]; + } + __syncthreads(); + } + + //32 threads <==> 1 warp + if (tib < 32) + { + { + scumuls_1[ CFI(tib)] += scumuls_1[ CFI(tib + 32) ]; + scumuls_x[ CFI(tib)] += scumuls_x[ CFI(tib + 32) ]; + scumuls_x2[CFI(tib)] += scumuls_x2[CFI(tib + 32) ]; + } + { + scumuls_1[ CFI(tib)] += scumuls_1[ CFI(tib + 16) ]; + scumuls_x[ CFI(tib)] += scumuls_x[ CFI(tib + 16) ]; + scumuls_x2[CFI(tib)] += scumuls_x2[CFI(tib + 16) ]; + } + { + scumuls_1[ CFI(tib)] += scumuls_1[ CFI(tib + 8) ]; + scumuls_x[ CFI(tib)] += scumuls_x[ CFI(tib + 8) ]; + scumuls_x2[CFI(tib)] += scumuls_x2[CFI(tib + 8) ]; + } + scumuls_1[ CFI(tib)] += scumuls_1[ CFI(tib + 4) ]; + scumuls_x[ CFI(tib)] += scumuls_x[ CFI(tib + 4) ]; + scumuls_x2[CFI(tib)] += scumuls_x2[CFI(tib + 4) ]; + + scumuls_1[ CFI(tib)] += scumuls_1[ CFI(tib + 2) ]; + scumuls_x[ CFI(tib)] += scumuls_x[ CFI(tib + 2) ]; + scumuls_x2[CFI(tib)] += scumuls_x2[CFI(tib + 2) ]; + + scumuls_1[ CFI(tib)] += scumuls_1[ CFI(tib + 1) ]; + scumuls_x[ CFI(tib)] += scumuls_x[ CFI(tib + 1) ]; + scumuls_x2[CFI(tib)] += scumuls_x2[CFI(tib + 1) ]; + } + + // resultat sommes partielles en gmem + if (tib == 0) { + gsombloc[ blockIdx.x ] = (t_sum_x2) scumuls_1[0]; + gsombloc[ blockIdx.x + gridDim.x ] = (t_sum_x2) scumuls_x[0]; + gsombloc[ blockIdx.x + 2*gridDim.x ] = (t_sum_x2) scumuls_x2[0]; + } + + //calculs freemans, centre et code segment + //1 uint4 par segment + + int Di, Dj; + if (tis == 0){ + Di = 1 + liste_pix[idx+1].x - liste_pix[idx].x ; + Dj = 1 + liste_pix[idx+1].y - liste_pix[idx].y ; + d_snake[segment].freeman_out = d_table_freeman[3*Di + Dj] ; + //code seg + if (dy > 0 ) d_snake[segment].code_segment = -1 ; + if (dy < 0 ) d_snake[segment].code_segment = 1 ; + if (dy == 0) d_snake[segment].code_segment = 0 ; + } + + if (tis == nb_pix-1){ + Di = 1 + liste_pix[idx].x - liste_pix[idx-1].x ; + Dj = 1 + liste_pix[idx].y - liste_pix[idx-1].y; + d_snake[segment].freeman_in = d_table_freeman[3*Di + Dj] ; + } + + if (tis == (nb_pix/2)){ + d_snake[segment].centre_i = liste_pix[idx].x ; + d_snake[segment].centre_j = liste_pix[idx].y ; + } +} + +/* + sommme des contribs par bloc -> contribs segment, pour le snake + + execution sur : 1bloc / 1 thread par segment + */ + +__global__ void somsom_snake(t_sum_x2 * somblocs, int nb_nodes, unsigned int nb_bl_seg, snake_node_gpu * d_snake){ + + t_sum_x2 sdata[3]; + unsigned int seg = blockIdx.x ; + + //un thread par segment + { + sdata[0] = 0; + sdata[1] = 0; + sdata[2] = 0; + } + + for (int b=0; b < nb_bl_seg ; b++){ + sdata[0] += somblocs[seg*nb_bl_seg + b]; + sdata[1] += somblocs[(seg + nb_nodes)*nb_bl_seg + b]; + sdata[2] += somblocs[(seg + 2*nb_nodes)*nb_bl_seg + b]; + } + + //totaux en gmem + { + d_snake[seg].sum_1 = sdata[0]; + d_snake[seg].sum_x = sdata[1]; + d_snake[seg].sum_x2 = sdata[2]; + } +} + +__device__ double codage_gl_gauss(uint64 stat_sum_1, uint64 stat_sum_x, uint64 stat_sum_x2, + uint64 n_dim, uint64 SUM_X, uint64 SUM_X2){ + uint64 stat_sum_xe ; /* somme des xn region exterieure */ + uint32 ne ; /* nombre de pixel region exterieure */ + double sigi2, sige2; /* variance region interieure et exterieure */ + + /* variance des valeurs des niveaux de gris a l'interieur du snake */ + sigi2 = + ((double)stat_sum_x2/(double)stat_sum_1) - + ((double)stat_sum_x/(uint64)stat_sum_1)*((double)stat_sum_x/(uint64)stat_sum_1) ; + + /* variance des valeurs des niveaux de gris a l'exterieur du snake */ + ne = n_dim-stat_sum_1 ; + stat_sum_xe = SUM_X - stat_sum_x ; + sige2 = + ((double)SUM_X2-stat_sum_x2)/(double)ne - + ((double)stat_sum_xe/(uint64)ne)*((double)stat_sum_xe/(uint64)ne) ; + + if ((sigi2 > 0)|(sige2 > 0)) + return 0.5*((double)stat_sum_1*log(sigi2) + (double)ne*log(sige2)) ; + return -1 ; +} + + +__global__ void calcul_stats_snake(snake_node_gpu * d_snake, int nnodes, int64 * d_stats_snake, double * vrais_min, + t_cumul_x * cumul_x, t_cumul_x2 * cumul_x2, int * TABLE_CODAGE, uint32 l + ) +{ + + int id_nx, id_nprec, id_nprecprec ; + int code_noeud, code_segment, pos ; + __shared__ int64 s_stats_snake[3] ; + + //init stats en shared mem + s_stats_snake[0] = 0 ; + s_stats_snake[1] = 0 ; + s_stats_snake[2] = 0 ; + + + for (id_nx = 0; id_nx < nnodes; id_nx++) + { + if (id_nx == 0) id_nprec = nnodes - 1; + else id_nprec = id_nx - 1; + if (id_nprec == 0) id_nprecprec = nnodes -1 ; + else id_nprecprec = id_nprec - 1 ; + /* gestion des segments partant du noeud */ + /* vers le noeud suivant dans l'ordre trigo */ + code_segment = d_snake[id_nprec].code_segment ; + if (code_segment > 0) + { + /* on somme les contributions */ + s_stats_snake[0] += d_snake[id_nprec].sum_1 ; + s_stats_snake[1] += d_snake[id_nprec].sum_x ; + s_stats_snake[2] += d_snake[id_nprec].sum_x2 ; + } + else if (code_segment < 0) + { + /* on soustrait les contributions */ + s_stats_snake[0] -= d_snake[id_nprec].sum_1 ; + s_stats_snake[1] -= d_snake[id_nprec].sum_x ; + s_stats_snake[2] -= d_snake[id_nprec].sum_x2 ; + } + // else (code_segment == 0), on ne fait rien + /* gestion des pixels connectant les segments */ + /* pixel de depart du segment actuel np --> np->noeud_suiv */ + /* freeman_out = np->freeman_out ; */ + /* freeman_in = np->noeud_prec->freeman_in ; */ + pos = d_snake[id_nprecprec].freeman_in*8 + d_snake[id_nprec].freeman_out ; + code_noeud = TABLE_CODAGE[pos] ; + pos = d_snake[id_nprec].posi*l + d_snake[id_nprec].posj ; + + if (code_noeud > 0) + { + /* on somme les contributions */ + s_stats_snake[0] += 1 + d_snake[id_nprec].posj ; + s_stats_snake[1] += cumul_x[pos] ; + s_stats_snake[2] += cumul_x2[pos] ; + } + else if (code_noeud < 0) + { + /* on soustrait les contributions */ + s_stats_snake[0] -= 1 + d_snake[id_nprec].posj ; + s_stats_snake[1] -= cumul_x[pos] ; + s_stats_snake[2] -= cumul_x2[pos] ; + } + // else (code_pixel == 0), on ne fait rien + } + d_stats_snake[0] = s_stats_snake[0] ; + d_stats_snake[1] = s_stats_snake[1] ; + d_stats_snake[2] = s_stats_snake[2] ; + + *vrais_min = codage_gl_gauss(s_stats_snake[0], s_stats_snake[1], s_stats_snake[2], + d_stats_snake[3], d_stats_snake[4], d_stats_snake[5]); +} diff --git a/src/lib_kernels_contribs.cu b/src/lib_kernels_contribs.cu new file mode 100644 index 0000000..2440f0c --- /dev/null +++ b/src/lib_kernels_contribs.cu @@ -0,0 +1,1043 @@ +#include "constantes.h" + +/* + * determine et retourne le nb de pixels composant le segment (i,j)-(i1,j1) + * + */ +__device__ int calcul_nb_pixels(int i, int j, int i1, int j1){ + int absi, absj,nbpix =0; + //MAX( ABS(i1-i) , ABS(j1-j)) + 1 + if (i1 > i) absi = i1 - i ; else absi = i - i1 ; + if (j1 > j) absj = j1 - j ; else absj = j - j1 ; + if (absi > absj ) nbpix = absi+1 ; else nbpix = absj+1 ; + return nbpix ; +} + +/* + construit la liste des coordonnées des 8 positions a tester pour l'ensemble des N noeuds du snake + ainsi que le liste des nombres de pixels correspondant (en z, seg avant, en w seg apres) + a executer avec N blocs de 8 threads +*/ +__global__ void liste_positions_a_tester(snake_node_gpu * d_snake, uint4 * liste_positions, uint32 * nb_pix_max, int pas, int nb_nodes, int h, int l){ + int tib = threadIdx.x; // une position par thread + int node = blockIdx.x; // 1 noeud par bloc de threads + int node_prec, node_suiv ; // indices des nodes + int i, j, i1, j1, i2, j2, i3, j3, npix_prec, npix_suiv ; // coordonnees des noeuds , nb de pixels + + //lecture des coordonnees + node_prec = (node == 0)? (nb_nodes-1) : (node - 1) ; + node_suiv = (node == nb_nodes-1)? (0) : (node + 1) ; + i1 = d_snake[node_prec].posi ; + j1 = d_snake[node_prec].posj ; + i2 = d_snake[node].posi ; + j2 = d_snake[node].posj ; + i3 = d_snake[node_suiv].posi ; + j3 = d_snake[node_suiv].posj ; + + switch(tib){ // on considere un voisinage a 8 points + case 0: + i = i2 ; + if ((j2 + pas) < l) j = j2 + pas ; else j = l-2 ; + break; + case 1: + if ((j2 + pas) < l) j = j2 + pas ; else j = l-2 ; + if (i2 > pas ) i = i2 - pas ; else i = 1 ; + break; + case 2: + if (i2 > pas ) i = i2 - pas ; else i = 1 ; + j = j2 ; + break; + case 3: + if (i2 > pas) i = i2 - pas ; else i = 1 ; + if (j2 > pas) j = j2 - pas ; else j = 1 ; + break; + case 4: + i = i2 ; + if (j2 > pas) j = j2 - pas ; else j = 1 ; + break; + case 5: + if ((i2 + pas) < h) i = i2 + pas ; else i = h-2 ; + if (j2 > pas) j = j2 - pas ; else j = 1 ; + break; + case 6: + if ((i2 + pas) < h) i = i2 + pas ; else i = h-2 ; + j = j2 ; + break; + case 7: + if ((i2 + pas) < h) i = i2 + pas ; else i = h-2 ; + if ((j2 + pas) < l) j = j2 + pas ; else j = l-2 ; + break; + } + + //calcul des nombres de pixels dans chaque cas + npix_prec = calcul_nb_pixels(i,j,i1,j1) ; + npix_suiv = calcul_nb_pixels(i,j,i3,j3) ; + + liste_positions[8*node + tib] = make_uint4(i,j, (uint)npix_prec, (uint)npix_suiv ); + + // calcule du maximum global du nb de pixels + if ((node == 0) && (tib == 0)) + { + *nb_pix_max = 0 ; + for (int n=0; n *nb_pix_max) *nb_pix_max = liste_positions[n].z ; + if (liste_positions[n].w > *nb_pix_max) *nb_pix_max = liste_positions[n].w ; + } + } +} + +/* + * calcule : + * - les coordonnees de chaque pixel de chaque segment a evaluer pour les 8 voisins de chaque noeud (pair ou impair) + * cela represente 16 segments par noeud pair/impair + * - les contributions de chacun de ces pixels + * - les sommes, par blocs, des contributions des pixels (les sommes totales sont faites par le kernel somsom) + * - le code de chaque segment envisage + */ + +__global__ void calcul_contribs_segments_blocs_full(snake_node_gpu * d_snake, int nb_nodes, uint4 * liste_points, uint32 npix_max, + t_cumul_x * cumul_x, t_cumul_x2 * cumul_x2, int * d_codes_x16, + int l, uint2 * liste_pix, uint64 * gsombloc, bool pairs) +{ + // indices des elements + int blockSize = blockDim.x ; // nb threads par bloc + int tib = threadIdx.x ; // position du thread dans le bloc + int nblocs_noeud = gridDim.x / (nb_nodes/2 + pairs*(nb_nodes%2)) ; // nb de blocs dédié à chaque noeud + int nblocs_seg = nblocs_noeud / 16 ; // nb de blocs dédiés à un segment de test + int idx = blockDim.x*blockIdx.x + threadIdx.x ; // position absolue du thread ds la grille + int id_interval = blockIdx.x / nblocs_noeud ; // indice de l'intervalle du noeud dans la grille + int segment = ( blockIdx.x - id_interval*nblocs_noeud )/nblocs_seg ; // indice du segment de 0 à 15 + int tis = idx - ( id_interval*nblocs_noeud + segment*nblocs_seg )*blockDim.x ; // position du thread ds le segment + int id_base_seg = 16*id_interval + segment ; // indice du segment courant + int id_base_pix = 5*id_base_seg ; // indice du pixel 0/5 du segment courant dans la liste_pix pour le calcul des freemans + + //tab pour contribs pixels + extern __shared__ tcontribs scumuls[]; + + //coordonnees des extremites de segment + uint x1, y1, x2, y2 ; + //indices des noeuds precedent(n1), courant(n2), suivant(n3) + int n1, n2, n3 ; + // pixel courant + uint2 p ; + // nb de pixels du segment precedent, suivant + int xprec, xsuiv ; + + // determine les indices des noeuds prec, courant, suiv + if (pairs) + { + n1 = 2*id_interval -1 ; + n2 = 2*id_interval ; + n3 = 2*id_interval +1 ; + } + else + { + n1 = 2*id_interval ; + n2 = 2*id_interval +1 ; + n3 = 2*id_interval +2 ; + } + //gestion du bouclage du snake + if (n1 < 0) n1 = nb_nodes-1 ; + if (n3 >= nb_nodes) n3 = 0 ; + + + //affectation des differentes positions aux différents segments 'blocs de threads' + if ( segment < 8 ){ + x1 = d_snake[n1].posj ; + y1 = d_snake[n1].posi ; + x2 = liste_points[8*n2 + segment].y ; + y2 = liste_points[8*n2 + segment].x ; + } else { + x1 = liste_points[8*n2 + segment-8].y ; + y1 = liste_points[8*n2 + segment-8].x ; + x2 = d_snake[n3].posj ; + y2 = d_snake[n3].posi ; + } + + //params des deplacements + int dx=x2-x1; + int dy=y2-y1; + uint abs_dx = ABS(dx); + uint abs_dy = ABS(dy); + uint nb_pix = abs_dy>abs_dx?(abs_dy+1):(abs_dx+1); + int incx=0, incy=0; + + + //calcul liste des pixels du segment (x1,y1)-(x2,y2) + if (dy > 0) incy=1; else incy=-1 ; + if (dx > 0) incx=1; else incx=-1 ; + + if (tis < nb_pix){ + if (abs_dy > abs_dx){ + //1 thread par ligne pente 1/k + double k = (double)dx/dy ; + //coordonnees pixel + p.x = y1 + incy*tis ; + p.y = x1 + floor((double)incy*k*tis+0.5) ; + } else { + //1 thread par colonne pente k + double k=(double)dy/dx ; + //coordonnees pixel + p.x = y1 + floor((double)(incx*k*tis)+0.5) ; + p.y = x1 + incx*tis ; + // ordonnees des pixels suivant & precedent + if ( tis > 0 ){ + xsuiv = y1 + floor((double)(incx*k*(tis+1))+0.5) ; + xprec = y1 + floor((double)(incx*k*(tis-1))+0.5) ; + } + } + // memorisation des valeurs necessaires au calcul des freemans et des centres + if (tis == 0) liste_pix[id_base_pix] = make_uint2(p.x, p.y) ; + if (tis == 1) liste_pix[id_base_pix +1] = make_uint2(p.x,p.y) ; + if (tis == nb_pix/2) liste_pix[id_base_pix +2] = make_uint2(p.x,p.y) ; + if (tis == nb_pix-2) liste_pix[id_base_pix +3] = make_uint2(p.x,p.y) ; + if (tis == nb_pix-1) liste_pix[id_base_pix +4] = make_uint2(p.x,p.y) ; + } + + __syncthreads(); + // calcul contribs individuelles des pixels + // dans le cas des segments 'plutot horizontaux', on ne garde qu'une contrib par ligne ; celle du pixel le plus a l'interieur du snake + if ( (tis >0) && (tis < nb_pix-1) + && ( ((abs_dy <= abs_dx) && ( ( xprec > p.x) || ( xsuiv > p.x))) + || (abs_dy > abs_dx) ) ) + { + int pos = p.x * l + p.y ; + scumuls[ CFI(tib)].c1 = 1 + p.y ; + scumuls[ CFI(tib)].cx = cumul_x[ pos ] ; + scumuls[CFI(tib)].cx2 = cumul_x2[ pos ]; + } else { + scumuls[ CFI(tib)].c1 = 0; + scumuls[ CFI(tib)].cx = 0; + scumuls[ CFI(tib)].cx2 = 0; + } + + __syncthreads(); + // somme des contribs individuelles + // unroll des sommes partielles en shared memory + if (blockSize >= 512) { + if (tib < 256) { + scumuls[ CFI(tib)].c1 += scumuls[ CFI(tib + 256) ].c1; + scumuls[ CFI(tib)].cx += scumuls[ CFI(tib + 256) ].cx; + scumuls[ CFI(tib)].cx2 += scumuls[CFI(tib + 256) ].cx2; + } + __syncthreads(); + } + + if (blockSize >= 256) { + if (tib < 128) { + scumuls[ CFI(tib)].c1 += scumuls[ CFI(tib + 128) ].c1; + scumuls[ CFI(tib)].cx += scumuls[ CFI(tib + 128) ].cx; + scumuls[ CFI(tib)].cx2 += scumuls[CFI(tib + 128) ].cx2; + } + __syncthreads(); + } + if (blockSize >= 128) { + if (tib < 64) { + scumuls[ CFI(tib)].c1 += scumuls[ CFI(tib + 64) ].c1; + scumuls[ CFI(tib)].cx += scumuls[ CFI(tib + 64) ].cx; + scumuls[CFI(tib)].cx2 += scumuls[CFI(tib + 64) ].cx2; + } + __syncthreads(); + } + + //32 threads <==> 1 warp + volatile tcontribs * scontribs = scumuls ; + if (tib < 32){ + { + scontribs[ CFI(tib)].c1 += scontribs[ CFI(tib + 32) ].c1; + scontribs[ CFI(tib)].cx += scontribs[ CFI(tib + 32) ].cx; + scontribs[CFI(tib)].cx2 += scontribs[CFI(tib + 32) ].cx2; + } + if (tib < 16) + { + scontribs[ CFI(tib)].c1 += scontribs[ CFI(tib + 16) ].c1; + scontribs[ CFI(tib)].cx += scontribs[ CFI(tib + 16) ].cx; + scontribs[CFI(tib)].cx2 += scontribs[CFI(tib + 16) ].cx2; + } + if (tib < 8) + { + scontribs[ CFI(tib)].c1 += scontribs[ CFI(tib + 8) ].c1; + scontribs[ CFI(tib)].cx += scontribs[ CFI(tib + 8) ].cx; + scontribs[CFI(tib)].cx2 += scontribs[CFI(tib + 8) ].cx2; + } + if (tib < 4) + { + scontribs[ CFI(tib)].c1 += scontribs[ CFI(tib + 4) ].c1; + scontribs[ CFI(tib)].cx += scontribs[ CFI(tib + 4) ].cx; + scontribs[ CFI(tib)].cx2 +=scontribs[ CFI(tib + 4) ].cx2; + } + if (tib < 2) + { + scontribs[ CFI(tib)].c1 += scontribs[ CFI(tib + 2) ].c1; + scontribs[ CFI(tib)].cx += scontribs[ CFI(tib + 2) ].cx; + scontribs[CFI(tib)].cx2 += scontribs[CFI(tib + 2) ].cx2; + } + if (tib == 0) + { + scontribs[ CFI(tib)].c1 += scontribs[ CFI(tib + 1) ].c1; + scontribs[ CFI(tib)].cx += scontribs[ CFI(tib + 1) ].cx; + scontribs[CFI(tib)].cx2 += scontribs[CFI(tib + 1) ].cx2; + + // resultat sommes partielles en gmem + //if (tib == 0) { + gsombloc[ blockIdx.x ] = scontribs[0].c1 ; + gsombloc[ blockIdx.x + gridDim.x ] = scontribs[0].cx ; + gsombloc[ blockIdx.x + 2*gridDim.x ] = scontribs[0].cx2 ; + + //code seg + if (dy > 0 ) d_codes_x16[id_base_seg] = -1 ; + if (dy < 0 ) d_codes_x16[id_base_seg] = 1 ; + if (dy == 0) d_codes_x16[id_base_seg]= 0 ; + } + } +} + +/* + calcul des freeman et du centre de chaque segment de test + a executer sur 'n_interval' blocs de 16 threads + soit un thread par segment +*/ +__global__ void calcul_freemans_centre(uint2 * liste_pix, int * d_table_freeman, uint4 * d_freemans_x16){ + + int id_segment = threadIdx.x ; + int id_freeman = ( blockDim.x*blockIdx.x + id_segment ) ; + int id_base_pix = 5*id_freeman ; + + //calculs freemans, centre et code segment + //1 uint4 par segment + int Dio, Djo, Dii, Dji; + + //freeman out + Dio = 1 + liste_pix[id_base_pix +1].x - liste_pix[id_base_pix].x ; + Djo = 1 + liste_pix[id_base_pix +1].y - liste_pix[id_base_pix].y ; + d_freemans_x16[id_freeman].z = d_table_freeman[3*Dio + Djo] ; + + + //freeman_in + Dii = 1 + liste_pix[id_base_pix +4].x - liste_pix[id_base_pix +3].x ; + Dji = 1 + liste_pix[id_base_pix +4].y - liste_pix[id_base_pix +3].y ; + d_freemans_x16[id_freeman].w = d_table_freeman[3*Dii + Dji] ; + + //centre + d_freemans_x16[id_freeman].x = liste_pix[id_base_pix +2].x ; + d_freemans_x16[id_freeman].y = liste_pix[id_base_pix +2].y ; + +} + + +/* + calcul des contribs 1, x et x2 des 16 segments + autour du noeud + a partir des sommes partielles des blocs + 1 bloc / 1 thread par segment +*/ + +__global__ void somsom_full(uint64 * somblocs, int nb_nodes, unsigned int nb_bl_seg, uint64 * somsom){ + + uint64 sdata[3]; + unsigned int seg = blockIdx.x ; + unsigned int nb_seg = gridDim.x ; + + //un thread par segment + { + sdata[0] = 0; + sdata[1] = 0; + sdata[2] = 0; + } + + for (int b=0; b < nb_bl_seg ; b++){ //voir atomicadd 64bits + sdata[0] += somblocs[seg*nb_bl_seg + b]; + sdata[1] += somblocs[(seg + nb_seg)*nb_bl_seg + b]; + sdata[2] += somblocs[(seg + 2*nb_seg)*nb_bl_seg + b]; + } + + //totaux en gmem + { + somsom[3*seg] = sdata[0]; + somsom[3*seg + 1] = sdata[1]; + somsom[3*seg + 2] = sdata[2]; + } +} + +/* + version GPU de la fonction definie ds src/lib_math.c +*/ +__device__ bool test_inf_gpu(double arg1, double arg2){ + if (arg2 > 0) + return (arg1 < (arg2*COEF_DECROI)) ; + else + return (arg1 < (arg2*INV_COEF_DECROI)) ; +} + +/* + version GPU de la fonction codage_niveau_gris_hyp_gaussienne + */ +__device__ double codage_gl_hyp_gauss(uint64 stat_sum_1, uint64 stat_sum_x, uint64 stat_sum_x2, + uint64 n_dim, uint64 SUM_X, uint64 SUM_X2){ + uint64 stat_sum_xe ; /* somme des xn region exterieure */ + uint32 ne ; /* nombre de pixel region exterieure */ + double sigi2, sige2; /* variance region interieure et exterieure */ + + /* variance des valeurs des niveaux de gris a l'interieur du snake */ + sigi2 = + (double)stat_sum_x2/(double)stat_sum_1 - + ((double)stat_sum_x/stat_sum_1)*((double)stat_sum_x/stat_sum_1) ; + + /* variance des valeurs des niveaux de gris a l'exterieur du snake */ + ne = n_dim-stat_sum_1 ; + stat_sum_xe = SUM_X - stat_sum_x ; + sige2 = + ((double)SUM_X2-stat_sum_x2)/ne - + ((double)stat_sum_xe/ne)*((double)stat_sum_xe/ne) ; + + if ((sigi2 > 0)&&(sige2 > 0)) + return 0.5*((double)stat_sum_1*log(sigi2) + (double)ne*log(sige2)) ; + return -1 ; +} + +/* + soustrait, pour chaque intervalle [N1--Nx--N2] + les contributions des segments N1--Nx et Nx--N2 + + A executer par nnodes blocs de 1 thread par intervalle + */ + +__global__ void soustrait_aux_stats_2N_segments_noeud(snake_node_gpu * d_snake, int64 * d_stats_snake, int64 * d_stats_ref, + t_cumul_x * cumul_x, t_cumul_x2 * cumul_x2, + int * TABLE_CODAGE, uint32 l + ) +{ + int nnodes = gridDim.x ; + int id_nx, id_nprec, id_nprecprec, id_nsuiv ; + int code_noeud, pos; + __shared__ int64 s_stats_snake[3] ; + + id_nx = blockIdx.x ; + if (id_nx == 0) id_nprec = nnodes - 1; + else id_nprec = id_nx - 1; + if (id_nprec == 0) id_nprecprec = nnodes -1 ; + else id_nprecprec = id_nprec - 1 ; + if (id_nx == nnodes-1) id_nsuiv = 0; + else id_nsuiv = id_nx + 1 ; + + //init avec les valeurs du contour actuel + s_stats_snake[0] = d_stats_snake[0] ; + s_stats_snake[1] = d_stats_snake[1] ; + s_stats_snake[2] = d_stats_snake[2] ; + + /* segment Na -- Nx */ + if (d_snake[id_nprec].code_segment > 0) + { + s_stats_snake[0] -= d_snake[id_nprec].sum_1 ; + s_stats_snake[1] -= d_snake[id_nprec].sum_x ; + s_stats_snake[2] -= d_snake[id_nprec].sum_x2 ; + } + else if (d_snake[id_nprec].code_segment < 0) + { + s_stats_snake[0] += d_snake[id_nprec].sum_1 ; + s_stats_snake[1] += d_snake[id_nprec].sum_x ; + s_stats_snake[2] += d_snake[id_nprec].sum_x2 ; + } + // else (code_segment_NaNx == 0), on ne fait rien + + /* gestion des pixels connectant les segments */ + /* pixel de depart du segment Na --> Nx */ + pos = d_snake[id_nprecprec].freeman_in*8 + d_snake[id_nprec].freeman_out ; + code_noeud = TABLE_CODAGE[pos] ; + pos = d_snake[id_nprec].posi*l + d_snake[id_nprec].posj ; + if (code_noeud > 0) + { + s_stats_snake[0] -= 1 + d_snake[id_nprec].posj ; + s_stats_snake[1] -= cumul_x[pos] ; + s_stats_snake[2] -= cumul_x2[pos]; + } + else if (code_noeud < 0) + { + s_stats_snake[0] += 1 + d_snake[id_nprec].posj ; + s_stats_snake[1] += cumul_x[pos] ; + s_stats_snake[2] += cumul_x2[pos]; + } + // else (code_noeud == 0), on ne fait rien + + /* -------------------------- */ + /* -------------------------- */ + /* segment Nx -- Nb */ + if ( d_snake[id_nx].code_segment > 0 ) + { + // on soustrait la contribution + s_stats_snake[0] -= d_snake[id_nx].sum_1 ; + s_stats_snake[1] -= d_snake[id_nx].sum_x ; + s_stats_snake[2] -= d_snake[id_nx].sum_x2 ; + } + else if ( d_snake[id_nx].code_segment < 0) + { + s_stats_snake[0] += d_snake[id_nx].sum_1 ; + s_stats_snake[1] += d_snake[id_nx].sum_x ; + s_stats_snake[2] += d_snake[id_nx].sum_x2 ; + } + // else (code_segment_NxNb == 0), on ne fait rien + + /* gestion des pixels connectant les segments */ + /* pixel de depart du segment Nx --> Nb */ + pos = d_snake[id_nprec].freeman_in*8 + d_snake[id_nx].freeman_out ; + code_noeud = TABLE_CODAGE[pos] ; + pos = d_snake[id_nx].posi*l + d_snake[id_nx].posj ; + if (code_noeud > 0) + { + s_stats_snake[0] -= 1 + d_snake[id_nx].posj ; + s_stats_snake[1] -= cumul_x[pos] ; + s_stats_snake[2] -= cumul_x2[pos]; + } + else if (code_noeud < 0) + { + s_stats_snake[0] += 1 + d_snake[id_nx].posj ; + s_stats_snake[1] += cumul_x[pos] ; + s_stats_snake[2] += cumul_x2[pos]; + } + // else (code_noeud == 0), on ne fait rien + + /* pixel d'arrivee du segment Nx --> Nb */ + pos = d_snake[id_nx].freeman_in*8 + d_snake[id_nsuiv].freeman_out ; + code_noeud = TABLE_CODAGE[pos] ; + pos = d_snake[id_nsuiv].posi*l + d_snake[id_nsuiv].posj ; + if (code_noeud > 0) + { + s_stats_snake[0] -= 1 + d_snake[id_nsuiv].posj ; + s_stats_snake[1] -= cumul_x[pos] ; + s_stats_snake[2] -= cumul_x2[pos]; + } + else if (code_noeud < 0) + { + s_stats_snake[0] += 1 + d_snake[id_nsuiv].posj ; + s_stats_snake[1] += cumul_x[pos] ; + s_stats_snake[2] += cumul_x2[pos]; + } + // else (code_noeud == 0), on ne fait rien + __syncthreads(); + + d_stats_ref[3*id_nx] = s_stats_snake[0] ; + d_stats_ref[3*id_nx + 1] = s_stats_snake[1] ; + d_stats_ref[3*id_nx + 2] = s_stats_snake[2] ; + +} + + +/* + calcul des stats associees a chaque position de test + + EXEC : sur n_interval blocs de 8 threads +*/ +__global__ void calcul_stats_full(snake_node_gpu * d_snake, int nnodes, bool pairs, int64 * d_stats_snake, + int64 * d_stats_ref, int64 * d_stats, uint64 * d_contribs, + uint4 * d_liste_points, int * code_segment, uint4 * d_freemans, + int * d_table_codes, t_cumul_x * cumul_x, t_cumul_x2 * cumul_x2, + uint32 h, uint32 l, double * vrais, double * vrais_min, bool * move){ + + int interval = blockIdx.x ; + int seg = threadIdx.x ; + int thread = seg; + int id_nx, id_nprec, id_nprecprec, id_nsuiv, id_seg ; + int code_noeud; + __shared__ int64 s_stats_snake[3*8] ; + + id_nx = 2*interval + !pairs ; + if (id_nx == 0) id_nprec = nnodes - 1 ; + else id_nprec = id_nx - 1 ; + if (id_nprec == 0) id_nprecprec = nnodes -1 ; + else id_nprecprec = id_nprec - 1 ; + if (id_nx == nnodes-1) id_nsuiv = 0 ; + else id_nsuiv = id_nx + 1 ; + + //chargement en smem , prevoir CFI car on a 24x64bits par blocs => conflits + s_stats_snake[3*thread + 0] = d_stats_ref[3*id_nx] ; + s_stats_snake[3*thread + 1] = d_stats_ref[3*id_nx + 1] ; + s_stats_snake[3*thread + 2] = d_stats_ref[3*id_nx + 2] ; + + + //stats segments N1-Nx + id_seg = 16*interval + seg ; + if ( code_segment[id_seg] > 0 ){ + s_stats_snake[3*thread +0] += d_contribs[3*id_seg] ; + s_stats_snake[3*thread +1] += d_contribs[3*id_seg + 1 ] ; + s_stats_snake[3*thread +2] += d_contribs[3*id_seg + 2 ] ; + } else if ( code_segment[16*interval + seg] < 0 ) { + s_stats_snake[3*thread +0] -= d_contribs[3*id_seg] ; + s_stats_snake[3*thread +1] -= d_contribs[3*id_seg + 1] ; + s_stats_snake[3*thread +2] -= d_contribs[3*id_seg + 2] ; + } + + //stats noeud N1(i1,j1) + int fo_N1 = d_freemans[id_seg].z ; + int fi_Nprecprec = d_snake[id_nprecprec].freeman_in ; + int pos = d_snake[id_nprec].posi*l + d_snake[id_nprec].posj ; + + code_noeud = d_table_codes[fi_Nprecprec*8 + fo_N1]; + if (code_noeud > 0){ + s_stats_snake[3*thread +0] += 1 + d_snake[id_nprec].posj ; + s_stats_snake[3*thread +1] += cumul_x[ pos ] ; + s_stats_snake[3*thread +2] += cumul_x2[pos ] ; + } else if (code_noeud < 0){ + s_stats_snake[3*thread +0] -= 1 + d_snake[id_nprec].posj ; + s_stats_snake[3*thread +1] -= cumul_x[ pos ] ; + s_stats_snake[3*thread +2] -= cumul_x2[pos ] ; + } + + //stats noeud Nx + int fo_Nx = d_freemans[id_seg + 8].z ; + int fi_Nx = d_freemans[id_seg].w ; + int Nxi = d_liste_points[8*id_nx + seg].x ; + int Nxj = d_liste_points[8*id_nx + seg].y ; + pos = Nxi*l + Nxj ; + + code_noeud = d_table_codes[fi_Nx*8 + fo_Nx]; + if (code_noeud > 0){ + s_stats_snake[3*thread +0] += 1 + Nxj ; + s_stats_snake[3*thread +1] += cumul_x[ pos ] ; + s_stats_snake[3*thread +2] += cumul_x2[pos ] ; + } + if (code_noeud < 0){ + s_stats_snake[3*thread +0] -= 1 + Nxj ; + s_stats_snake[3*thread +1] -= cumul_x[ pos ] ; + s_stats_snake[3*thread +2] -= cumul_x2[pos ] ; + } + + //stats segments Nx-N2 + seg += 8; + id_seg = 16*interval + seg ; + if ( code_segment[id_seg] > 0 ){ + s_stats_snake[3*thread +0] += d_contribs[3*id_seg] ; + s_stats_snake[3*thread +1] += d_contribs[3*id_seg + 1] ; + s_stats_snake[3*thread +2] += d_contribs[3*id_seg + 2] ; + } + if ( code_segment[id_seg] < 0 ) { + s_stats_snake[3*thread +0] -= d_contribs[3*id_seg] ; + s_stats_snake[3*thread +1] -= d_contribs[3*id_seg + 1] ; + s_stats_snake[3*thread +2] -= d_contribs[3*id_seg + 2] ; + } + + //stats noeud N2(i2,j2) + int fi_N2 = d_freemans[id_seg].w ; + int fo_N2 = d_snake[id_nsuiv].freeman_out ; + pos = d_snake[id_nsuiv].posi*l + d_snake[id_nsuiv].posj ; + + code_noeud = d_table_codes[fi_N2*8 + fo_N2]; + if (code_noeud > 0){ + s_stats_snake[3*thread +0] += 1 + d_snake[id_nsuiv].posj ; + s_stats_snake[3*thread +1] += cumul_x[ pos ] ; + s_stats_snake[3*thread +2] += cumul_x2[pos ] ; + } + if (code_noeud < 0){ + s_stats_snake[3*thread +0] -= 1 + d_snake[id_nsuiv].posj ; + s_stats_snake[3*thread +1] -= cumul_x[ pos ] ; + s_stats_snake[3*thread +2] -= cumul_x2[pos ] ; + } + + //TODO + //voir si on peut s'en passer + d_stats[3*(8*interval + thread)] = s_stats_snake[3*thread +0]; + d_stats[3*(8*interval + thread) + 1] = s_stats_snake[3*thread +1]; + d_stats[3*(8*interval + thread) + 2] = s_stats_snake[3*thread +2]; + + //codage hyp gaussienne + uint64 stat_sum_xe[8] ; //somme des xn region exterieure + uint32 ne[8] ; // nombre de pixels region exterieure + double sigi2[8], sige2[8]; // carres des variances, regions interieure et exterieure + + /* variance des valeurs des niveaux de gris a l'interieur du snake */ + sigi2[thread] = + ((double)s_stats_snake[3*thread +2]/(double)s_stats_snake[3*thread +0]) - + ((double)s_stats_snake[3*thread +1]/s_stats_snake[3*thread +0])*((double)s_stats_snake[3*thread +1]/s_stats_snake[3*thread +0]) ; + + /* variance des valeurs des niveaux de gris a l'exterieur du snake */ + ne[thread] = h*l-s_stats_snake[3*thread +0] ; + stat_sum_xe[thread] = d_stats_snake[4] - s_stats_snake[3*thread +1] ; + sige2[thread] = + (double)(d_stats_snake[5]-s_stats_snake[3*thread +2])/(double)ne[thread] - + ((double)stat_sum_xe[thread]/ne[thread])*((double)stat_sum_xe[thread]/ne[thread]) ; + + if (sige2[thread]>0 && sigi2[thread]>0) + vrais[8*interval + thread] = 0.5*((double)s_stats_snake[3*thread]*log(sigi2[thread]) + (double)ne[thread]*log(sige2[thread])) ; + else + vrais[8*interval + thread] = -1.0; + + if ( thread == 0 ){ + //init move + move[id_nx] = false ; + int pos_optim = -1; + double vrais_tmp = *vrais_min; + for (int v=0; v < 8; v++){ + if ( (vrais[8*interval + v] > 0) && (vrais[8*interval + v] < vrais_tmp*COEF_DECROI) ) { + vrais_tmp = vrais[8*interval + v]; + pos_optim = v; + } + } + if (pos_optim >-1){ + if ( !croisement(d_snake, id_nx, d_liste_points[8*id_nx + pos_optim].x, d_liste_points[8*id_nx + pos_optim].y, nnodes) ) + { + /*maj data snake*/ + move[id_nx] = true ; + //new position + d_snake[id_nx].posi = d_liste_points[8*id_nx + pos_optim].x ; + d_snake[id_nx].posj = d_liste_points[8*id_nx + pos_optim].y ; + //nb pixels segment precedent + d_snake[id_nprec].nb_pixels = d_liste_points[8*id_nx + pos_optim].z ; + //nb pixels segment suivant + d_snake[id_nx].nb_pixels = d_liste_points[8*id_nx + pos_optim].w ; + //contribs segment precedent + d_snake[id_nprec].sum_1 = d_contribs[3*(16*interval + pos_optim)] ; + d_snake[id_nprec].sum_x = d_contribs[3*(16*interval + pos_optim) + 1] ; + d_snake[id_nprec].sum_x2 = d_contribs[3*(16*interval + pos_optim) + 2] ; + //contribs segment suivant + d_snake[id_nx].sum_1 = d_contribs[3*(16*interval + pos_optim + 8)] ; + d_snake[id_nx].sum_x = d_contribs[3*(16*interval + pos_optim + 8) + 1] ; + d_snake[id_nx].sum_x2 = d_contribs[3*(16*interval + pos_optim + 8) + 2] ; + //freemans segment precedent + d_snake[id_nprec].freeman_out = d_freemans[16*interval + pos_optim].z ; + d_snake[id_nprec].freeman_in = d_freemans[16*interval + pos_optim].w ; + //freemans segment suivant + d_snake[id_nx].freeman_out = d_freemans[16*interval + pos_optim + 8].z ; + d_snake[id_nx].freeman_in = d_freemans[16*interval + pos_optim + 8].w ; + //codes segment precedent + d_snake[id_nprec].code_segment = code_segment[16*interval + pos_optim] ; + //code segment suivant + d_snake[id_nx].code_segment = code_segment[16*interval + pos_optim + 8] ; + //centre segment precedent + d_snake[id_nprec].centre_i = d_freemans[16*interval + pos_optim ].x ; + d_snake[id_nprec].centre_j = d_freemans[16*interval + pos_optim ].y ; + //centre segment suivant + d_snake[id_nx].centre_i = d_freemans[16*interval + pos_optim + 8].x ; + d_snake[id_nx].centre_j = d_freemans[16*interval + pos_optim + 8].y ; + + } + } + } + + +} + +__global__ void recalcul_stats_snake(snake_node_gpu * d_snake, int nnodes, int64 * d_stats_snake, double * vrais_min, + t_cumul_x * cumul_x, t_cumul_x2 * cumul_x2, int * TABLE_CODAGE, uint32 l + ) +{ + + int id_nx, id_nprec, id_nprecprec ; + int code_noeud, code_segment, pos; + int64 s_stats_snake[3] ; + + //init stats en shared mem + s_stats_snake[0] = 0 ; + s_stats_snake[1] = 0 ; + s_stats_snake[2] = 0 ; + + + for (id_nx = 0; id_nx < nnodes; id_nx++) + { + if (id_nx == 0) id_nprec = nnodes - 1; + else id_nprec = id_nx - 1; + if (id_nprec == 0) id_nprecprec = nnodes -1 ; + else id_nprecprec = id_nprec - 1 ; + /* gestion des segments partant du noeud */ + /* vers le noeud suivant dans l'ordre trigo */ + code_segment = d_snake[id_nprec].code_segment ; + if (code_segment > 0) + { + /* on somme les contributions */ + s_stats_snake[0] += d_snake[id_nprec].sum_1 ; + s_stats_snake[1] += d_snake[id_nprec].sum_x ; + s_stats_snake[2] += d_snake[id_nprec].sum_x2 ; + } + else if (code_segment < 0) + { + /* on soustrait les contributions */ + s_stats_snake[0] -= d_snake[id_nprec].sum_1 ; + s_stats_snake[1] -= d_snake[id_nprec].sum_x ; + s_stats_snake[2] -= d_snake[id_nprec].sum_x2 ; + } + // else (code_segment == 0), on ne fait rien + /* gestion des pixels connectant les segments */ + pos = d_snake[id_nprecprec].freeman_in*8 + d_snake[id_nprec].freeman_out ; + code_noeud = TABLE_CODAGE[pos] ; + pos = d_snake[id_nprec].posi*l + d_snake[id_nprec].posj ; + + if (code_noeud > 0) + { + /* on somme les contributions */ + s_stats_snake[0] += 1 + d_snake[id_nprec].posj ; + s_stats_snake[1] += cumul_x[pos] ; + s_stats_snake[2] += cumul_x2[pos] ; + } + else if (code_noeud < 0) + { + /* on soustrait les contributions */ + s_stats_snake[0] -= 1 + d_snake[id_nprec].posj ; + s_stats_snake[1] -= cumul_x[pos] ; + s_stats_snake[2] -= cumul_x2[pos] ; + } + // else (code_pixel == 0), on ne fait rien + } + d_stats_snake[0] = s_stats_snake[0] ; + d_stats_snake[1] = s_stats_snake[1] ; + d_stats_snake[2] = s_stats_snake[2] ; + + *vrais_min = codage_gl_hyp_gauss(s_stats_snake[0], s_stats_snake[1], s_stats_snake[2], + d_stats_snake[3], d_stats_snake[4], d_stats_snake[5]); +} + + +__global__ void ajoute_noeuds(snake_node_gpu * snake, snake_node_gpu * snake_tmp, int nnodes, int seuil, int * new_nb_nodes){ + + volatile snake_node_gpu * st = snake_tmp ; + + int id_cpy = 0; + for (int id_nx=0; id_nx < nnodes; id_nx++){ + //position du noeud existant + st[id_cpy].posi = snake[id_nx].posi ; + st[id_cpy].posj = snake[id_nx].posj ; + + id_cpy++ ; + + if ( snake[id_nx].nb_pixels > seuil) + { + //position du nouveau noeud + st[id_cpy].posi = snake[id_nx].centre_i ; + st[id_cpy].posj = snake[id_nx].centre_j ; + id_cpy++ ; + } + } + for( int node=0; node= nb_nodes) n2 = 0 ; + + //affectation des differentes positions aux différents segments 'blocs de threads' + x1 = d_snake[n1].posj ; + y1 = d_snake[n1].posi ; + x2 = d_snake[n2].posj ; + y2 = d_snake[n2].posi ; + + //params des deplacements + int dx=x2-x1; + int dy=y2-y1; + uint abs_dx = ABS(dx); + uint abs_dy = ABS(dy); + uint nb_pix = abs_dy>abs_dx?(abs_dy+1):(abs_dx+1); // alternative -> lecture ds liste_points[] + int incx=0, incy=0; + + + //calcul liste des pixels du segment (x1,y1)-(x2,y2) + if (dy > 0) incy=1; else incy=-1 ; + if (dx > 0) incx=1; else incx=-1 ; + + if (tis < nb_pix){ + if (abs_dy > abs_dx){ + //1 thread par ligne + double k = (double)dx/dy ; + p.x = y1 + incy*tis ; + p.y = x1 + floor((double)incy*k*tis+0.5) ; + + } else { + //1 thread par colonne + double k=(double)dy/dx ; + p.x = y1 + floor((double)(incx*k*tis)+0.5) ; + p.y = x1 + incx*tis ; + if ( tis > 0 ){ + xsuiv = y1 + floor((double)(incx*k*(tis+1))+0.5) ; + xprec = y1 + floor((double)(incx*k*(tis-1))+0.5) ; + } + + } + if (tis == 0) liste_pix[5*segment] = make_uint2(p.x, p.y) ; + if (tis == 1) liste_pix[5*segment +1] = make_uint2(p.x,p.y) ; + if (tis == nb_pix/2) liste_pix[5*segment +2] = make_uint2(p.x,p.y) ; + if (tis == nb_pix-2) liste_pix[5*segment +3] = make_uint2(p.x,p.y) ; + if (tis == nb_pix-1) liste_pix[5*segment +4] = make_uint2(p.x,p.y) ; + + } + __syncthreads(); + + //calcul contribs individuelles des pixels + + if ( (tis >0) && (tis < nb_pix-1) + && ( ( (abs_dy <= abs_dx) && ( ( xprec > p.x) || ( xsuiv > p.x)) ) + || (abs_dy > abs_dx) ) ) + { + int pos = p.x * l + p.y ; + scumuls[ CFI(tib)].c1 = 1+p.y; + scumuls[ CFI(tib)].cx = cumul_x[ pos ] ; + scumuls[CFI(tib)].cx2 = cumul_x2[ pos ]; + } else { + scumuls[ CFI(tib)].c1 = 0; + scumuls[ CFI(tib)].cx = 0; + scumuls[CFI(tib)].cx2 = 0; + } + + __syncthreads(); + //somme des contribs individuelles + // unroll des sommes partielles en smem + + if (blockSize >= 512) { + if (tib < 256) { + scumuls[ CFI(tib)].c1 += scumuls[ CFI(tib + 256) ].c1; + scumuls[ CFI(tib)].cx += scumuls[ CFI(tib + 256) ].cx; + scumuls[CFI(tib)].cx2 += scumuls[CFI(tib + 256) ].cx2; + } + __syncthreads(); + } + + if (blockSize >= 256) { + if (tib < 128) { + scumuls[ CFI(tib)].c1 += scumuls[ CFI(tib + 128) ].c1; + scumuls[ CFI(tib)].cx += scumuls[ CFI(tib + 128) ].cx; + scumuls[CFI(tib)].cx2 += scumuls[CFI(tib + 128) ].cx2; + } + __syncthreads(); + } + if (blockSize >= 128) { + if (tib < 64) { + scumuls[ CFI(tib)].c1 += scumuls[ CFI(tib + 64) ].c1; + scumuls[ CFI(tib)].cx += scumuls[ CFI(tib + 64) ].cx; + scumuls[CFI(tib)].cx2 += scumuls[ CFI(tib + 64) ].cx2; + } + __syncthreads(); + } + + //32 threads <==> 1 warp + volatile tcontribs * scontribs = scumuls ; + if (tib < 32) + { + { + scontribs[ CFI(tib)].c1 += scontribs[ CFI(tib + 32) ].c1; + scontribs[ CFI(tib)].cx += scontribs[ CFI(tib + 32) ].cx; + scontribs[ CFI(tib)].cx2 +=scontribs[ CFI(tib + 32) ].cx2; + } + if (tib<16) + { + scontribs[ CFI(tib)].c1 += scontribs[ CFI(tib + 16) ].c1; + scontribs[ CFI(tib)].cx += scontribs[ CFI(tib + 16) ].cx; + scontribs[ CFI(tib)].cx2 +=scontribs[ CFI(tib + 16) ].cx2; + } + if (tib<8) + { + scontribs[ CFI(tib)].c1 += scontribs[ CFI(tib + 8) ].c1; + scontribs[ CFI(tib)].cx += scontribs[ CFI(tib + 8) ].cx; + scontribs[ CFI(tib)].cx2 +=scontribs[ CFI(tib + 8) ].cx2;} + if (tib<4){ + scontribs[ CFI(tib)].c1 += scontribs[ CFI(tib + 4) ].c1; + scontribs[ CFI(tib)].cx += scontribs[ CFI(tib + 4) ].cx; + scontribs[ CFI(tib)].cx2 +=scontribs[ CFI(tib + 4) ].cx2; + } + if (tib<2){ + scontribs[ CFI(tib)].c1 += scontribs[ CFI(tib + 2) ].c1; + scontribs[ CFI(tib)].cx += scontribs[ CFI(tib + 2) ].cx; + scontribs[ CFI(tib)].cx2 +=scontribs[ CFI(tib + 2) ].cx2; + } + if (tib==0){ + scontribs[ CFI(tib)].c1 += scontribs[ CFI(tib + 1) ].c1; + scontribs[ CFI(tib)].cx += scontribs[ CFI(tib + 1) ].cx; + scontribs[ CFI(tib)].cx2 +=scontribs[ CFI(tib + 1) ].cx2; + // resultat sommes partielles en gmem + //if (tib == 0) { + gsombloc[ blockIdx.x ] = scontribs[0].c1; + gsombloc[ blockIdx.x + gridDim.x ] = scontribs[0].cx; + gsombloc[ blockIdx.x + 2*gridDim.x ] = scontribs[0].cx2; + + //calculs code segment + //code seg + if (dy > 0 ) d_snake[segment].code_segment = -1 ; + if (dy < 0 ) d_snake[segment].code_segment = 1 ; + if (dy == 0) d_snake[segment].code_segment = 0 ; + } + } +} + +__global__ void recalcul_freemans_centre(snake_node_gpu * snake, uint2 * liste_pix, int * d_table_freeman){ + + int id_segment = blockIdx.x ; + int id_base_pix = 5*id_segment ; + + //calculs freemans, centre et code segment + //1 uint4 par segment + int Dio, Djo, Dii, Dji; + + //freeman out + Dio = 1 + liste_pix[id_base_pix +1].x - liste_pix[id_base_pix].x ; + Djo = 1 + liste_pix[id_base_pix +1].y - liste_pix[id_base_pix].y ; + snake[id_segment].freeman_out = d_table_freeman[3*Dio + Djo] ; + + //freeman_in + Dii = 1 + liste_pix[id_base_pix +4].x - liste_pix[id_base_pix +3].x ; + Dji = 1 + liste_pix[id_base_pix +4].y - liste_pix[id_base_pix +3].y ; + snake[id_segment].freeman_in = d_table_freeman[3*Dii + Dji] ; + + //centre + snake[id_segment].centre_i = liste_pix[id_base_pix +2].x ; + snake[id_segment].centre_j = liste_pix[id_base_pix +2].y ; + +} + + +/* + sommme des contribs par bloc -> contribs segment, pour le snake + + execution sur : 1bloc / 1 thread par segment + */ + +__global__ void resomsom_snake(uint64 * somblocs, int nb_nodes, unsigned int nb_bl_seg, snake_node_gpu * d_snake){ + + uint64 sdata[3]; + unsigned int seg = blockIdx.x ; + + //un thread par segment + { + sdata[0] = 0; + sdata[1] = 0; + sdata[2] = 0; + } + + for (int b=0; b < nb_bl_seg ; b++){ + sdata[0] += somblocs[seg*nb_bl_seg + b]; + sdata[1] += somblocs[(seg + nb_nodes)*nb_bl_seg + b]; + sdata[2] += somblocs[(seg + 2*nb_nodes)*nb_bl_seg + b]; + } + + //totaux en gmem + { + d_snake[seg].sum_1 = sdata[0]; + d_snake[seg].sum_x = sdata[1]; + d_snake[seg].sum_x2 = sdata[2]; + } +} + diff --git a/src/lib_kernels_contribs.cu~ b/src/lib_kernels_contribs.cu~ new file mode 100644 index 0000000..2052ac2 --- /dev/null +++ b/src/lib_kernels_contribs.cu~ @@ -0,0 +1,1043 @@ +#include "constantes.h" + +/* + * determine et retourne le nb de pixels composant le segment (i,j)-(i1,j1) + * + */ +__device__ int calcul_nb_pixels(int i, int j, int i1, int j1){ + int absi, absj,nbpix =0; + //MAX( ABS(i1-i) , ABS(j1-j)) + 1 + if (i1 > i) absi = i1 - i ; else absi = i - i1 ; + if (j1 > j) absj = j1 - j ; else absj = j - j1 ; + if (absi > absj ) nbpix = absi+1 ; else nbpix = absj+1 ; + return nbpix ; +} + +/* + construit la liste des coordonnées des 8 positions a tester pour l'ensemble des N noeuds du snake + ainsi que le liste des nombres de pixels correspondant (en z, seg avant, en w seg apres) + a executer avec N blocs de 8 threads +*/ +__global__ void liste_positions_a_tester(snake_node_gpu * d_snake, uint4 * liste_positions, uint32 * nb_pix_max, int pas, int nb_nodes, int h, int l){ + int tib = threadIdx.x; // une position par thread + int node = blockIdx.x; // 1 noeud par bloc de threads + int node_prec, node_suiv ; // indices des nodes + int i, j, i1, j1, i2, j2, i3, j3, npix_prec, npix_suiv ; // coordonnees des noeuds , nb de pixels + + //lecture des coordonnees + node_prec = (node == 0)? (nb_nodes-1) : (node - 1) ; + node_suiv = (node == nb_nodes-1)? (0) : (node + 1) ; + i1 = d_snake[node_prec].posi ; + j1 = d_snake[node_prec].posj ; + i2 = d_snake[node].posi ; + j2 = d_snake[node].posj ; + i3 = d_snake[node_suiv].posi ; + j3 = d_snake[node_suiv].posj ; + + switch(tib){ // on considere un voisinage a 8 points + case 0: + i = i2 ; + if ((j2 + pas) < l) j = j2 + pas ; else j = l-2 ; + break; + case 1: + if ((j2 + pas) < l) j = j2 + pas ; else j = l-2 ; + if (i2 > pas ) i = i2 - pas ; else i = 1 ; + break; + case 2: + if (i2 > pas ) i = i2 - pas ; else i = 1 ; + j = j2 ; + break; + case 3: + if (i2 > pas) i = i2 - pas ; else i = 1 ; + if (j2 > pas) j = j2 - pas ; else j = 1 ; + break; + case 4: + i = i2 ; + if (j2 > pas) j = j2 - pas ; else j = 1 ; + break; + case 5: + if ((i2 + pas) < h) i = i2 + pas ; else i = h-2 ; + if (j2 > pas) j = j2 - pas ; else j = 1 ; + break; + case 6: + if ((i2 + pas) < h) i = i2 + pas ; else i = h-2 ; + j = j2 ; + break; + case 7: + if ((i2 + pas) < h) i = i2 + pas ; else i = h-2 ; + if ((j2 + pas) < l) j = j2 + pas ; else j = l-2 ; + break; + } + + //calcul des nombres de pixels dans chaque cas + npix_prec = calcul_nb_pixels(i,j,i1,j1) ; + npix_suiv = calcul_nb_pixels(i,j,i3,j3) ; + + liste_positions[8*node + tib] = make_uint4(i,j, (uint)npix_prec, (uint)npix_suiv ); + + // calcule du maximum global du nb de pixels + if ((node == 0) && (tib == 0)) + { + *nb_pix_max = 0 ; + for (int n=0; n *nb_pix_max) *nb_pix_max = liste_positions[n].z ; + if (liste_positions[n].w > *nb_pix_max) *nb_pix_max = liste_positions[n].w ; + } + } +} + +/* + * calcule : + * - les coordonnees de chaque pixel de chaque segment a evaluer pour les 8 voisins de chaque noeud (pair ou impair) + * cela represente 16 segments par noeud pair/impair + * - les contributions de chacun de ces pixels + * - les sommes, par blocs, des contributions des pixels (les sommes totales sont faites par le kernel somsom) + * - le code de chaque segment envisage + */ + +__global__ void calcul_contribs_segments_blocs_full(snake_node_gpu * d_snake, int nb_nodes, uint4 * liste_points, uint32 npix_max, + t_cumul_x * cumul_x, t_cumul_x2 * cumul_x2, int * d_codes_x16, + int l, uint2 * liste_pix, uint64 * gsombloc, bool pairs) +{ + // indices des elements + int blockSize = blockDim.x ; // nb threads par bloc + int tib = threadIdx.x ; // position du thread dans le bloc + int nblocs_noeud = gridDim.x / (nb_nodes/2 + pairs*(nb_nodes%2)) ; // nb de blocs dédié à chaque noeud + int nblocs_seg = nblocs_noeud / 16 ; // nb de blocs dédiés à un segment de test + int idx = blockDim.x*blockIdx.x + threadIdx.x ; // position absolue du thread ds la grille + int id_interval = blockIdx.x / nblocs_noeud ; // indice de l'intervalle du noeud dans la grille + int segment = ( blockIdx.x - id_interval*nblocs_noeud )/nblocs_seg ; // indice du segment de 0 à 15 + int tis = idx - ( id_interval*nblocs_noeud + segment*nblocs_seg )*blockDim.x ; // position du thread ds le segment + int id_base_seg = 16*id_interval + segment ; // indice du segment courant + int id_base_pix = 5*id_base_seg ; // indice du pixel 0/5 du segment courant dans la liste_pix pour le calcul des freemans + + //tab pour contribs pixels + extern __shared__ tcontribs scumuls[]; + + //coordonnees des extremites de segment + uint x1, y1, x2, y2 ; + //indices des noeuds precedent(n1), courant(n2), suivant(n3) + int n1, n2, n3 ; + // pixel courant + uint2 p ; + // nb de pixels du segment precedent, suivant + int xprec, xsuiv ; + + // determine les indices des noeuds prec, courant, suiv + if (pairs) + { + n1 = 2*id_interval -1 ; + n2 = 2*id_interval ; + n3 = 2*id_interval +1 ; + } + else + { + n1 = 2*id_interval ; + n2 = 2*id_interval +1 ; + n3 = 2*id_interval +2 ; + } + //gestion du bouclage du snake + if (n1 < 0) n1 = nb_nodes-1 ; + if (n3 >= nb_nodes) n3 = 0 ; + + + //affectation des differentes positions aux différents segments 'blocs de threads' + if ( segment < 8 ){ + x1 = d_snake[n1].posj ; + y1 = d_snake[n1].posi ; + x2 = liste_points[8*n2 + segment].y ; + y2 = liste_points[8*n2 + segment].x ; + } else { + x1 = liste_points[8*n2 + segment-8].y ; + y1 = liste_points[8*n2 + segment-8].x ; + x2 = d_snake[n3].posj ; + y2 = d_snake[n3].posi ; + } + + //params des deplacements + int dx=x2-x1; + int dy=y2-y1; + uint abs_dx = ABS(dx); + uint abs_dy = ABS(dy); + uint nb_pix = abs_dy>abs_dx?(abs_dy+1):(abs_dx+1); + int incx=0, incy=0; + + + //calcul liste des pixels du segment (x1,y1)-(x2,y2) + if (dy > 0) incy=1; else incy=-1 ; + if (dx > 0) incx=1; else incx=-1 ; + + if (tis < nb_pix){ + if (abs_dy > abs_dx){ + //1 thread par ligne pente 1/k + double k = (double)dx/dy ; + //coordonnees pixel + p.x = y1 + incy*tis ; + p.y = x1 + floor((double)incy*k*tis+0.5) ; + } else { + //1 thread par colonne pente k + double k=(double)dy/dx ; + //coordonnees pixel + p.x = y1 + floor((double)(incx*k*tis)+0.5) ; + p.y = x1 + incx*tis ; + // ordonnees des pixels suivant & precedent + if ( tis > 0 ){ + xsuiv = y1 + floor((double)(incx*k*(tis+1))+0.5) ; + xprec = y1 + floor((double)(incx*k*(tis-1))+0.5) ; + } + } + // memorisation des valeurs necessaires au calcul des freemans et des centres + if (tis == 0) liste_pix[id_base_pix] = make_uint2(p.x, p.y) ; + if (tis == 1) liste_pix[id_base_pix +1] = make_uint2(p.x,p.y) ; + if (tis == nb_pix/2) liste_pix[id_base_pix +2] = make_uint2(p.x,p.y) ; + if (tis == nb_pix-2) liste_pix[id_base_pix +3] = make_uint2(p.x,p.y) ; + if (tis == nb_pix-1) liste_pix[id_base_pix +4] = make_uint2(p.x,p.y) ; + } + + __syncthreads(); + // calcul contribs individuelles des pixels + // dans le cas des segments 'plutot horizontaux', on ne garde qu'une contrib par ligne ; celle du pixel le plus a l'interieur du snake + if ( (tis >0) && (tis < nb_pix-1) + && ( ((abs_dy <= abs_dx) && ( ( xprec > p.x) || ( xsuiv > p.x))) + || (abs_dy > abs_dx) ) ) + { + int pos = p.x * l + p.y ; + scumuls[ CFI(tib)].c1 = 1 + p.y ; + scumuls[ CFI(tib)].cx = cumul_x[ pos ] ; + scumuls[CFI(tib)].cx2 = cumul_x2[ pos ]; + } else { + scumuls[ CFI(tib)].c1 = 0; + scumuls[ CFI(tib)].cx = 0; + scumuls[ CFI(tib)].cx2 = 0; + } + + __syncthreads(); + // somme des contribs individuelles + // unroll des sommes partielles en shared memory + if (blockSize >= 512) { + if (tib < 256) { + scumuls[ CFI(tib)].c1 += scumuls[ CFI(tib + 256) ].c1; + scumuls[ CFI(tib)].cx += scumuls[ CFI(tib + 256) ].cx; + scumuls[ CFI(tib)].cx2 += scumuls[CFI(tib + 256) ].cx2; + } + __syncthreads(); + } + + if (blockSize >= 256) { + if (tib < 128) { + scumuls[ CFI(tib)].c1 += scumuls[ CFI(tib + 128) ].c1; + scumuls[ CFI(tib)].cx += scumuls[ CFI(tib + 128) ].cx; + scumuls[ CFI(tib)].cx2 += scumuls[CFI(tib + 128) ].cx2; + } + __syncthreads(); + } + if (blockSize >= 128) { + if (tib < 64) { + scumuls[ CFI(tib)].c1 += scumuls[ CFI(tib + 64) ].c1; + scumuls[ CFI(tib)].cx += scumuls[ CFI(tib + 64) ].cx; + scumuls[CFI(tib)].cx2 += scumuls[CFI(tib + 64) ].cx2; + } + __syncthreads(); + } + + //32 threads <==> 1 warp + volatile tcontribs * scontribs = scumuls ; + if (tib < 32){ + { + scontribs[ CFI(tib)].c1 += scontribs[ CFI(tib + 32) ].c1; + scontribs[ CFI(tib)].cx += scontribs[ CFI(tib + 32) ].cx; + scontribs[CFI(tib)].cx2 += scontribs[CFI(tib + 32) ].cx2; + } + if (tib < 16) + { + scontribs[ CFI(tib)].c1 += scontribs[ CFI(tib + 16) ].c1; + scontribs[ CFI(tib)].cx += scontribs[ CFI(tib + 16) ].cx; + scontribs[CFI(tib)].cx2 += scontribs[CFI(tib + 16) ].cx2; + } + if (tib < 8) + { + scontribs[ CFI(tib)].c1 += scontribs[ CFI(tib + 8) ].c1; + scontribs[ CFI(tib)].cx += scontribs[ CFI(tib + 8) ].cx; + scontribs[CFI(tib)].cx2 += scontribs[CFI(tib + 8) ].cx2; + } + if (tib < 4) + { + scontribs[ CFI(tib)].c1 += scontribs[ CFI(tib + 4) ].c1; + scontribs[ CFI(tib)].cx += scontribs[ CFI(tib + 4) ].cx; + scontribs[ CFI(tib)].cx2 +=scontribs[ CFI(tib + 4) ].cx2; + } + if (tib < 2) + { + scontribs[ CFI(tib)].c1 += scontribs[ CFI(tib + 2) ].c1; + scontribs[ CFI(tib)].cx += scontribs[ CFI(tib + 2) ].cx; + scontribs[CFI(tib)].cx2 += scontribs[CFI(tib + 2) ].cx2; + } + if (tib == 0) + { + scontribs[ CFI(tib)].c1 += scontribs[ CFI(tib + 1) ].c1; + scontribs[ CFI(tib)].cx += scontribs[ CFI(tib + 1) ].cx; + scontribs[CFI(tib)].cx2 += scontribs[CFI(tib + 1) ].cx2; + + // resultat sommes partielles en gmem + //if (tib == 0) { + gsombloc[ blockIdx.x ] = scontribs[0].c1 ; + gsombloc[ blockIdx.x + gridDim.x ] = scontribs[0].cx ; + gsombloc[ blockIdx.x + 2*gridDim.x ] = scontribs[0].cx2 ; + + //code seg + if (dy > 0 ) d_codes_x16[id_base_seg] = -1 ; + if (dy < 0 ) d_codes_x16[id_base_seg] = 1 ; + if (dy == 0) d_codes_x16[id_base_seg]= 0 ; + } + } +} + +/* + calcul des freeman et du centre de chaque segment de test + a executer sur 'n_interval' blocs de 16 threads + soit un thread par segment +*/ +__global__ void calcul_freemans_centre(uint2 * liste_pix, int * d_table_freeman, uint4 * d_freemans_x16){ + + int id_segment = threadIdx.x ; + int id_freeman = ( blockDim.x*blockIdx.x + id_segment ) ; + int id_base_pix = 5*id_freeman ; + + //calculs freemans, centre et code segment + //1 uint4 par segment + int Dio, Djo, Dii, Dji; + + //freeman out + Dio = 1 + liste_pix[id_base_pix +1].x - liste_pix[id_base_pix].x ; + Djo = 1 + liste_pix[id_base_pix +1].y - liste_pix[id_base_pix].y ; + d_freemans_x16[id_freeman].z = d_table_freeman[3*Dio + Djo] ; + + + //freeman_in + Dii = 1 + liste_pix[id_base_pix +4].x - liste_pix[id_base_pix +3].x ; + Dji = 1 + liste_pix[id_base_pix +4].y - liste_pix[id_base_pix +3].y ; + d_freemans_x16[id_freeman].w = d_table_freeman[3*Dii + Dji] ; + + //centre + d_freemans_x16[id_freeman].x = liste_pix[id_base_pix +2].x ; + d_freemans_x16[id_freeman].y = liste_pix[id_base_pix +2].y ; + +} + + +/* + calcul des contribs 1, x et x2 des 16 segments + autour du noeud + a partir des sommes partielles des blocs + 1 bloc / 1 thread par segment +*/ + +__global__ void somsom_full(uint64 * somblocs, int nb_nodes, unsigned int nb_bl_seg, uint64 * somsom){ + + uint64 sdata[3]; + unsigned int seg = blockIdx.x ; + unsigned int nb_seg = gridDim.x ; + + //un thread par segment + { + sdata[0] = 0; + sdata[1] = 0; + sdata[2] = 0; + } + + for (int b=0; b < nb_bl_seg ; b++){ //voir atomicadd 64bits + sdata[0] += somblocs[seg*nb_bl_seg + b]; + sdata[1] += somblocs[(seg + nb_seg)*nb_bl_seg + b]; + sdata[2] += somblocs[(seg + 2*nb_seg)*nb_bl_seg + b]; + } + + //totaux en gmem + { + somsom[3*seg] = sdata[0]; + somsom[3*seg + 1] = sdata[1]; + somsom[3*seg + 2] = sdata[2]; + } +} + +/* + version GPU de la fonction definie ds src/lib_math.c +*/ +__device__ bool test_inf_gpu(double arg1, double arg2){ + if (arg2 > 0) + return (arg1 < (arg2*COEF_DECROI)) ; + else + return (arg1 < (arg2*INV_COEF_DECROI)) ; +} + +/* + version GPU de la fonction codage_niveau_gris_hyp_gaussienne + */ +__device__ double codage_gl_hyp_gauss(uint64 stat_sum_1, uint64 stat_sum_x, uint64 stat_sum_x2, + uint64 n_dim, uint64 SUM_X, uint64 SUM_X2){ + uint64 stat_sum_xe ; /* somme des xn region exterieure */ + uint32 ne ; /* nombre de pixel region exterieure */ + double sigi2, sige2; /* variance region interieure et exterieure */ + + /* variance des valeurs des niveaux de gris a l'interieur du snake */ + sigi2 = + (double)stat_sum_x2/(double)stat_sum_1 - + ((double)stat_sum_x/stat_sum_1)*((double)stat_sum_x/stat_sum_1) ; + + /* variance des valeurs des niveaux de gris a l'exterieur du snake */ + ne = n_dim-stat_sum_1 ; + stat_sum_xe = SUM_X - stat_sum_x ; + sige2 = + ((double)SUM_X2-stat_sum_x2)/ne - + ((double)stat_sum_xe/ne)*((double)stat_sum_xe/ne) ; + + if ((sigi2 > 0)&&(sige2 > 0)) + return 0.5*((double)stat_sum_1*log(sigi2) + (double)ne*log(sige2)) ; + return -1 ; +} + +/* + soustrait, pour chaque intervalle [N1--Nx--N2] + les contributions des segments N1--Nx et Nx--N2 + + A executer par nnodes blocs de 1 thread par intervalle + */ + +__global__ void soustrait_aux_stats_2N_segments_noeud(snake_node_gpu * d_snake, int64 * d_stats_snake, int64 * d_stats_ref, + t_cumul_x * cumul_x, t_cumul_x2 * cumul_x2, + int * TABLE_CODAGE, uint32 l + ) +{ + int nnodes = gridDim.x ; + int id_nx, id_nprec, id_nprecprec, id_nsuiv ; + int code_noeud, pos; + __shared__ int64 s_stats_snake[3] ; + + id_nx = blockIdx.x ; + if (id_nx == 0) id_nprec = nnodes - 1; + else id_nprec = id_nx - 1; + if (id_nprec == 0) id_nprecprec = nnodes -1 ; + else id_nprecprec = id_nprec - 1 ; + if (id_nx == nnodes-1) id_nsuiv = 0; + else id_nsuiv = id_nx + 1 ; + + //init avec les valeurs du contour actuel + s_stats_snake[0] = d_stats_snake[0] ; + s_stats_snake[1] = d_stats_snake[1] ; + s_stats_snake[2] = d_stats_snake[2] ; + + /* segment Na -- Nx */ + if (d_snake[id_nprec].code_segment > 0) + { + s_stats_snake[0] -= d_snake[id_nprec].sum_1 ; + s_stats_snake[1] -= d_snake[id_nprec].sum_x ; + s_stats_snake[2] -= d_snake[id_nprec].sum_x2 ; + } + else if (d_snake[id_nprec].code_segment < 0) + { + s_stats_snake[0] += d_snake[id_nprec].sum_1 ; + s_stats_snake[1] += d_snake[id_nprec].sum_x ; + s_stats_snake[2] += d_snake[id_nprec].sum_x2 ; + } + // else (code_segment_NaNx == 0), on ne fait rien + + /* gestion des pixels connectant les segments */ + /* pixel de depart du segment Na --> Nx */ + pos = d_snake[id_nprecprec].freeman_in*8 + d_snake[id_nprec].freeman_out ; + code_noeud = TABLE_CODAGE[pos] ; + pos = d_snake[id_nprec].posi*l + d_snake[id_nprec].posj ; + if (code_noeud > 0) + { + s_stats_snake[0] -= 1 + d_snake[id_nprec].posj ; + s_stats_snake[1] -= cumul_x[pos] ; + s_stats_snake[2] -= cumul_x2[pos]; + } + else if (code_noeud < 0) + { + s_stats_snake[0] += 1 + d_snake[id_nprec].posj ; + s_stats_snake[1] += cumul_x[pos] ; + s_stats_snake[2] += cumul_x2[pos]; + } + // else (code_noeud == 0), on ne fait rien + + /* -------------------------- */ + /* -------------------------- */ + /* segment Nx -- Nb */ + if ( d_snake[id_nx].code_segment > 0 ) + { + // on soustrait la contribution + s_stats_snake[0] -= d_snake[id_nx].sum_1 ; + s_stats_snake[1] -= d_snake[id_nx].sum_x ; + s_stats_snake[2] -= d_snake[id_nx].sum_x2 ; + } + else if ( d_snake[id_nx].code_segment < 0) + { + s_stats_snake[0] += d_snake[id_nx].sum_1 ; + s_stats_snake[1] += d_snake[id_nx].sum_x ; + s_stats_snake[2] += d_snake[id_nx].sum_x2 ; + } + // else (code_segment_NxNb == 0), on ne fait rien + + /* gestion des pixels connectant les segments */ + /* pixel de depart du segment Nx --> Nb */ + pos = d_snake[id_nprec].freeman_in*8 + d_snake[id_nx].freeman_out ; + code_noeud = TABLE_CODAGE[pos] ; + pos = d_snake[id_nx].posi*l + d_snake[id_nx].posj ; + if (code_noeud > 0) + { + s_stats_snake[0] -= 1 + d_snake[id_nx].posj ; + s_stats_snake[1] -= cumul_x[pos] ; + s_stats_snake[2] -= cumul_x2[pos]; + } + else if (code_noeud < 0) + { + s_stats_snake[0] += 1 + d_snake[id_nx].posj ; + s_stats_snake[1] += cumul_x[pos] ; + s_stats_snake[2] += cumul_x2[pos]; + } + // else (code_noeud == 0), on ne fait rien + + /* pixel d'arrivee du segment Nx --> Nb */ + pos = d_snake[id_nx].freeman_in*8 + d_snake[id_nsuiv].freeman_out ; + code_noeud = TABLE_CODAGE[pos] ; + pos = d_snake[id_nsuiv].posi*l + d_snake[id_nsuiv].posj ; + if (code_noeud > 0) + { + s_stats_snake[0] -= 1 + d_snake[id_nsuiv].posj ; + s_stats_snake[1] -= cumul_x[pos] ; + s_stats_snake[2] -= cumul_x2[pos]; + } + else if (code_noeud < 0) + { + s_stats_snake[0] += 1 + d_snake[id_nsuiv].posj ; + s_stats_snake[1] += cumul_x[pos] ; + s_stats_snake[2] += cumul_x2[pos]; + } + // else (code_noeud == 0), on ne fait rien + __syncthreads(); + + d_stats_ref[3*id_nx] = s_stats_snake[0] ; + d_stats_ref[3*id_nx + 1] = s_stats_snake[1] ; + d_stats_ref[3*id_nx + 2] = s_stats_snake[2] ; + +} + + +/* + calcul des stats associees a chaque position de test + + EXEC : sur n_interval blocs de 8 threads +*/ +__global__ void calcul_stats_full(snake_node_gpu * d_snake, int nnodes, bool pairs, int64 * d_stats_snake, + int64 * d_stats_ref, int64 * d_stats, uint64 * d_contribs, + uint4 * d_liste_points, int * code_segment, uint4 * d_freemans, + int * d_table_codes, t_cumul_x * cumul_x, t_cumul_x2 * cumul_x2, + uint32 h, uint32 l, double * vrais, double * vrais_min, bool * move){ + + int interval = blockIdx.x ; + int seg = threadIdx.x ; + int thread = seg; + int id_nx, id_nprec, id_nprecprec, id_nsuiv, id_seg ; + int code_noeud; + __shared__ int64 s_stats_snake[3*8] ; + + id_nx = 2*interval + !pairs ; + if (id_nx == 0) id_nprec = nnodes - 1 ; + else id_nprec = id_nx - 1 ; + if (id_nprec == 0) id_nprecprec = nnodes -1 ; + else id_nprecprec = id_nprec - 1 ; + if (id_nx == nnodes-1) id_nsuiv = 0 ; + else id_nsuiv = id_nx + 1 ; + + //chargement en smem , prevoir CFI car on a 24x64bits par blocs => conflits + s_stats_snake[3*thread + 0] = d_stats_ref[3*id_nx] ; + s_stats_snake[3*thread + 1] = d_stats_ref[3*id_nx + 1] ; + s_stats_snake[3*thread + 2] = d_stats_ref[3*id_nx + 2] ; + + + //stats segments N1-Nx + id_seg = 16*interval + seg ; + if ( code_segment[id_seg] > 0 ){ + s_stats_snake[3*thread +0] += d_contribs[3*id_seg] ; + s_stats_snake[3*thread +1] += d_contribs[3*id_seg + 1 ] ; + s_stats_snake[3*thread +2] += d_contribs[3*id_seg + 2 ] ; + } else if ( code_segment[16*interval + seg] < 0 ) { + s_stats_snake[3*thread +0] -= d_contribs[3*id_seg] ; + s_stats_snake[3*thread +1] -= d_contribs[3*id_seg + 1] ; + s_stats_snake[3*thread +2] -= d_contribs[3*id_seg + 2] ; + } + + //stats noeud N1(i1,j1) + int fo_N1 = d_freemans[id_seg].z ; + int fi_Nprecprec = d_snake[id_nprecprec].freeman_in ; + int pos = d_snake[id_nprec].posi*l + d_snake[id_nprec].posj ; + + code_noeud = d_table_codes[fi_Nprecprec*8 + fo_N1]; + if (code_noeud > 0){ + s_stats_snake[3*thread +0] += 1 + d_snake[id_nprec].posj ; + s_stats_snake[3*thread +1] += cumul_x[ pos ] ; + s_stats_snake[3*thread +2] += cumul_x2[pos ] ; + } else if (code_noeud < 0){ + s_stats_snake[3*thread +0] -= 1 + d_snake[id_nprec].posj ; + s_stats_snake[3*thread +1] -= cumul_x[ pos ] ; + s_stats_snake[3*thread +2] -= cumul_x2[pos ] ; + } + + //stats noeud Nx + int fo_Nx = d_freemans[id_seg + 8].z ; + int fi_Nx = d_freemans[id_seg].w ; + int Nxi = d_liste_points[8*id_nx + seg].x ; + int Nxj = d_liste_points[8*id_nx + seg].y ; + pos = Nxi*l + Nxj ; + + code_noeud = d_table_codes[fi_Nx*8 + fo_Nx]; + if (code_noeud > 0){ + s_stats_snake[3*thread +0] += 1 + Nxj ; + s_stats_snake[3*thread +1] += cumul_x[ pos ] ; + s_stats_snake[3*thread +2] += cumul_x2[pos ] ; + } + if (code_noeud < 0){ + s_stats_snake[3*thread +0] -= 1 + Nxj ; + s_stats_snake[3*thread +1] -= cumul_x[ pos ] ; + s_stats_snake[3*thread +2] -= cumul_x2[pos ] ; + } + + //stats segments Nx-N2 + seg += 8; + id_seg = 16*interval + seg ; + if ( code_segment[id_seg] > 0 ){ + s_stats_snake[3*thread +0] += d_contribs[3*id_seg] ; + s_stats_snake[3*thread +1] += d_contribs[3*id_seg + 1] ; + s_stats_snake[3*thread +2] += d_contribs[3*id_seg + 2] ; + } + if ( code_segment[id_seg] < 0 ) { + s_stats_snake[3*thread +0] -= d_contribs[3*id_seg] ; + s_stats_snake[3*thread +1] -= d_contribs[3*id_seg + 1] ; + s_stats_snake[3*thread +2] -= d_contribs[3*id_seg + 2] ; + } + + //stats noeud N2(i2,j2) + int fi_N2 = d_freemans[id_seg].w ; + int fo_N2 = d_snake[id_nsuiv].freeman_out ; + pos = d_snake[id_nsuiv].posi*l + d_snake[id_nsuiv].posj ; + + code_noeud = d_table_codes[fi_N2*8 + fo_N2]; + if (code_noeud > 0){ + s_stats_snake[3*thread +0] += 1 + d_snake[id_nsuiv].posj ; + s_stats_snake[3*thread +1] += cumul_x[ pos ] ; + s_stats_snake[3*thread +2] += cumul_x2[pos ] ; + } + if (code_noeud < 0){ + s_stats_snake[3*thread +0] -= 1 + d_snake[id_nsuiv].posj ; + s_stats_snake[3*thread +1] -= cumul_x[ pos ] ; + s_stats_snake[3*thread +2] -= cumul_x2[pos ] ; + } + + //TODO + //voir si on peut s'en passer + d_stats[3*(8*interval + thread)] = s_stats_snake[3*thread +0]; + d_stats[3*(8*interval + thread) + 1] = s_stats_snake[3*thread +1]; + d_stats[3*(8*interval + thread) + 2] = s_stats_snake[3*thread +2]; + + //codage hyp gaussienne + uint64 stat_sum_xe[8] ; //somme des xn region exterieure + uint32 ne[8] ; // nombre de pixels region exterieure + double sigi2[8], sige2[8]; // carres des variances, regions interieure et exterieure + + /* variance des valeurs des niveaux de gris a l'interieur du snake */ + sigi2[thread] = + ((double)s_stats_snake[3*thread +2]/(double)s_stats_snake[3*thread +0]) - + ((double)s_stats_snake[3*thread +1]/s_stats_snake[3*thread +0])*((double)s_stats_snake[3*thread +1]/s_stats_snake[3*thread +0]) ; + + /* variance des valeurs des niveaux de gris a l'exterieur du snake */ + ne[thread] = h*l-s_stats_snake[3*thread +0] ; + stat_sum_xe[thread] = d_stats_snake[4] - s_stats_snake[3*thread +1] ; + sige2[thread] = + (double)(d_stats_snake[5]-s_stats_snake[3*thread +2])/(double)ne[thread] - + ((double)stat_sum_xe[thread]/ne[thread])*((double)stat_sum_xe[thread]/ne[thread]) ; + + if (sige2[thread]>0 && sigi2[thread]>0) + vrais[8*interval + thread] = 0.5*((double)s_stats_snake[3*thread]*log(sigi2[thread]) + (double)ne[thread]*log(sige2[thread])) ; + else + vrais[8*interval + thread] = -1.0; + + if ( thread == 0 ){ + //init move + move[id_nx] = false ; + int pos_optim = -1; + double vrais_tmp = *vrais_min; + for (int v=0; v < 8; v++){ + if ( (vrais[8*interval + v] > 0) && (vrais[8*interval + v] < vrais_tmp*COEF_DECROI) ) { + vrais_tmp = vrais[8*interval + v]; + pos_optim = v; + } + } + if (pos_optim >-1){ + if ( !croisement(d_snake, id_nx, d_liste_points[8*id_nx + pos_optim].x, d_liste_points[8*id_nx + pos_optim].y, nnodes) ) + { + /*maj data snake*/ + move[id_nx] = true ; + //new position + d_snake[id_nx].posi = d_liste_points[8*id_nx + pos_optim].x ; + d_snake[id_nx].posj = d_liste_points[8*id_nx + pos_optim].y ; + //nb pixels segment precedent + d_snake[id_nprec].nb_pixels = d_liste_points[8*id_nx + pos_optim].z ; + //nb pixels segment suivant + d_snake[id_nx].nb_pixels = d_liste_points[8*id_nx + pos_optim].w ; + //contribs segment precedent + d_snake[id_nprec].sum_1 = d_contribs[3*(16*interval + pos_optim)] ; + d_snake[id_nprec].sum_x = d_contribs[3*(16*interval + pos_optim) + 1] ; + d_snake[id_nprec].sum_x2 = d_contribs[3*(16*interval + pos_optim) + 2] ; + //contribs segment suivant + d_snake[id_nx].sum_1 = d_contribs[3*(16*interval + pos_optim + 8)] ; + d_snake[id_nx].sum_x = d_contribs[3*(16*interval + pos_optim + 8) + 1] ; + d_snake[id_nx].sum_x2 = d_contribs[3*(16*interval + pos_optim + 8) + 2] ; + //freemans segment precedent + d_snake[id_nprec].freeman_out = d_freemans[16*interval + pos_optim].z ; + d_snake[id_nprec].freeman_in = d_freemans[16*interval + pos_optim].w ; + //freemans segment suivant + d_snake[id_nx].freeman_out = d_freemans[16*interval + pos_optim + 8].z ; + d_snake[id_nx].freeman_in = d_freemans[16*interval + pos_optim + 8].w ; + //codes segment precedent + d_snake[id_nprec].code_segment = code_segment[16*interval + pos_optim] ; + //code segment suivant + d_snake[id_nx].code_segment = code_segment[16*interval + pos_optim + 8] ; + //centre segment precedent + d_snake[id_nprec].centre_i = d_freemans[16*interval + pos_optim ].x ; + d_snake[id_nprec].centre_j = d_freemans[16*interval + pos_optim ].y ; + //centre segment suivant + d_snake[id_nx].centre_i = d_freemans[16*interval + pos_optim + 8].x ; + d_snake[id_nx].centre_j = d_freemans[16*interval + pos_optim + 8].y ; + + } + } + } + + +} + +__global__ void recalcul_stats_snake(snake_node_gpu * d_snake, int nnodes, int64 * d_stats_snake, double * vrais_min, + t_cumul_x * cumul_x, t_cumul_x2 * cumul_x2, int * TABLE_CODAGE, uint32 l + ) +{ + + int id_nx, id_nprec, id_nprecprec ; + int code_noeud, code_segment, pos; + int64 s_stats_snake[3] ; + + //init stats en shared mem + s_stats_snake[0] = 0 ; + s_stats_snake[1] = 0 ; + s_stats_snake[2] = 0 ; + + + for (id_nx = 0; id_nx < nnodes; id_nx++) + { + if (id_nx == 0) id_nprec = nnodes - 1; + else id_nprec = id_nx - 1; + if (id_nprec == 0) id_nprecprec = nnodes -1 ; + else id_nprecprec = id_nprec - 1 ; + /* gestion des segments partant du noeud */ + /* vers le noeud suivant dans l'ordre trigo */ + code_segment = d_snake[id_nprec].code_segment ; + if (code_segment > 0) + { + /* on somme les contributions */ + s_stats_snake[0] += d_snake[id_nprec].sum_1 ; + s_stats_snake[1] += d_snake[id_nprec].sum_x ; + s_stats_snake[2] += d_snake[id_nprec].sum_x2 ; + } + else if (code_segment < 0) + { + /* on soustrait les contributions */ + s_stats_snake[0] -= d_snake[id_nprec].sum_1 ; + s_stats_snake[1] -= d_snake[id_nprec].sum_x ; + s_stats_snake[2] -= d_snake[id_nprec].sum_x2 ; + } + // else (code_segment == 0), on ne fait rien + /* gestion des pixels connectant les segments */ + pos = d_snake[id_nprecprec].freeman_in*8 + d_snake[id_nprec].freeman_out ; + code_noeud = TABLE_CODAGE[pos] ; + pos = d_snake[id_nprec].posi*l + d_snake[id_nprec].posj ; + + if (code_noeud > 0) + { + /* on somme les contributions */ + s_stats_snake[0] += 1 + d_snake[id_nprec].posj ; + s_stats_snake[1] += cumul_x[pos] ; + s_stats_snake[2] += cumul_x2[pos] ; + } + else if (code_noeud < 0) + { + /* on soustrait les contributions */ + s_stats_snake[0] -= 1 + d_snake[id_nprec].posj ; + s_stats_snake[1] -= cumul_x[pos] ; + s_stats_snake[2] -= cumul_x2[pos] ; + } + // else (code_pixel == 0), on ne fait rien + } + d_stats_snake[0] = s_stats_snake[0] ; + d_stats_snake[1] = s_stats_snake[1] ; + d_stats_snake[2] = s_stats_snake[2] ; + + *vrais_min = codage_gl_hyp_gauss(s_stats_snake[0], s_stats_snake[1], s_stats_snake[2], + d_stats_snake[3], d_stats_snake[4], d_stats_snake[5]); +} + + +__global__ void ajoute_noeuds(snake_node_gpu * snake, snake_node_gpu * snake_tmp, int nnodes, int seuil, int * new_nb_nodes){ + + volatile snake_node_gpu * st = snake_tmp ; + + int id_cpy = 0; + for (int id_nx=0; id_nx < nnodes; id_nx++){ + //position du noeud existant + st[id_cpy].posi = snake[id_nx].posi ; + st[id_cpy].posj = snake[id_nx].posj ; + + id_cpy++ ; + + if ( snake[id_nx].nb_pixels > seuil) + { + //position du nouveau noeud + st[id_cpy].posi = snake[id_nx].centre_i ; + st[id_cpy].posj = snake[id_nx].centre_j ; + id_cpy++ ; + } + } + for( int node=0; node= nb_nodes) n2 = 0 ; + + //affectation des differentes positions aux différents segments 'blocs de threads' + x1 = d_snake[n1].posj ; + y1 = d_snake[n1].posi ; + x2 = d_snake[n2].posj ; + y2 = d_snake[n2].posi ; + + //params des deplacements + int dx=x2-x1; + int dy=y2-y1; + uint abs_dx = ABS(dx); + uint abs_dy = ABS(dy); + uint nb_pix = abs_dy>abs_dx?(abs_dy+1):(abs_dx+1); // alternative -> lecture ds liste_points[] + int incx=0, incy=0; + + + //calcul liste des pixels du segment (x1,y1)-(x2,y2) + if (dy > 0) incy=1; else incy=-1 ; + if (dx > 0) incx=1; else incx=-1 ; + + if (tis < nb_pix){ + if (abs_dy > abs_dx){ + //1 thread par ligne + double k = (double)dx/dy ; + p.x = y1 + incy*tis ; + p.y = x1 + floor((double)incy*k*tis+0.5) ; + + } else { + //1 thread par colonne + double k=(double)dy/dx ; + p.x = y1 + floor((double)(incx*k*tis)+0.5) ; + p.y = x1 + incx*tis ; + if ( tis > 0 ){ + xsuiv = y1 + floor((double)(incx*k*(tis+1))+0.5) ; + xprec = y1 + floor((double)(incx*k*(tis-1))+0.5) ; + } + + } + if (tis == 0) liste_pix[5*segment] = make_uint2(p.x, p.y) ; + if (tis == 1) liste_pix[5*segment +1] = make_uint2(p.x,p.y) ; + if (tis == nb_pix/2) liste_pix[5*segment +2] = make_uint2(p.x,p.y) ; + if (tis == nb_pix-2) liste_pix[5*segment +3] = make_uint2(p.x,p.y) ; + if (tis == nb_pix-1) liste_pix[5*segment +4] = make_uint2(p.x,p.y) ; + + } + __syncthreads(); + + //calcul contribs individuelles des pixels + + if ( (tis >0) && (tis < nb_pix-1) + && ( ( (abs_dy <= abs_dx) && ( ( xprec > p.x) || ( xsuiv > p.x)) ) + || (abs_dy > abs_dx) ) ) + { + int pos = p.x * l + p.y ; + scumuls[ CFI(tib)].c1 = 1+p.y; + scumuls[ CFI(tib)].cx = cumul_x[ pos ] ; + scumuls[CFI(tib)].cx2 = cumul_x2[ pos ]; + } else { + scumuls[ CFI(tib)].c1 = 0; + scumuls[ CFI(tib)].cx = 0; + scumuls[CFI(tib)].cx2 = 0; + } + + __syncthreads(); + //somme des contribs individuelles + // unroll des sommes partielles en smem + + if (blockSize >= 512) { + if (tib < 256) { + scumuls[ CFI(tib)].c1 += scumuls[ CFI(tib + 256) ].c1; + scumuls[ CFI(tib)].cx += scumuls[ CFI(tib + 256) ].cx; + scumuls[CFI(tib)].cx2 += scumuls[CFI(tib + 256) ].cx2; + } + __syncthreads(); + } + + if (blockSize >= 256) { + if (tib < 128) { + scumuls[ CFI(tib)].c1 += scumuls[ CFI(tib + 128) ].c1; + scumuls[ CFI(tib)].cx += scumuls[ CFI(tib + 128) ].cx; + scumuls[CFI(tib)].cx2 += scumuls[CFI(tib + 128) ].cx2; + } + __syncthreads(); + } + if (blockSize >= 128) { + if (tib < 64) { + scumuls[ CFI(tib)].c1 += scumuls[ CFI(tib + 64) ].c1; + scumuls[ CFI(tib)].cx += scumuls[ CFI(tib + 64) ].cx; + scumuls[CFI(tib)].cx2 += scumuls[ CFI(tib + 64) ].cx2; + } + __syncthreads(); + } + + //32 threads <==> 1 warp + volatile tcontribs * scontribs = scumuls ; + if (tib < 32) + { + { + scontribs[ CFI(tib)].c1 += scontribs[ CFI(tib + 32) ].c1; + scontribs[ CFI(tib)].cx += scontribs[ CFI(tib + 32) ].cx; + scontribs[ CFI(tib)].cx2 +=scontribs[ CFI(tib + 32) ].cx2; + } + if (tib<16) + { + scontribs[ CFI(tib)].c1 += scontribs[ CFI(tib + 16) ].c1; + scontribs[ CFI(tib)].cx += scontribs[ CFI(tib + 16) ].cx; + scontribs[ CFI(tib)].cx2 +=scontribs[ CFI(tib + 16) ].cx2; + } + if (tib<8) + { + scontribs[ CFI(tib)].c1 += scontribs[ CFI(tib + 8) ].c1; + scontribs[ CFI(tib)].cx += scontribs[ CFI(tib + 8) ].cx; + scontribs[ CFI(tib)].cx2 +=scontribs[ CFI(tib + 8) ].cx2;} + if (tib<4){ + scontribs[ CFI(tib)].c1 += scontribs[ CFI(tib + 4) ].c1; + scontribs[ CFI(tib)].cx += scontribs[ CFI(tib + 4) ].cx; + scontribs[ CFI(tib)].cx2 +=scontribs[ CFI(tib + 4) ].cx2; + } + if (tib<2){ + scontribs[ CFI(tib)].c1 += scontribs[ CFI(tib + 2) ].c1; + scontribs[ CFI(tib)].cx += scontribs[ CFI(tib + 2) ].cx; + scontribs[ CFI(tib)].cx2 +=scontribs[ CFI(tib + 2) ].cx2; + } + if (tib==0){ + scontribs[ CFI(tib)].c1 += scontribs[ CFI(tib + 1) ].c1; + scontribs[ CFI(tib)].cx += scontribs[ CFI(tib + 1) ].cx; + scontribs[ CFI(tib)].cx2 +=scontribs[ CFI(tib + 1) ].cx2; + // resultat sommes partielles en gmem + //if (tib == 0) { + gsombloc[ blockIdx.x ] = scontribs[0].c1; + gsombloc[ blockIdx.x + gridDim.x ] = scontribs[0].cx; + gsombloc[ blockIdx.x + 2*gridDim.x ] = scontribs[0].cx2; + + //calculs code segment + //code seg + if (dy > 0 ) d_snake[segment].code_segment = -1 ; + if (dy < 0 ) d_snake[segment].code_segment = 1 ; + if (dy == 0) d_snake[segment].code_segment = 0 ; + } + } +} + +__global__ void recalcul_freemans_centre(snake_node_gpu * snake, uint2 * liste_pix, int * d_table_freeman){ + + int id_segment = blockIdx.x ; + int id_base_pix = 5*id_segment ; + + //calculs freemans, centre et code segment + //1 uint4 par segment + int Dio, Djo, Dii, Dji; + + //freeman out + Dio = 1 + liste_pix[id_base_pix +1].x - liste_pix[id_base_pix].x ; + Djo = 1 + liste_pix[id_base_pix +1].y - liste_pix[id_base_pix].y ; + snake[id_segment].freeman_out = d_table_freeman[3*Dio + Djo] ; + + //freeman_in + Dii = 1 + liste_pix[id_base_pix +4].x - liste_pix[id_base_pix +3].x ; + Dji = 1 + liste_pix[id_base_pix +4].y - liste_pix[id_base_pix +3].y ; + snake[id_segment].freeman_in = d_table_freeman[3*Dii + Dji] ; + + //centre + snake[id_segment].centre_i = liste_pix[id_base_pix +2].x ; + snake[id_segment].centre_j = liste_pix[id_base_pix +2].y ; + +} + + +/* + sommme des contribs par bloc -> contribs segment, pour le snake + + execution sur : 1bloc / 1 thread par segment + */ + +__global__ void resomsom_snake(uint64 * somblocs, int nb_nodes, unsigned int nb_bl_seg, snake_node_gpu * d_snake){ + + uint64 sdata[3]; + unsigned int seg = blockIdx.x ; + + //un thread par segment + { + sdata[0] = 0; + sdata[1] = 0; + sdata[2] = 0; + } + + for (int b=0; b < nb_bl_seg ; b++){ + sdata[0] += somblocs[seg*nb_bl_seg + b]; + sdata[1] += somblocs[(seg + nb_nodes)*nb_bl_seg + b]; + sdata[2] += somblocs[(seg + 2*nb_nodes)*nb_bl_seg + b]; + } + + //totaux en gmem + { + d_snake[seg].sum_1 = sdata[0]; + d_snake[seg].sum_x = sdata[1]; + d_snake[seg].sum_x2 = sdata[2]; + } +} + diff --git a/src/lib_kernels_contribs.h b/src/lib_kernels_contribs.h new file mode 100644 index 0000000..486b0ba --- /dev/null +++ b/src/lib_kernels_contribs.h @@ -0,0 +1,33 @@ +#ifndef __KERNEL_CONTRIB__ +#define __KERNEL_CONTRIB__ + +__global__ void liste_positions_a_tester(snake_node_gpu * d_snake, uint4 * liste_positions, uint32 * nb_pix_max, + int pas, int nb_nodes, int h, int l); +__global__ void calcul_contribs_segments_snake(snake_node_gpu * d_snake, int nb_nodes, + uint64 * cumul_1, uint64 * cumul_x, uint64 * cumul_x2, + int l, uint2 * liste_pix, uint64 * gsombloc, int * d_table_freeman); + +__global__ void somsom_snake(uint64 * somblocs, int nb_nodes, unsigned int nb_bl_seg, snake_node_gpu * d_snake); + + +__global__ void calcul_contribs_segments_blocs_full(snake_node_gpu * d_snake, int nb_nodes, uint4 * liste_points, uint32 npix_max, + uint64 * cumul_1, uint64 * cumul_x, uint64 * cumul_x2, int * d_codes_x16, + int l, uint2 * liste_pix, uint64 * gsombloc, int * d_table_freeman, + uint4 * d_freemans_x16, bool pairs); + +__global__ void somsom_full(uint64 * somblocs, int nb_nodes, unsigned int nb_bl_seg, uint64 * somsom, bool pairs); +__device__ bool test_inf_gpu(double arg1, double arg2); + +__global__ void calcul_stats_snake(snake_node_gpu * d_snake, int nnodes, int64 * d_stats_snake, double * vrais_min, + uint64 * cumul_1, uint64 * cumul_x, uint64 * cumul_x2, int * TABLE_CODAGE, uint32 l); + +__global__ void soustrait_aux_stats_2N_segments_noeud(snake_node_gpu * d_snake, int64 * d_stats_snake, int64 * d_stats_ref, + uint64 * cumul_1, uint64 * cumul_x, uint64 * cumul_x2, + int * TABLE_CODAGE, uint32 l); + +__global__ void calcul_stats_full(snake_node_gpu * d_snake, int nnodes, bool pairs, int64 * d_stats_snake, + int64 * d_stats_ref, int64 * d_stats, uint64 * d_contribs, + uint4 * d_liste_points, int * code_segment, uint4 * d_freemans, + int * d_table_codes, uint64 * cumul_1, uint64 * cumul_x, uint64 * cumul_x2, + uint32 h, uint32 l, double * vrais, double * vrais_min, bool * move); +#endif // __KERNEL_CONTRIB__ diff --git a/src/lib_kernels_cumuls.cu b/src/lib_kernels_cumuls.cu new file mode 100644 index 0000000..641a0ff --- /dev/null +++ b/src/lib_kernels_cumuls.cu @@ -0,0 +1,233 @@ + + + +__global__ void calcul_cumuls_gpu(unsigned short * img, t_cumul_x * cumul_x, t_cumul_x2 * cumul_x2, uint32 h, uint32 l, uint64 * gsomblocs, unsigned int N_BLOCS_LIGNE, unsigned int baseline, unsigned int nb_lines ) +{ + int bs = blockDim.x ; + int offsetSom = N_BLOCS_LIGNE * nb_lines; //indice du premier element de cumul_x2 dans le tableau + + int tib = threadIdx.x ; //indice du thread dans le bloc + int idx = blockIdx.x*bs + tib ; //indice global du thread dans la portion d'image + int num_ligne = blockIdx.x / N_BLOCS_LIGNE ; //indice de la ligne du thread dans la portion d'image + int til = idx - num_ligne*bs*N_BLOCS_LIGNE ; //indice du thread ds la ligne + int pos = num_ligne*l + til ; //indice du pixel dans la 'tranche' courante + int pos_img = pos + baseline*l ; //indice correspondant dans l'image originale + int id, stride=1; + + extern __shared__ tcumuls sdata[]; + //chargement en smem avec complement de 0 + id = CFI(tib); + if (til < l){ + sdata[id].x = img[ pos_img ] ; + sdata[id].x2 = img[ pos_img ]*img[ pos_img ] ; + } else { + sdata[id].x = 0 ; + sdata[id].x2 = 0 ; + } + /* + *prefix sum en smem + */ + //passe 1 : construction des sommes + + for (int d = bs/2; d > 0; d >>= 1) + { + __syncthreads(); + + if (tib < d) + { + int i = __mul24(__mul24(2, stride), tib); + int ai = i + stride - 1; + int bi = CFI(ai + stride); + + ai = CFI(ai); + //bi = CFI(bi); + + sdata[bi].x += sdata[ai].x; + sdata[bi].x2 += sdata[ai].x2; + + } + stride *= 2; + } + + //stockage somme du bloc en gmem + // et + //mise a zero dernier element du bloc + + __syncthreads(); + + if (tib == bs-1) { + t_cumul_x som_x = sdata[CFI(tib)].x; + t_cumul_x2 som_x2 = sdata[CFI(tib)].x2; + if (til < l){ //il ne faut pas ecrire de somme dans le dernier bloc, elle serait hors image + cumul_x[ pos_img ] = som_x; + cumul_x2[pos_img ] = som_x2; + } + gsomblocs[blockIdx.x] = som_x; + gsomblocs[blockIdx.x + offsetSom] = som_x2; + sdata[CFI(tib)].x = 0; + sdata[CFI(tib)].x2 = 0; + } + + //Passe 2 : construction des scans + for (int d = 1; d <= (bs/2); d *= 2) + { + stride >>= 1; + __syncthreads(); + + if (tib < d) + { + int i = __mul24(__mul24(2, stride), tib); + int ai = i + stride - 1; + int bi = CFI(ai + stride); + + ai = CFI(ai); + //bi = CFI(bi); + + t_cumul_x tx = sdata[ai].x; + t_cumul_x2 tx2 = sdata[ai].x2; + + sdata[ai].x = sdata[bi].x; + sdata[bi].x += tx; + + sdata[ai].x2 = sdata[bi].x2; + sdata[bi].x2 += tx2; + } + } + + //transfert en gmem des scans + //il faut décaler à gauche de 1 element + __syncthreads(); + if ( (til < l) && ( tib < (bs-1) ) ){ + cumul_x[ pos_img ] = sdata[CFI(tib+1)].x; + cumul_x2[pos_img ] = sdata[CFI(tib+1)].x2; + } + +} + + + +/* + kernel pour faire le prefixsum des sommes de blocs des lignes de l'image + les params d'executions kivonbien sont : + - threads : la moitié de la nextpow2 du nb de blocs par ligne + - grid : 2 x le nombre de blocs de sommes dans l'image , soit le nb_blocs_par_ligne x nb_lignes x 2 + - shared mem : 2 x nextPow2(nb_blocs par ligne) +*/ + + + +__global__ void scan_somblocs(uint64 * g_idata, int n_bl_l){ + + extern __shared__ uint64 temp[]; + + int tib = threadIdx.x; + int toff = blockIdx.x*n_bl_l; // offset des positions des sommes partielles dans le tableau g_idata + int nmax = blockDim.x*2; //nb max de sommes partielles par ligne + + + int aai = tib; + int bbi = tib + blockDim.x; + + + // chargement data en smem + temp[ CFI(aai) ] = (aai < n_bl_l)? g_idata[ toff + aai ] : 0; + temp[ CFI(bbi) ] = (bbi < n_bl_l)? g_idata[ toff + bbi ] : 0; + + int offset = 1; + + // passe 1 de bas en haut + for (int d = nmax/2; d > 0; d >>= 1) + { + __syncthreads(); + + if (tib < d) + { + int ai = CFI(offset*(2*tib+1)-1); + int bi = CFI(offset*(2*tib+2)-1); + + temp[bi] += temp[ai]; + } + + offset *= 2; + } + + // zero le dernier element + __syncthreads(); + if (tib == 0) + { + int index = CFI(nmax - 1); + g_idata[ toff + n_bl_l - 1 ] = temp[ index ]; //memorisation de la somme du bloc a sa place en gmem + temp[index] = 0; + } + + // passe 2 de haut en bas + for (int d = 1; d < nmax; d *= 2) + { + offset /= 2; + + __syncthreads(); + + if (tib < d) + { + int ai = CFI(offset*(2*tib+1)-1); + int bi = CFI(offset*(2*tib+2)-1); + + uint64 t = temp[ai]; + temp[ai] = temp[bi]; + temp[bi] += t; //tester atomicadd 64 bits + } + + } + + __syncthreads(); + + // transfert resultats en gmem decales d'un element vers la gauche + g_idata[ toff + aai ] = temp[ CFI(aai + 1) ]; //pour le demi tableau smem inferieur + if ( bbi < n_bl_l-1 ) g_idata[ toff + bbi ] = temp[CFI( bbi + 1) ]; //demi tableau smem sup. sauf dernier=somme. + +} + + +__global__ void add_soms_to_cumuls(t_cumul_x * cumul_x, t_cumul_x2 * cumul_x2, uint32 h, uint32 l, uint64 * gsomblocs, + unsigned int N_BLOCS_LIGNE, unsigned int baseline, unsigned int nb_lines){ + + int bs = blockDim.x ; + int offsetSom = N_BLOCS_LIGNE * nb_lines; + int tib = threadIdx.x ; //indice du thread dans le bloc + int idx = blockIdx.x*blockDim.x + tib ; //indice global du thread + int num_ligne = blockIdx.x / N_BLOCS_LIGNE ; //indice de la ligne du thread dans l'image partielle + int til = idx - num_ligne*bs*N_BLOCS_LIGNE ; //indice du thread ds la ligne + int pos = num_ligne*l + til; + int pos_img = pos + baseline*l ; + + + //chargement des valeurs a ajouter en smem 0<-->x et 1<-->x2 + uint64 __shared__ ajout[2]; + + if ( til >= bs ){ + ajout[0] = gsomblocs[blockIdx.x -1 ]; + ajout[1] = gsomblocs[blockIdx.x -1 + offsetSom]; + __syncthreads(); //tester les nouveaux __sync__ + + //addition par bloc + if (til < l) { + cumul_x[pos_img] += ajout[0]; + cumul_x2[pos_img]+= ajout[1]; + } + } +} + +//calcul des SUM_1, SUM_X et SUM_X2 de l'image + +__global__ void calcul_stats_image( t_cumul_x * cumul_x, t_cumul_x2 * cumul_x2, uint32 h, uint32 l, uint64 * d_stats_snake){ + uint64 sigX = 0, sigX2 = 0 ; + for (int i=l-1; i 0; d >>= 1) + { + __syncthreads(); + + if (tib < d) + { + int i = __mul24(__mul24(2, stride), tib); + int ai = i + stride - 1; + int bi = CFI(ai + stride); + + ai = CFI(ai); + //bi = CFI(bi); + + sdata[bi].x += sdata[ai].x; + sdata[bi].x2 += sdata[ai].x2; + + } + stride *= 2; + } + + //stockage somme du bloc en gmem + // et + //mise a zero dernier element du bloc + + __syncthreads(); + + if (tib == bs-1) { + t_cumul_x som_x = sdata[CFI(tib)].x; + t_cumul_x2 som_x2 = sdata[CFI(tib)].x2; + if (til < l){ //il ne faut pas ecrire de somme dans le dernier bloc, elle serait hors image + cumul_x[ pos_img ] = som_x; + cumul_x2[pos_img ] = som_x2; + } + gsomblocs[blockIdx.x] = som_x; + gsomblocs[blockIdx.x + offsetSom] = som_x2; + sdata[CFI(tib)].x = 0; + sdata[CFI(tib)].x2 = 0; + } + + //Passe 2 : construction des scans + for (int d = 1; d <= (bs/2); d *= 2) + { + stride >>= 1; + __syncthreads(); + + if (tib < d) + { + int i = __mul24(__mul24(2, stride), tib); + int ai = i + stride - 1; + int bi = CFI(ai + stride); + + ai = CFI(ai); + //bi = CFI(bi); + + t_cumul_x tx = sdata[ai].x; + t_cumul_x2 tx2 = sdata[ai].x2; + + sdata[ai].x = sdata[bi].x; + sdata[bi].x += tx; + + sdata[ai].x2 = sdata[bi].x2; + sdata[bi].x2 += tx2; + } + } + + //transfert en gmem des scans + //il faut décaler à gauche de 1 element + __syncthreads(); + if ( (til < l) && ( tib < (bs-1) ) ){ + cumul_x[ pos_img ] = sdata[CFI(tib+1)].x; + cumul_x2[pos_img ] = sdata[CFI(tib+1)].x2; + } + +} + + + +/* + kernel pour faire le prefixsum des sommes de blocs des lignes de l'image + les params d'executions kivonbien sont : + - threads : la moitié de la nextpow2 du nb de blocs par ligne + - grid : 2 x le nombre de blocs de sommes dans l'image , soit le nb_blocs_par_ligne x nb_lignes x 2 + - shared mem : 2 x nextPow2(nb_blocs par ligne) +*/ + + + +__global__ void scan_somblocs(uint64 * g_idata, int n_bl_l){ + + extern __shared__ uint64 temp[]; + + int tib = threadIdx.x; + int toff = blockIdx.x*n_bl_l; // offset des positions des sommes partielles dans le tableau g_idata + int nmax = blockDim.x*2; //nb max de sommes partielles par ligne + + + int aai = tib; + int bbi = tib + blockDim.x; + + + // chargement data en smem + temp[ CFI(aai) ] = (aai < n_bl_l)? g_idata[ toff + aai ] : 0; + temp[ CFI(bbi) ] = (bbi < n_bl_l)? g_idata[ toff + bbi ] : 0; + + int offset = 1; + + // passe 1 de bas en haut + for (int d = nmax/2; d > 0; d >>= 1) + { + __syncthreads(); + + if (tib < d) + { + int ai = CFI(offset*(2*tib+1)-1); + int bi = CFI(offset*(2*tib+2)-1); + + temp[bi] += temp[ai]; + } + + offset *= 2; + } + + // zero le dernier element + __syncthreads(); + if (tib == 0) + { + int index = CFI(nmax - 1); + g_idata[ toff + n_bl_l - 1 ] = temp[ index ]; //memorisation de la somme du bloc a sa place en gmem + temp[index] = 0; + } + + // passe 2 de haut en bas + for (int d = 1; d < nmax; d *= 2) + { + offset /= 2; + + __syncthreads(); + + if (tib < d) + { + int ai = CFI(offset*(2*tib+1)-1); + int bi = CFI(offset*(2*tib+2)-1); + + uint64 t = temp[ai]; + temp[ai] = temp[bi]; + temp[bi] += t; //tester atomicadd 64 bits + } + + } + + __syncthreads(); + + // transfert resultats en gmem decales d'un element vers la gauche + g_idata[ toff + aai ] = temp[ CFI(aai + 1) ]; //pour le demi tableau smem inferieur + if ( bbi < n_bl_l-1 ) g_idata[ toff + bbi ] = temp[CFI( bbi + 1) ]; //demi tableau smem sup. sauf dernier=somme. + +} + + +__global__ void add_soms_to_cumuls(t_cumul_x * cumul_x, t_cumul_x2 * cumul_x2, uint32 h, uint32 l, uint64 * gsomblocs, + unsigned int N_BLOCS_LIGNE, unsigned int baseline, unsigned int nb_lines){ + + int bs = blockDim.x ; + int offsetSom = N_BLOCS_LIGNE * nb_lines; + int tib = threadIdx.x ; //indice du thread dans le bloc + int idx = blockIdx.x*blockDim.x + tib ; //indice global du thread + int num_ligne = blockIdx.x / N_BLOCS_LIGNE ; //indice de la ligne du thread dans l'image partielle + int til = idx - num_ligne*bs*N_BLOCS_LIGNE ; //indice du thread ds la ligne + int pos = num_ligne*l + til; + int pos_img = pos + baseline*l ; + + + //chargement des valeurs a ajouter en smem 0<-->x et 1<-->x2 + uint64 __shared__ ajout[2]; + + if ( til >= bs ){ + ajout[0] = gsomblocs[blockIdx.x -1 ]; + ajout[1] = gsomblocs[blockIdx.x -1 + offsetSom]; + __syncthreads(); //tester les nouveaux __sync__ + + //addition par bloc + if (til < l) { + cumul_x[pos_img] += ajout[0]; + cumul_x2[pos_img]+= ajout[1]; + } + } +} + +//calcul des SUM_1, SUM_X et SUM_X2 de l'image + +__global__ void calcul_stats_image( t_cumul_x * cumul_x, t_cumul_x2 * cumul_x2, uint32 h, uint32 l, uint64 * d_stats_snake){ + uint64 sigX = 0, sigX2 = 0 ; + for (int i=l-1; i 0)? (nx - 1):(nb_nodes - 1); + nsuiv = (nx < nb_nodes - 1)? (nx + 1):(0); +} + +__device__ double codage_niveau_gris_hyp_gaussienne_gpu(uint32 stat_sum_1, uint64 stat_sum_x, + uint64 stat_sum_x2, uint32 n_dim, + uint64 SUM_X, uint64 SUM_X2) +{ + uint64 stat_sum_xe ; /* somme des xn region exterieure */ + uint32 ne ; /* nombre de pixel region exterieure */ + double sigi2, sige2; /* variance region interieure et exterieure */ + + /* variance des valeurs des niveaux de gris a l'interieur du snake */ + sigi2 = + (double)stat_sum_x2/(double)stat_sum_1 - + (double)(stat_sum_x*stat_sum_x)/(double)((uint64)stat_sum_1*(uint64)stat_sum_1) ; + + /* variance des valeurs des niveaux de gris a l'exterieur du snake */ + ne = n_dim-stat_sum_1 ; + stat_sum_xe = SUM_X - stat_sum_x ; + sige2 = + (double)(SUM_X2-stat_sum_x2)/(double)ne - + (double)(stat_sum_xe*stat_sum_xe)/(double)((uint64)ne*(uint64)ne) ; + + if ((sigi2 <= 0)|(sige2 <= 0)) return -1; + + return 0.5*((double)stat_sum_1*log(sigi2) + (double)ne*log(sige2)) ; +} + +__device__ double codage_gl_hyp_gaussienne(uint64 stat_sum_1, uint64 stat_sum_x, uint64 stat_sum_x2, + uint64 n_dim, uint64 SUM_X, uint64 SUM_X2){ + uint64 stat_sum_xe ; /* somme des xn region exterieure */ + uint32 ne ; /* nombre de pixel region exterieure */ + double sigi2, sige2; /* variance region interieure et exterieure */ + + /* variance des valeurs des niveaux de gris a l'interieur du snake */ + sigi2 = + (double)stat_sum_x2/(double)stat_sum_1 - + (double)(stat_sum_x*stat_sum_x)/(double)((uint64)stat_sum_1*(uint64)stat_sum_1) ; + + /* variance des valeurs des niveaux de gris a l'exterieur du snake */ + ne = n_dim-stat_sum_1 ; + stat_sum_xe = SUM_X - stat_sum_x ; + sige2 = + (double)(SUM_X2-stat_sum_x2)/(double)ne - + (double)(stat_sum_xe*stat_sum_xe)/(double)((uint64)ne*(uint64)ne) ; + + if ((sigi2 > 0)|(sige2 > 0)) + return 0.5*((double)stat_sum_1*log(sigi2) + (double)ne*log(sige2)) ; + return -1 ; +} + +__device__ inline unsigned int nextPow2_gpu( unsigned int x ) { + --x; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return ++x; +} + + +__device__ inline int sign_diff_strict(int val1, int val2) +{ + if (val1 > 0) + { + if (val2 >= 0) return 0 ; + else return 1 ; + } + else + if (val1 < 0) + { + if (val2 <= 0) return 0 ; + else return 1 ; + } + else + return 0 ;/* val1 == 0 */ +} + +__device__ inline int sign_diff_ou_egal_zero(int val1, int val2) +{ + if (val1 > 0) + { + if (val2 > 0) return 0 ; + else return 1 ; + } + else + if (val1 < 0) + { + if (val2 < 0) return 0 ; + else return 1 ; + } + else + return 1 ;/* val1 == 0 */ +} + + +__device__ int sinus_triangle(int Ai, int Aj, int Bi, int Bj, int Ci, int Cj) +{ + return (((Bi-Ai)*(Cj-Aj)) - ((Ci-Ai)*(Bj-Aj))) ; +} + +__device__ int test_croisement_large(uint32 Ai, uint32 Aj, uint32 Bi, uint32 Bj, + uint32 Ui, uint32 Uj, uint32 Vi, uint32 Vj) +{ + if (sign_diff_strict(sinus_triangle(Ai, Aj, Bi, Bj, Ui, Uj), // Bi-Ai, Uj-Aj, Ui-Ai, Bj-Aj + sinus_triangle(Ai, Aj, Bi, Bj, Vi, Vj))) // Bi-Ai, Vj-Aj, Vi-Ai, Bj-Aj + if (sign_diff_strict(sinus_triangle(Ui, Uj, Vi, Vj, Ai, Aj), // Vi-Ui, Aj-Uj, Ai-Ui, Vj-Uj + sinus_triangle(Ui, Uj, Vi, Vj, Bi, Bj))) // Vi-Ui, Bj-Uj, Bi-Ui, Vj-Uj + return 1 ; + return 0 ; +} + +__device__ int test_croisement_strict(uint32 Ai, uint32 Aj, uint32 Bi, uint32 Bj, + uint32 Ui, uint32 Uj, uint32 Vi, uint32 Vj ) +{ + if (sign_diff_ou_egal_zero(sinus_triangle(Ai, Aj, Bi, Bj, Ui, Uj), + sinus_triangle(Ai, Aj, Bi, Bj, Vi, Vj))) + if (sign_diff_ou_egal_zero(sinus_triangle(Ui, Uj, Vi, Vj, Ai, Aj), + sinus_triangle(Ui, Uj, Vi, Vj, Bi, Bj))) + return 1 ; + return 0 ; +} + +__global__ void kernel_test_croisement_move_seg_strict(struct snake_node_gpu *d_snake, uint32 nx, uint32 Nxi, uint32 Nxj, int Nb_nodes, bool * croist) +{ + int idx = blockDim.x*blockIdx.x + threadIdx.x, idx_prec, idx_suiv ; + int na, nb, naa, nbb ; + int Nai, Naj, Nbi, Nbj ; + bool croistil = false ; + + calcul_indices_prec_suiv(Nb_nodes, nx, na, nb); + calcul_indices_prec_suiv(Nb_nodes, na, naa, nbb); + + //coord. nodes extremites des segments a tester + Nai = d_snake[na].posi ; + Naj = d_snake[na].posj ; + Nbi = d_snake[nb].posi ; + Nbj = d_snake[nb].posj ; + + if (idx == nb) //premier segment apres + { + calcul_indices_prec_suiv(Nb_nodes, idx, idx_prec, idx_suiv); + if ( test_croisement_large(Nxi, Nxj, Nbi, Nbj, + Nbi, Nbj, d_snake[idx_suiv].posi, d_snake[idx_suiv].posj)) + croistil = true ; + else if ( test_croisement_strict(Nai, Naj, Nxi, Nxj, + Nbi, Nbj, d_snake[idx_suiv].posi, d_snake[idx_suiv].posj) ) + croistil = true ; + } + else if ( idx == naa ) //premier segment avant + { + if ( test_croisement_large(d_snake[naa].posi, d_snake[naa].posj, Nai, Naj, + Nai, Naj, Nxi, Nxj) ) + croistil = true ; + else if ( test_croisement_strict(d_snake[naa].posi, d_snake[naa].posj, Nai, Naj, + Nxi, Nxj, Nbi, Nbj)) + croistil = true ; + } + else if ( (idx != nx) && (idx != na) ) //les autres segments + { + calcul_indices_prec_suiv(Nb_nodes, idx, idx_prec, idx_suiv); + if ( test_croisement_strict(Nai, Naj, Nxi, Nxj, + d_snake[idx].posi, d_snake[idx].posj, + d_snake[idx_suiv].posi, d_snake[idx_suiv].posj) ) + croistil = true ; + else if ( test_croisement_strict(Nxi, Nxj, Nbi, Nbj, + d_snake[idx].posi, d_snake[idx].posj, + d_snake[idx_suiv].posi, d_snake[idx_suiv].posj) ) + croistil = true ; + } + + croist[idx] = croistil ; +} + +__device__ bool croisement(snake_node_gpu *d_snake, uint32 nx, uint32 Nxi, uint32 Nxj, int Nb_nodes) +{ + int idx_prec, idx_suiv ; + int na, nb, naa, nbb ; + int Nai, Naj, Nbi, Nbj ; + bool croistil = false ; + + //coord. nodes extremites des segments a tester + calcul_indices_prec_suiv(Nb_nodes, nx, na, nb); + calcul_indices_prec_suiv(Nb_nodes, na, naa, nbb); + + Nai = d_snake[na].posi ; + Naj = d_snake[na].posj ; + Nbi = d_snake[nb].posi ; + Nbj = d_snake[nb].posj ; + + //parcours du snake + for (int idx=0; idx < Nb_nodes; idx++){ + if (idx == nb) //premier segment apres + { + calcul_indices_prec_suiv(Nb_nodes, idx, idx_prec, idx_suiv); + if ( test_croisement_large(Nxi, Nxj, Nbi, Nbj, Nbi, Nbj, d_snake[idx_suiv].posi, d_snake[idx_suiv].posj) ) + { + croistil = true ; + break ; + } + if ( test_croisement_strict(Nai, Naj, Nxi, Nxj, Nbi, Nbj, d_snake[idx_suiv].posi, d_snake[idx_suiv].posj) ) + { + croistil = true ; + break ; + } + } + if ( idx == naa ) //premier segment avant + { + if ( test_croisement_large(d_snake[naa].posi, d_snake[naa].posj, Nai, Naj, Nai, Naj, Nxi, Nxj) ) + { + croistil = true ; + break ; + } + if ( test_croisement_strict(d_snake[naa].posi, d_snake[naa].posj, Nai, Naj, Nxi, Nxj, Nbi, Nbj)) + { + croistil = true ; + break ; + } + } + if ( (idx != nx) && (idx != na) && (idx != nb) && (idx != naa) ) //les autres segments + { + calcul_indices_prec_suiv(Nb_nodes, idx, idx_prec, idx_suiv); + if ( test_croisement_strict(Nai, Naj, Nxi, Nxj, + d_snake[idx].posi, d_snake[idx].posj, + d_snake[idx_suiv].posi, d_snake[idx_suiv].posj) ) + { + croistil = true ; + break ; + } + if ( test_croisement_strict(Nxi, Nxj, Nbi, Nbj, + d_snake[idx].posi, d_snake[idx].posj, + d_snake[idx_suiv].posi, d_snake[idx_suiv].posj) ) + { + croistil = true ; + break ; + } + } + } + return croistil; +} diff --git a/src/lib_kernels_maths.cu~ b/src/lib_kernels_maths.cu~ new file mode 100644 index 0000000..c98f3bc --- /dev/null +++ b/src/lib_kernels_maths.cu~ @@ -0,0 +1,226 @@ + +__device__ void calcul_indices_prec_suiv(int nb_nodes, int nx, int& nprec, int& nsuiv){ + nprec = (nx > 0)? (nx - 1):(nb_nodes - 1); + nsuiv = (nx < nb_nodes - 1)? (nx + 1):(0); +} + +__device__ double codage_niveau_gris_hyp_gaussienne_gpu(uint32 stat_sum_1, uint64 stat_sum_x, + uint64 stat_sum_x2, uint32 n_dim, + uint64 SUM_X, uint64 SUM_X2) +{ + uint64 stat_sum_xe ; /* somme des xn region exterieure */ + uint32 ne ; /* nombre de pixel region exterieure */ + double sigi2, sige2; /* variance region interieure et exterieure */ + + /* variance des valeurs des niveaux de gris a l'interieur du snake */ + sigi2 = + (double)stat_sum_x2/(double)stat_sum_1 - + (double)(stat_sum_x*stat_sum_x)/(double)((uint64)stat_sum_1*(uint64)stat_sum_1) ; + + /* variance des valeurs des niveaux de gris a l'exterieur du snake */ + ne = n_dim-stat_sum_1 ; + stat_sum_xe = SUM_X - stat_sum_x ; + sige2 = + (double)(SUM_X2-stat_sum_x2)/(double)ne - + (double)(stat_sum_xe*stat_sum_xe)/(double)((uint64)ne*(uint64)ne) ; + + if ((sigi2 <= 0)|(sige2 <= 0)) return -1; + + return 0.5*((double)stat_sum_1*log(sigi2) + (double)ne*log(sige2)) ; +} + +__device__ double codage_gl_hyp_gaussienne(uint64 stat_sum_1, uint64 stat_sum_x, uint64 stat_sum_x2, + uint64 n_dim, uint64 SUM_X, uint64 SUM_X2){ + uint64 stat_sum_xe ; /* somme des xn region exterieure */ + uint32 ne ; /* nombre de pixel region exterieure */ + double sigi2, sige2; /* variance region interieure et exterieure */ + + /* variance des valeurs des niveaux de gris a l'interieur du snake */ + sigi2 = + (double)stat_sum_x2/(double)stat_sum_1 - + (double)(stat_sum_x*stat_sum_x)/(double)((uint64)stat_sum_1*(uint64)stat_sum_1) ; + + /* variance des valeurs des niveaux de gris a l'exterieur du snake */ + ne = n_dim-stat_sum_1 ; + stat_sum_xe = SUM_X - stat_sum_x ; + sige2 = + (double)(SUM_X2-stat_sum_x2)/(double)ne - + (double)(stat_sum_xe*stat_sum_xe)/(double)((uint64)ne*(uint64)ne) ; + + if ((sigi2 > 0)|(sige2 > 0)) + return 0.5*((double)stat_sum_1*log(sigi2) + (double)ne*log(sige2)) ; + return -1 ; +} + +__device__ inline unsigned int nextPow2_gpu( unsigned int x ) { + --x; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return ++x; +} + + +__device__ inline int sign_diff_strict(int val1, int val2) +{ + if (val1 > 0) + { + if (val2 >= 0) return 0 ; + else return 1 ; + } + else + if (val1 < 0) + { + if (val2 <= 0) return 0 ; + else return 1 ; + } + else + return 0 ;/* val1 == 0 */ +} + +__device__ inline int sign_diff_ou_egal_zero(int val1, int val2) +{ + if (val1 > 0) + { + if (val2 > 0) return 0 ; + else return 1 ; + } + else + if (val1 < 0) + { + if (val2 < 0) return 0 ; + else return 1 ; + } + else + return 1 ;/* val1 == 0 */ +} + + +__device__ int sinus_triangle(int Ai, int Aj, int Bi, int Bj, int Ci, int Cj) +{ + return (((Bi-Ai)*(Cj-Aj)) - ((Ci-Ai)*(Bj-Aj))) ; +} + +__device__ int test_croisement_large(uint32 Ai, uint32 Aj, uint32 Bi, uint32 Bj, + uint32 Ui, uint32 Uj, uint32 Vi, uint32 Vj) +{ + if (sign_diff_strict(sinus_triangle(Ai, Aj, Bi, Bj, Ui, Uj), // Bi-Ai, Uj-Aj, Ui-Ai, Bj-Aj + sinus_triangle(Ai, Aj, Bi, Bj, Vi, Vj))) // Bi-Ai, Vj-Aj, Vi-Ai, Bj-Aj + if (sign_diff_strict(sinus_triangle(Ui, Uj, Vi, Vj, Ai, Aj), // Vi-Ui, Aj-Uj, Ai-Ui, Vj-Uj + sinus_triangle(Ui, Uj, Vi, Vj, Bi, Bj))) // Vi-Ui, Bj-Uj, Bi-Ui, Vj-Uj + return 1 ; + return 0 ; +} + +__device__ int test_croisement_strict(uint32 Ai, uint32 Aj, uint32 Bi, uint32 Bj, + uint32 Ui, uint32 Uj, uint32 Vi, uint32 Vj ) +{ + if (sign_diff_ou_egal_zero(sinus_triangle(Ai, Aj, Bi, Bj, Ui, Uj), + sinus_triangle(Ai, Aj, Bi, Bj, Vi, Vj))) + if (sign_diff_ou_egal_zero(sinus_triangle(Ui, Uj, Vi, Vj, Ai, Aj), + sinus_triangle(Ui, Uj, Vi, Vj, Bi, Bj))) + return 1 ; + return 0 ; +} + +__global__ void kernel_test_croisement_move_seg_strict(struct snake_node_gpu *d_snake, uint32 nx, uint32 Nxi, uint32 Nxj, int Nb_nodes, bool * croist) +{ + int idx = blockDim.x*blockIdx.x + threadIdx.x, idx_prec, idx_suiv ; + int na, nb, naa, nbb ; + int Nai, Naj, Nbi, Nbj ; + bool croistil = false ; + + calcul_indices_prec_suiv(Nb_nodes, nx, na, nb); + calcul_indices_prec_suiv(Nb_nodes, na, naa, nbb); + + //coord. nodes extremites des segments a tester + Nai = d_snake[na].posi ; + Naj = d_snake[na].posj ; + Nbi = d_snake[nb].posi ; + Nbj = d_snake[nb].posj ; + + if (idx == nb) //premier segment apres + { + calcul_indices_prec_suiv(Nb_nodes, idx, idx_prec, idx_suiv); + if ( test_croisement_large(Nxi, Nxj, Nbi, Nbj, + Nbi, Nbj, d_snake[idx_suiv].posi, d_snake[idx_suiv].posj)) + croistil = true ; + else if ( test_croisement_strict(Nai, Naj, Nxi, Nxj, + Nbi, Nbj, d_snake[idx_suiv].posi, d_snake[idx_suiv].posj) ) + croistil = true ; + } + else if ( idx == naa ) //premier segment avant + { + if ( test_croisement_large(d_snake[naa].posi, d_snake[naa].posj, Nai, Naj, + Nai, Naj, Nxi, Nxj) ) + croistil = true ; + else if ( test_croisement_strict(d_snake[naa].posi, d_snake[naa].posj, Nai, Naj, + Nxi, Nxj, Nbi, Nbj)) + croistil = true ; + } + else if ( (idx != nx) && (idx != na) ) //les autres segments + { + calcul_indices_prec_suiv(Nb_nodes, idx, idx_prec, idx_suiv); + if ( test_croisement_strict(Nai, Naj, Nxi, Nxj, + d_snake[idx].posi, d_snake[idx].posj, + d_snake[idx_suiv].posi, d_snake[idx_suiv].posj) ) + croistil = true ; + else if ( test_croisement_strict(Nxi, Nxj, Nbi, Nbj, + d_snake[idx].posi, d_snake[idx].posj, + d_snake[idx_suiv].posi, d_snake[idx_suiv].posj) ) + croistil = true ; + } + + croist[idx] = croistil ; +} + +__device__ bool croisement(snake_node_gpu *d_snake, uint32 nx, uint32 Nxi, uint32 Nxj, int Nb_nodes) +{ + int idx_prec, idx_suiv ; + int na, nb, naa, nbb ; + int Nai, Naj, Nbi, Nbj ; + bool croistil = false ; + + //coord. nodes extremites des segments a tester + calcul_indices_prec_suiv(Nb_nodes, nx, na, nb); + calcul_indices_prec_suiv(Nb_nodes, na, naa, nbb); + + Nai = d_snake[na].posi ; + Naj = d_snake[na].posj ; + Nbi = d_snake[nb].posi ; + Nbj = d_snake[nb].posj ; + + //parcours du snake + for (int idx=0; idx < Nb_nodes; idx++){ + if (idx == nb) //premier segment apres + { + calcul_indices_prec_suiv(Nb_nodes, idx, idx_prec, idx_suiv); + if ( test_croisement_large(Nxi, Nxj, Nbi, Nbj, Nbi, Nbj, d_snake[idx_suiv].posi, d_snake[idx_suiv].posj) ) + return true ; + if ( test_croisement_strict(Nai, Naj, Nxi, Nxj, Nbi, Nbj, d_snake[idx_suiv].posi, d_snake[idx_suiv].posj) ) + return true ; + } + if ( idx == naa ) //premier segment avant + { + if ( test_croisement_large(d_snake[naa].posi, d_snake[naa].posj, Nai, Naj, Nai, Naj, Nxi, Nxj) ) + return true ; + if ( test_croisement_strict(d_snake[naa].posi, d_snake[naa].posj, Nai, Naj, Nxi, Nxj, Nbi, Nbj)) + return true ; + } + if ( (idx != nx) && (idx != na) && (idx != nb) && (idx != naa) ) //les autres segments + { + calcul_indices_prec_suiv(Nb_nodes, idx, idx_prec, idx_suiv); + if ( test_croisement_strict(Nai, Naj, Nxi, Nxj, + d_snake[idx].posi, d_snake[idx].posj, + d_snake[idx_suiv].posi, d_snake[idx_suiv].posj) ) + return true ; + if ( test_croisement_strict(Nxi, Nxj, Nbi, Nbj, + d_snake[idx].posi, d_snake[idx].posj, + d_snake[idx_suiv].posi, d_snake[idx_suiv].posj) ) + return true ; + } + } + return false; +} diff --git a/src/lib_kernels_maths.h b/src/lib_kernels_maths.h new file mode 100644 index 0000000..d827597 --- /dev/null +++ b/src/lib_kernels_maths.h @@ -0,0 +1,37 @@ + +#ifndef __KERNELS_MATHS__ +#define __KERNELS_MATHS__ + +__device__ void calcul_indices_prec_suiv(int nb_nodes, int nx, int& nprec, int& nsuiv); + +__device__ double codage_niveau_gris_hyp_gaussienne_gpu(uint32 stat_sum_1, uint64 stat_sum_x, + uint64 stat_sum_x2, uint32 n_dim, + uint64 SUM_X, uint64 SUM_X2); + +__device__ double codage_gl_hyp_gaussienne(uint64 stat_sum_1, uint64 stat_sum_x, uint64 stat_sum_x2, + uint64 n_dim, uint64 SUM_X, uint64 SUM_X2); + +__device__ inline unsigned int nextPow2_gpu( unsigned int x ); + +__device__ inline int sign_diff_strict(int val1, int val2); + + +__device__ inline int sign_diff_ou_egal_zero(int val1, int val2); + + +__device__ inline int sinus_triangle(int Ai, int Aj, int Bi, int Bj, int Ci, int Cj); + +__device__ inline int test_croisement_large(uint32 Ai, uint32 Aj, uint32 Bi, uint32 Bj, + uint32 Ui, uint32 Uj, uint32 Vi, uint32 Vj); + + +__device__ inline int test_croisement_strict(uint32 Ai, uint32 Aj, uint32 Bi, uint32 Bj, + uint32 Ui, uint32 Uj, uint32 Vi, uint32 Vj ); + + +__global__ void kernel_test_croisement_move_seg_strict(struct snake_node_gpu *d_snake, uint32 nx, uint32 Nxi, uint32 Nxj, int Nb_nodes, bool * croist); + + +__device__ bool test_croisement(struct snake_node_gpu *d_snake, uint32 nx, uint32 Nxi, uint32 Nxj, int Nb_nodes); + +#endif diff --git a/src/lib_kernels_maths.h~ b/src/lib_kernels_maths.h~ new file mode 100644 index 0000000..98d2830 --- /dev/null +++ b/src/lib_kernels_maths.h~ @@ -0,0 +1,231 @@ +#include "lib_kernels_maths.h" + +__device__ void calcul_indices_prec_suiv(int nb_nodes, int nx, int& nprec, int& nsuiv){ + nprec = (nx > 0)? (nx - 1):(nb_nodes - 1); + nsuiv = (nx < nb_nodes - 1)? (nx + 1):(0); +} + +__device__ double codage_niveau_gris_hyp_gaussienne_gpu(uint32 stat_sum_1, uint64 stat_sum_x, + uint64 stat_sum_x2, uint32 n_dim, + uint64 SUM_X, uint64 SUM_X2) +{ + uint64 stat_sum_xe ; /* somme des xn region exterieure */ + uint32 ne ; /* nombre de pixel region exterieure */ + double sigi2, sige2; /* variance region interieure et exterieure */ + + /* variance des valeurs des niveaux de gris a l'interieur du snake */ + sigi2 = + (double)stat_sum_x2/(double)stat_sum_1 - + (double)(stat_sum_x*stat_sum_x)/(double)((uint64)stat_sum_1*(uint64)stat_sum_1) ; + + /* variance des valeurs des niveaux de gris a l'exterieur du snake */ + ne = n_dim-stat_sum_1 ; + stat_sum_xe = SUM_X - stat_sum_x ; + sige2 = + (double)(SUM_X2-stat_sum_x2)/(double)ne - + (double)(stat_sum_xe*stat_sum_xe)/(double)((uint64)ne*(uint64)ne) ; + + if ((sigi2 <= 0)|(sige2 <= 0)) return -1; + + return 0.5*((double)stat_sum_1*log(sigi2) + (double)ne*log(sige2)) ; +} + +__device__ double codage_gl_hyp_gaussienne(uint64 stat_sum_1, uint64 stat_sum_x, uint64 stat_sum_x2, + uint64 n_dim, uint64 SUM_X, uint64 SUM_X2){ + uint64 stat_sum_xe ; /* somme des xn region exterieure */ + uint32 ne ; /* nombre de pixel region exterieure */ + double sigi2, sige2; /* variance region interieure et exterieure */ + + /* variance des valeurs des niveaux de gris a l'interieur du snake */ + sigi2 = + (double)stat_sum_x2/(double)stat_sum_1 - + (double)(stat_sum_x*stat_sum_x)/(double)((uint64)stat_sum_1*(uint64)stat_sum_1) ; + + /* variance des valeurs des niveaux de gris a l'exterieur du snake */ + ne = n_dim-stat_sum_1 ; + stat_sum_xe = SUM_X - stat_sum_x ; + sige2 = + (double)(SUM_X2-stat_sum_x2)/(double)ne - + (double)(stat_sum_xe*stat_sum_xe)/(double)((uint64)ne*(uint64)ne) ; + + if ((sigi2 > 0)|(sige2 > 0)) + return 0.5*((double)stat_sum_1*log(sigi2) + (double)ne*log(sige2)) ; + return -1 ; +} + +__device__ inline unsigned int nextPow2_gpu( unsigned int x ) { + --x; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return ++x; +} + + +__device__ inline int sign_diff_strict(int val1, int val2) +{ + if (val1 > 0) + { + if (val2 >= 0) return 0 ; + else return 1 ; + } + else + if (val1 < 0) + { + if (val2 <= 0) return 0 ; + else return 1 ; + } + else + return 0 ;/* val1 == 0 */ +} + +__device__ inline int sign_diff_ou_egal_zero(int val1, int val2) +{ + if (val1 > 0) + { + if (val2 > 0) return 0 ; + else return 1 ; + } + else + if (val1 < 0) + { + if (val2 < 0) return 0 ; + else return 1 ; + } + else + return 1 ;/* val1 == 0 */ +} + + +__device__ inline int sinus_triangle(int Ai, int Aj, int Bi, int Bj, int Ci, int Cj) +{ + return (((Bi-Ai)*(Cj-Aj)) - ((Ci-Ai)*(Bj-Aj))) ; +} + +__device__ inline int test_croisement_large(uint32 Ai, uint32 Aj, uint32 Bi, uint32 Bj, + uint32 Ui, uint32 Uj, uint32 Vi, uint32 Vj) +{ + if (sign_diff_strict(sinus_triangle(Ai, Aj, Bi, Bj, Ui, Uj), // Bi-Ai, Uj-Aj, Ui-Ai, Bj-Aj + sinus_triangle(Ai, Aj, Bi, Bj, Vi, Vj))) // Bi-Ai, Vj-Aj, Vi-Ai, Bj-Aj + if (sign_diff_strict(sinus_triangle(Ui, Uj, Vi, Vj, Ai, Aj), // Vi-Ui, Aj-Uj, Ai-Ui, Vj-Uj + sinus_triangle(Ui, Uj, Vi, Vj, Bi, Bj))) // Vi-Ui, Bj-Uj, Bi-Ui, Vj-Uj + return 1 ; + return 0 ; +} + +__device__ inline int test_croisement_strict(uint32 Ai, uint32 Aj, uint32 Bi, uint32 Bj, + uint32 Ui, uint32 Uj, uint32 Vi, uint32 Vj ) +{ + if (sign_diff_ou_egal_zero(sinus_triangle(Ai, Aj, Bi, Bj, Ui, Uj), + sinus_triangle(Ai, Aj, Bi, Bj, Vi, Vj))) + if (sign_diff_ou_egal_zero(sinus_triangle(Ui, Uj, Vi, Vj, Ai, Aj), + sinus_triangle(Ui, Uj, Vi, Vj, Bi, Bj))) + return 1 ; + return 0 ; +} + +__global__ void kernel_test_croisement_move_seg_strict(struct snake_node_gpu *d_snake, uint32 nx, uint32 Nxi, uint32 Nxj, int Nb_nodes, bool * croist) +{ + int idx = blockDim.x*blockIdx.x + threadIdx.x, idx_prec, idx_suiv ; + int na, nb, naa, nbb ; + int Nai, Naj, Nbi, Nbj ; + bool croistil = false ; + + calcul_indices_prec_suiv(Nb_nodes, nx, na, nb); + calcul_indices_prec_suiv(Nb_nodes, na, naa, nbb); + + //coord. nodes extremites des segments a tester + Nai = d_snake[na].posi ; + Naj = d_snake[na].posj ; + Nbi = d_snake[nb].posi ; + Nbj = d_snake[nb].posj ; + + if (idx == nb) //premier segment apres + { + calcul_indices_prec_suiv(Nb_nodes, idx, idx_prec, idx_suiv); + if ( test_croisement_large(Nxi, Nxj, Nbi, Nbj, + Nbi, Nbj, d_snake[idx_suiv].posi, d_snake[idx_suiv].posj)) + croistil = true ; + else if ( test_croisement_strict(Nai, Naj, Nxi, Nxj, + Nbi, Nbj, d_snake[idx_suiv].posi, d_snake[idx_suiv].posj) ) + croistil = true ; + } + else if ( idx == naa ) //premier segment avant + { + if ( test_croisement_large(d_snake[naa].posi, d_snake[naa].posj, Nai, Naj, + Nai, Naj, Nxi, Nxj) ) + croistil = true ; + else if ( test_croisement_strict(d_snake[naa].posi, d_snake[naa].posj, Nai, Naj, + Nxi, Nxj, Nbi, Nbj)) + croistil = true ; + } + else if ( (idx != nx) && (idx != na) ) //les autres segments + { + calcul_indices_prec_suiv(Nb_nodes, idx, idx_prec, idx_suiv); + if ( test_croisement_strict(Nai, Naj, Nxi, Nxj, + d_snake[idx].posi, d_snake[idx].posj, + d_snake[idx_suiv].posi, d_snake[idx_suiv].posj) ) + croistil = true ; + else if ( test_croisement_strict(Nxi, Nxj, Nbi, Nbj, + d_snake[idx].posi, d_snake[idx].posj, + d_snake[idx_suiv].posi, d_snake[idx_suiv].posj) ) + croistil = true ; + } + + croist[idx] = croistil ; +} + +__device__ bool test_croisement(struct snake_node_gpu *d_snake, uint32 nx, uint32 Nxi, uint32 Nxj, int Nb_nodes) +{ + int idx_prec, idx_suiv ; + int na, nb, naa, nbb ; + int Nai, Naj, Nbi, Nbj ; + bool croistil = false ; + + //coord. nodes extremites des segments a tester + calcul_indices_prec_suiv(Nb_nodes, nx, na, nb); + calcul_indices_prec_suiv(Nb_nodes, na, naa, nbb); + + Nai = d_snake[na].posi ; + Naj = d_snake[na].posj ; + Nbi = d_snake[nb].posi ; + Nbj = d_snake[nb].posj ; + + //parcours du snake + for (int idx=0; idx < Nb_nodes; idx++){ + if (idx == nb) //premier segment apres + { + calcul_indices_prec_suiv(Nb_nodes, idx, idx_prec, idx_suiv); + if ( test_croisement_large(Nxi, Nxj, Nbi, Nbj, + Nbi, Nbj, d_snake[idx_suiv].posi, d_snake[idx_suiv].posj)) + croistil = true ; + else if ( test_croisement_strict(Nai, Naj, Nxi, Nxj, + Nbi, Nbj, d_snake[idx_suiv].posi, d_snake[idx_suiv].posj) ) + croistil = true ; + } + else if ( idx == naa ) //premier segment avant + { + if ( test_croisement_large(d_snake[naa].posi, d_snake[naa].posj, Nai, Naj, + Nai, Naj, Nxi, Nxj) ) + croistil = true ; + else if ( test_croisement_strict(d_snake[naa].posi, d_snake[naa].posj, Nai, Naj, + Nxi, Nxj, Nbi, Nbj)) + croistil = true ; + } + else if ( (idx != nx) && (idx != na) ) //les autres segments + { + calcul_indices_prec_suiv(Nb_nodes, idx, idx_prec, idx_suiv); + if ( test_croisement_strict(Nai, Naj, Nxi, Nxj, + d_snake[idx].posi, d_snake[idx].posj, + d_snake[idx_suiv].posi, d_snake[idx_suiv].posj) ) + croistil = true ; + else if ( test_croisement_strict(Nxi, Nxj, Nbi, Nbj, + d_snake[idx].posi, d_snake[idx].posj, + d_snake[idx_suiv].posi, d_snake[idx_suiv].posj) ) + croistil = true ; + } + } + return ( croistil ); +} diff --git a/src/lib_kernels_maths_gpu.cu~ b/src/lib_kernels_maths_gpu.cu~ new file mode 100644 index 0000000..98d2830 --- /dev/null +++ b/src/lib_kernels_maths_gpu.cu~ @@ -0,0 +1,231 @@ +#include "lib_kernels_maths.h" + +__device__ void calcul_indices_prec_suiv(int nb_nodes, int nx, int& nprec, int& nsuiv){ + nprec = (nx > 0)? (nx - 1):(nb_nodes - 1); + nsuiv = (nx < nb_nodes - 1)? (nx + 1):(0); +} + +__device__ double codage_niveau_gris_hyp_gaussienne_gpu(uint32 stat_sum_1, uint64 stat_sum_x, + uint64 stat_sum_x2, uint32 n_dim, + uint64 SUM_X, uint64 SUM_X2) +{ + uint64 stat_sum_xe ; /* somme des xn region exterieure */ + uint32 ne ; /* nombre de pixel region exterieure */ + double sigi2, sige2; /* variance region interieure et exterieure */ + + /* variance des valeurs des niveaux de gris a l'interieur du snake */ + sigi2 = + (double)stat_sum_x2/(double)stat_sum_1 - + (double)(stat_sum_x*stat_sum_x)/(double)((uint64)stat_sum_1*(uint64)stat_sum_1) ; + + /* variance des valeurs des niveaux de gris a l'exterieur du snake */ + ne = n_dim-stat_sum_1 ; + stat_sum_xe = SUM_X - stat_sum_x ; + sige2 = + (double)(SUM_X2-stat_sum_x2)/(double)ne - + (double)(stat_sum_xe*stat_sum_xe)/(double)((uint64)ne*(uint64)ne) ; + + if ((sigi2 <= 0)|(sige2 <= 0)) return -1; + + return 0.5*((double)stat_sum_1*log(sigi2) + (double)ne*log(sige2)) ; +} + +__device__ double codage_gl_hyp_gaussienne(uint64 stat_sum_1, uint64 stat_sum_x, uint64 stat_sum_x2, + uint64 n_dim, uint64 SUM_X, uint64 SUM_X2){ + uint64 stat_sum_xe ; /* somme des xn region exterieure */ + uint32 ne ; /* nombre de pixel region exterieure */ + double sigi2, sige2; /* variance region interieure et exterieure */ + + /* variance des valeurs des niveaux de gris a l'interieur du snake */ + sigi2 = + (double)stat_sum_x2/(double)stat_sum_1 - + (double)(stat_sum_x*stat_sum_x)/(double)((uint64)stat_sum_1*(uint64)stat_sum_1) ; + + /* variance des valeurs des niveaux de gris a l'exterieur du snake */ + ne = n_dim-stat_sum_1 ; + stat_sum_xe = SUM_X - stat_sum_x ; + sige2 = + (double)(SUM_X2-stat_sum_x2)/(double)ne - + (double)(stat_sum_xe*stat_sum_xe)/(double)((uint64)ne*(uint64)ne) ; + + if ((sigi2 > 0)|(sige2 > 0)) + return 0.5*((double)stat_sum_1*log(sigi2) + (double)ne*log(sige2)) ; + return -1 ; +} + +__device__ inline unsigned int nextPow2_gpu( unsigned int x ) { + --x; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return ++x; +} + + +__device__ inline int sign_diff_strict(int val1, int val2) +{ + if (val1 > 0) + { + if (val2 >= 0) return 0 ; + else return 1 ; + } + else + if (val1 < 0) + { + if (val2 <= 0) return 0 ; + else return 1 ; + } + else + return 0 ;/* val1 == 0 */ +} + +__device__ inline int sign_diff_ou_egal_zero(int val1, int val2) +{ + if (val1 > 0) + { + if (val2 > 0) return 0 ; + else return 1 ; + } + else + if (val1 < 0) + { + if (val2 < 0) return 0 ; + else return 1 ; + } + else + return 1 ;/* val1 == 0 */ +} + + +__device__ inline int sinus_triangle(int Ai, int Aj, int Bi, int Bj, int Ci, int Cj) +{ + return (((Bi-Ai)*(Cj-Aj)) - ((Ci-Ai)*(Bj-Aj))) ; +} + +__device__ inline int test_croisement_large(uint32 Ai, uint32 Aj, uint32 Bi, uint32 Bj, + uint32 Ui, uint32 Uj, uint32 Vi, uint32 Vj) +{ + if (sign_diff_strict(sinus_triangle(Ai, Aj, Bi, Bj, Ui, Uj), // Bi-Ai, Uj-Aj, Ui-Ai, Bj-Aj + sinus_triangle(Ai, Aj, Bi, Bj, Vi, Vj))) // Bi-Ai, Vj-Aj, Vi-Ai, Bj-Aj + if (sign_diff_strict(sinus_triangle(Ui, Uj, Vi, Vj, Ai, Aj), // Vi-Ui, Aj-Uj, Ai-Ui, Vj-Uj + sinus_triangle(Ui, Uj, Vi, Vj, Bi, Bj))) // Vi-Ui, Bj-Uj, Bi-Ui, Vj-Uj + return 1 ; + return 0 ; +} + +__device__ inline int test_croisement_strict(uint32 Ai, uint32 Aj, uint32 Bi, uint32 Bj, + uint32 Ui, uint32 Uj, uint32 Vi, uint32 Vj ) +{ + if (sign_diff_ou_egal_zero(sinus_triangle(Ai, Aj, Bi, Bj, Ui, Uj), + sinus_triangle(Ai, Aj, Bi, Bj, Vi, Vj))) + if (sign_diff_ou_egal_zero(sinus_triangle(Ui, Uj, Vi, Vj, Ai, Aj), + sinus_triangle(Ui, Uj, Vi, Vj, Bi, Bj))) + return 1 ; + return 0 ; +} + +__global__ void kernel_test_croisement_move_seg_strict(struct snake_node_gpu *d_snake, uint32 nx, uint32 Nxi, uint32 Nxj, int Nb_nodes, bool * croist) +{ + int idx = blockDim.x*blockIdx.x + threadIdx.x, idx_prec, idx_suiv ; + int na, nb, naa, nbb ; + int Nai, Naj, Nbi, Nbj ; + bool croistil = false ; + + calcul_indices_prec_suiv(Nb_nodes, nx, na, nb); + calcul_indices_prec_suiv(Nb_nodes, na, naa, nbb); + + //coord. nodes extremites des segments a tester + Nai = d_snake[na].posi ; + Naj = d_snake[na].posj ; + Nbi = d_snake[nb].posi ; + Nbj = d_snake[nb].posj ; + + if (idx == nb) //premier segment apres + { + calcul_indices_prec_suiv(Nb_nodes, idx, idx_prec, idx_suiv); + if ( test_croisement_large(Nxi, Nxj, Nbi, Nbj, + Nbi, Nbj, d_snake[idx_suiv].posi, d_snake[idx_suiv].posj)) + croistil = true ; + else if ( test_croisement_strict(Nai, Naj, Nxi, Nxj, + Nbi, Nbj, d_snake[idx_suiv].posi, d_snake[idx_suiv].posj) ) + croistil = true ; + } + else if ( idx == naa ) //premier segment avant + { + if ( test_croisement_large(d_snake[naa].posi, d_snake[naa].posj, Nai, Naj, + Nai, Naj, Nxi, Nxj) ) + croistil = true ; + else if ( test_croisement_strict(d_snake[naa].posi, d_snake[naa].posj, Nai, Naj, + Nxi, Nxj, Nbi, Nbj)) + croistil = true ; + } + else if ( (idx != nx) && (idx != na) ) //les autres segments + { + calcul_indices_prec_suiv(Nb_nodes, idx, idx_prec, idx_suiv); + if ( test_croisement_strict(Nai, Naj, Nxi, Nxj, + d_snake[idx].posi, d_snake[idx].posj, + d_snake[idx_suiv].posi, d_snake[idx_suiv].posj) ) + croistil = true ; + else if ( test_croisement_strict(Nxi, Nxj, Nbi, Nbj, + d_snake[idx].posi, d_snake[idx].posj, + d_snake[idx_suiv].posi, d_snake[idx_suiv].posj) ) + croistil = true ; + } + + croist[idx] = croistil ; +} + +__device__ bool test_croisement(struct snake_node_gpu *d_snake, uint32 nx, uint32 Nxi, uint32 Nxj, int Nb_nodes) +{ + int idx_prec, idx_suiv ; + int na, nb, naa, nbb ; + int Nai, Naj, Nbi, Nbj ; + bool croistil = false ; + + //coord. nodes extremites des segments a tester + calcul_indices_prec_suiv(Nb_nodes, nx, na, nb); + calcul_indices_prec_suiv(Nb_nodes, na, naa, nbb); + + Nai = d_snake[na].posi ; + Naj = d_snake[na].posj ; + Nbi = d_snake[nb].posi ; + Nbj = d_snake[nb].posj ; + + //parcours du snake + for (int idx=0; idx < Nb_nodes; idx++){ + if (idx == nb) //premier segment apres + { + calcul_indices_prec_suiv(Nb_nodes, idx, idx_prec, idx_suiv); + if ( test_croisement_large(Nxi, Nxj, Nbi, Nbj, + Nbi, Nbj, d_snake[idx_suiv].posi, d_snake[idx_suiv].posj)) + croistil = true ; + else if ( test_croisement_strict(Nai, Naj, Nxi, Nxj, + Nbi, Nbj, d_snake[idx_suiv].posi, d_snake[idx_suiv].posj) ) + croistil = true ; + } + else if ( idx == naa ) //premier segment avant + { + if ( test_croisement_large(d_snake[naa].posi, d_snake[naa].posj, Nai, Naj, + Nai, Naj, Nxi, Nxj) ) + croistil = true ; + else if ( test_croisement_strict(d_snake[naa].posi, d_snake[naa].posj, Nai, Naj, + Nxi, Nxj, Nbi, Nbj)) + croistil = true ; + } + else if ( (idx != nx) && (idx != na) ) //les autres segments + { + calcul_indices_prec_suiv(Nb_nodes, idx, idx_prec, idx_suiv); + if ( test_croisement_strict(Nai, Naj, Nxi, Nxj, + d_snake[idx].posi, d_snake[idx].posj, + d_snake[idx_suiv].posi, d_snake[idx_suiv].posj) ) + croistil = true ; + else if ( test_croisement_strict(Nxi, Nxj, Nbi, Nbj, + d_snake[idx].posi, d_snake[idx].posj, + d_snake[idx_suiv].posi, d_snake[idx_suiv].posj) ) + croistil = true ; + } + } + return ( croistil ); +} diff --git a/src/lib_math.c b/src/lib_math.c new file mode 100644 index 0000000..79a2b20 --- /dev/null +++ b/src/lib_math.c @@ -0,0 +1,276 @@ +/** + * \file lib_math.c + * \brief routines + * \author NB - PhyTI + * \version x.x + * \date 20 decembre 2009 + * + */ + +#include +#include "lib_math.h" +#include "constantes.h" + +/** + * \fn void tic(struct timeval* temps, char* texte) + * \brief Initialise le compteur de temps + * + * \param[out] temps + * \param[in] texte texte a afficher + * + */ +void tic(struct timeval* temps, char* texte) +{ + gettimeofday(temps, NULL); + + if (texte != NULL) + printf("%s\n", texte) ; +} + +/** + * \fn double toc(struct timeval start, char* texte) + * \brief Calcule le temps ecoule + * + * \param[in] start temps de debut du chrono + * \param[in] texte texte a afficher + * + * \return le temps ecoule entre tic et toc + */ +double toc(struct timeval start, char* texte) +{ + struct timeval end ; + double elapsed ; + + gettimeofday(&end, NULL); + + elapsed = (double)(end.tv_sec-start.tv_sec) + + 0.000001*(double)(end.tv_usec-start.tv_usec); + if (texte != NULL) + printf("%s : %f\n", texte, elapsed) ; + + return elapsed ; +} + + +/** + * \fn void min_max_int1d(int *val_min, int *val_max, int *vect, int dim) + * \brief determine le min et max d'un vecteur de int + * + * \param[out] val_min + * \param[out] val_max + * \param[in] vect + * \param[in] dim dimension du vecteur + * + */ + +void min_max_int1d(int *val_min, int *val_max, int *vect, int dim) +{ + int n, min, max ; + + min = vect[1]; + max = min; + + for (n=0;n max) max = vect[n]; + if (vect[n] < min) min = vect[n]; + } + + *val_min = min ; + *val_max = max ; +} + +void min_max_ushort1d(int *val_min, int *val_max, unsigned short *vect, int dim) +{ + int n ; + unsigned short min, max ; + + min = vect[1]; + max = min; + + for (n=0;n max) max = vect[n]; + if (vect[n] < min) min = vect[n]; + } + + *val_min = min ; + *val_max = max ; +} + + + + +/** + * \fn inline int test_inf(double arg1, double arg2) + * + * \brief test (arg1 < arg2) inferieur a avec pourcentage minimum + * + * \param[in] arg1 + * \param[in] arg2 + * + * return test + */ +inline int test_inf(double arg1, double arg2) +{ + if (arg2 > 0) + return arg1 < (arg2*COEF_DECROI) ; + else + return arg1 < (arg2*INV_COEF_DECROI) ; +} + + + +/** + * \fn int calcul_px_autour_noeud(int ni, int nj, int pas, + * int idim_m1, int jdim_m1, + * int *liste_pixel_move) + * + * \brief determine les positions de test autout d'un noeud + * + * \param[in] ni coordonnee i + * \param[in] nj coordonnee j + * \param[in] pas ecartement par rapport au centre + * \param[in] idim_m1 dimension de l'image sur l'axe i (-1) + * \param[in] jdim_m1 dimension de l'image sur l'axe j (-1) + * \param[out] liste_pixel_move liste des coordonnees [i,j,i,j,...] + * + * return le nombre de coordonnees (*2) + */ +uint32 calcul_px_autour_noeud(uint32 ni, uint32 nj, int pas, + uint32 idim_m1, uint32 jdim_m1, + uint32 *liste_pixel_move) +{ + uint32 ind = 0 ; + + liste_pixel_move[ind++] = min(ni + pas, idim_m1) ; + liste_pixel_move[ind++] = nj ; + + liste_pixel_move[ind++] = min(ni + pas, idim_m1) ; + liste_pixel_move[ind++] = min(nj + pas, jdim_m1) ; + + liste_pixel_move[ind++] = ni ; + liste_pixel_move[ind++] = min(nj + pas, jdim_m1) ; + + liste_pixel_move[ind++] = max(ni - pas, 0) ; + liste_pixel_move[ind++] = min(nj + pas, jdim_m1) ; + + liste_pixel_move[ind++] = max(ni - pas, 0) ; + liste_pixel_move[ind++] = nj ; + + liste_pixel_move[ind++] = max(ni - pas, 0) ; + liste_pixel_move[ind++] = max(nj - pas, 0) ; + + liste_pixel_move[ind++] = ni ; + liste_pixel_move[ind++] = max(nj - pas, 0) ; + + liste_pixel_move[ind++] = min(ni + pas, idim_m1) ; + liste_pixel_move[ind++] = max(nj - pas, 0) ; + + return ind ; +} + + + +/** + * \fn inline int sign_diff_ou_egal_zero(int val1, int val2) + * + * \brief fonction qui test si les arguments sont de signes differents ou nuls + * \author NB - PhyTI + * + * \param[in] val1 + * \param[in] val2 + * + * \return le test 0/1 + * + */ +inline int sign_diff_ou_egal_zero(int val1, int val2) +{ + if (val1 > 0) + { + if (val2 > 0) return 0 ; + else return 1 ; + } + else + if (val1 < 0) + { + if (val2 < 0) return 0 ; + else return 1 ; + } + else + return 1 ;/* val1 == 0 */ +} + +/** + * \fn inline int sign_diff_strict(int val1, int val2) + * + * \brief fonction qui test si les arguments sont de signes differents strictement + * \author NB - PhyTI + * + * \param[in] val1 + * \param[in] val2 + * + * \return le test 0/1 + * + */ +inline int sign_diff_strict(int val1, int val2) +{ + if (val1 > 0) + { + if (val2 >= 0) return 0 ; + else return 1 ; + } + else + if (val1 < 0) + { + if (val2 <= 0) return 0 ; + else return 1 ; + } + else + return 0 ;/* val1 == 0 */ +} + + + +/** + * \fn inline int sinus_triangle(int Ai, int Aj, int Bi, int Bj, int Ci, int Cj) + * + * \brief calcul le "sinus" de l'angle du triangle ABC + * \author NB - PhyTI + * + * \param[in] Ai les coordonnees + * \param[in] Aj + * \param[in] Bi + * \param[in] Bj + * \param[in] Ci + * \param[in] Cj + * + * \return le sinus non normalise + * + * Cette fonction est utile pour determiner si un triangle ABC + * est donne dans l'ordre trigo. + * Signe > 0: sens trigo, + * signe < 0: sens antitrigo + * = 0: plat + */ +inline int sinus_triangle(int Ai, int Aj, int Bi, int Bj, int Ci, int Cj) +{ + return (((Bi-Ai)*(Cj-Aj)) - ((Ci-Ai)*(Bj-Aj))) ; +} + + +/** + * \fn void recopie_vecteur(int *in, int *out, int dim) + * + * \brief recopie le vecteur out vers in + * \author NB - PhyTI + * + * \param[in] in vecteur d'entree + * \param[out] out vecteur recopier + * \param[in] dim longueur du vecteur + */ +void recopie_vecteur(int *in, int *out, int dim) +{ + int n ; + for (n=0; n +#include "lib_math.h" +#include "constantes.h" + +/** + * \fn void tic(struct timeval* temps, char* texte) + * \brief Initialise le compteur de temps + * + * \param[out] temps + * \param[in] texte texte a afficher + * + */ +void tic(struct timeval* temps, char* texte) +{ + gettimeofday(temps, NULL); + + if (texte != NULL) + printf("%s\n", texte) ; +} + +/** + * \fn double toc(struct timeval start, char* texte) + * \brief Calcule le temps ecoule + * + * \param[in] start temps de debut du chrono + * \param[in] texte texte a afficher + * + * \return le temps ecoule entre tic et toc + */ +double toc(struct timeval start, char* texte) +{ + struct timeval end ; + double elapsed ; + + gettimeofday(&end, NULL); + + elapsed = (double)(end.tv_sec-start.tv_sec) + + 0.000001*(double)(end.tv_usec-start.tv_usec); + if (texte != NULL) + printf("%s : %f\n", texte, elapsed) ; + + return elapsed ; +} + + +/** + * \fn void min_max_int1d(int *val_min, int *val_max, int *vect, int dim) + * \brief determine le min et max d'un vecteur de int + * + * \param[out] val_min + * \param[out] val_max + * \param[in] vect + * \param[in] dim dimension du vecteur + * + */ +void min_max_int1d(int *val_min, int *val_max, int *vect, int dim) +{ + int n, min, max ; + + min = vect[1]; + max = min; + + for (n=0;n max) max = vect[n]; + if (vect[n] < min) min = vect[n]; + } + + *val_min = min ; + *val_max = max ; +} + + + + +/** + * \fn inline int test_inf(double arg1, double arg2) + * + * \brief test (arg1 < arg2) inferieur a avec pourcentage minimum + * + * \param[in] arg1 + * \param[in] arg2 + * + * return test + */ +inline int test_inf(double arg1, double arg2) +{ + if (arg2 > 0) + return arg1 < (arg2*COEF_DECROI) ; + else + return arg1 < (arg2*INV_COEF_DECROI) ; +} + + + +/** + * \fn int calcul_px_autour_noeud(int ni, int nj, int pas, + * int idim_m1, int jdim_m1, + * int *liste_pixel_move) + * + * \brief determine les positions de test autout d'un noeud + * + * \param[in] ni coordonnee i + * \param[in] nj coordonnee j + * \param[in] pas ecartement par rapport au centre + * \param[in] idim_m1 dimension de l'image sur l'axe i (-1) + * \param[in] jdim_m1 dimension de l'image sur l'axe j (-1) + * \param[out] liste_pixel_move liste des coordonnees [i,j,i,j,...] + * + * return le nombre de coordonnees (*2) + */ +uint32 calcul_px_autour_noeud(uint32 ni, uint32 nj, int pas, + uint32 idim_m1, uint32 jdim_m1, + uint32 *liste_pixel_move) +{ + uint32 ind = 0 ; + + liste_pixel_move[ind++] = min(ni + pas, idim_m1) ; + liste_pixel_move[ind++] = nj ; + + liste_pixel_move[ind++] = min(ni + pas, idim_m1) ; + liste_pixel_move[ind++] = min(nj + pas, jdim_m1) ; + + liste_pixel_move[ind++] = ni ; + liste_pixel_move[ind++] = min(nj + pas, jdim_m1) ; + + liste_pixel_move[ind++] = max(ni - pas, 0) ; + liste_pixel_move[ind++] = min(nj + pas, jdim_m1) ; + + liste_pixel_move[ind++] = max(ni - pas, 0) ; + liste_pixel_move[ind++] = nj ; + + liste_pixel_move[ind++] = max(ni - pas, 0) ; + liste_pixel_move[ind++] = max(nj - pas, 0) ; + + liste_pixel_move[ind++] = ni ; + liste_pixel_move[ind++] = max(nj - pas, 0) ; + + liste_pixel_move[ind++] = min(ni + pas, idim_m1) ; + liste_pixel_move[ind++] = max(nj - pas, 0) ; + + return ind ; +} + + + +/** + * \fn inline int sign_diff_ou_egal_zero(int val1, int val2) + * + * \brief fonction qui test si les arguments sont de signes differents ou nuls + * \author NB - PhyTI + * + * \param[in] val1 + * \param[in] val2 + * + * \return le test 0/1 + * + */ +inline int sign_diff_ou_egal_zero(int val1, int val2) +{ + if (val1 > 0) + { + if (val2 > 0) return 0 ; + else return 1 ; + } + else + if (val1 < 0) + { + if (val2 < 0) return 0 ; + else return 1 ; + } + else + return 1 ;/* val1 == 0 */ +} + +/** + * \fn inline int sign_diff_strict(int val1, int val2) + * + * \brief fonction qui test si les arguments sont de signes differents strictement + * \author NB - PhyTI + * + * \param[in] val1 + * \param[in] val2 + * + * \return le test 0/1 + * + */ +inline int sign_diff_strict(int val1, int val2) +{ + if (val1 > 0) + { + if (val2 >= 0) return 0 ; + else return 1 ; + } + else + if (val1 < 0) + { + if (val2 <= 0) return 0 ; + else return 1 ; + } + else + return 0 ;/* val1 == 0 */ +} + + + +/** + * \fn inline int sinus_triangle(int Ai, int Aj, int Bi, int Bj, int Ci, int Cj) + * + * \brief calcul le "sinus" de l'angle du triangle ABC + * \author NB - PhyTI + * + * \param[in] Ai les coordonnees + * \param[in] Aj + * \param[in] Bi + * \param[in] Bj + * \param[in] Ci + * \param[in] Cj + * + * \return le sinus non normalise + * + * Cette fonction est utile pour determiner si un triangle ABC + * est donne dans l'ordre trigo. + * Signe > 0: sens trigo, + * signe < 0: sens antitrigo + * = 0: plat + */ +inline int sinus_triangle(int Ai, int Aj, int Bi, int Bj, int Ci, int Cj) +{ + return (((Bi-Ai)*(Cj-Aj)) - ((Ci-Ai)*(Bj-Aj))) ; +} + + +/** + * \fn void recopie_vecteur(int *in, int *out, int dim) + * + * \brief recopie le vecteur out vers in + * \author NB - PhyTI + * + * \param[in] in vecteur d'entree + * \param[out] out vecteur recopier + * \param[in] dim longueur du vecteur + */ +void recopie_vecteur(int *in, int *out, int dim) +{ + int n ; + for (n=0; n +#include "structures.h" + +void tic(struct timeval* temps, char* texte) ; +double toc(struct timeval start, char* texte) ; + +void min_max_int1d(int *val_min, int *val_max, int *vect, int dim) ; +void min_max_ushort1d(int *val_min, int *val_max, unsigned short *vect, int dim) ; + +#define min(a,b) ((a)<(b)) ? (a) : (b) +#define max(a,b) ((a)>(b)) ? (a) : (b) + +uint32 calcul_px_autour_noeud(uint32 ni, uint32 nj, int pas, + uint32 idim_m1, uint32 jdim_m1, + uint32 *liste_pixel_move); + +inline int test_inf(double arg1, double arg2); + +inline int sign_diff_ou_egal_zero(int val1, int val2); +inline int sign_diff_strict(int val1, int val2); + +inline int sinus_triangle(int Ai, int Aj, int Bi, int Bj, int Ci, int Cj); + +void recopie_vecteur(int *in, int *out, int dim) ; + + +#endif diff --git a/src/lib_math.h~ b/src/lib_math.h~ new file mode 100644 index 0000000..ba4bead --- /dev/null +++ b/src/lib_math.h~ @@ -0,0 +1,30 @@ +#ifndef _LIB_MATH_H +#define _LIB_MATH_H + + +#include +#include "structures.h" + +void tic(struct timeval* temps, char* texte) ; +double toc(struct timeval start, char* texte) ; + +void min_max_int1d(int *val_min, int *val_max, int *vect, int dim) ; + +#define min(a,b) ((a)<(b)) ? (a) : (b) +#define max(a,b) ((a)>(b)) ? (a) : (b) + +uint32 calcul_px_autour_noeud(uint32 ni, uint32 nj, int pas, + uint32 idim_m1, uint32 jdim_m1, + uint32 *liste_pixel_move); + +inline int test_inf(double arg1, double arg2); + +inline int sign_diff_ou_egal_zero(int val1, int val2); +inline int sign_diff_strict(int val1, int val2); + +inline int sinus_triangle(int Ai, int Aj, int Bi, int Bj, int Ci, int Cj); + +void recopie_vecteur(int *in, int *out, int dim) ; + + +#endif diff --git a/src/lib_snake_2_gpu.cu b/src/lib_snake_2_gpu.cu new file mode 100644 index 0000000..63db755 --- /dev/null +++ b/src/lib_snake_2_gpu.cu @@ -0,0 +1,141 @@ + +extern "C"{ +#include "structures.h" +#include "lib_snake_2_gpu.h" +} +#include "stdio.h" + +void snake2gpu( snake_node_gpu * d_snake, snake_node* h_snake, int n ){ + + snake_node * snake = h_snake; + snake_node_gpu snake_nodes[n]; + + for (int i=0; icontrib.sum_1 ; + snake_nodes[i].sum_x = snake->contrib.sum_x ; + snake_nodes[i].sum_x2 = snake->contrib.sum_x2 ; + + snake_nodes[i].code_segment = snake->code_segment ; + snake_nodes[i].freeman_in = snake->freeman_in ; + snake_nodes[i].freeman_out = snake->freeman_out ; + snake_nodes[i].nb_pixels = snake->nb_pixels ; + + snake_nodes[i].posi = snake->posi ; + snake_nodes[i].posj = snake->posj ; + snake_nodes[i].centre_i = snake->centre_i ; + snake_nodes[i].centre_j = snake->centre_j ; + + snake_nodes[i].last_move = snake->last_move ; + + snake = snake->noeud_suiv ; + } + + cudaMemcpy( d_snake, snake_nodes, n*sizeof(snake_node_gpu), cudaMemcpyHostToDevice ); + + /*verif integrite data*/ + /* + snake_node_gpu new_snake_nodes[n]; + cudaMemcpy( new_snake_nodes , d_snake, n*sizeof(snake_node_gpu), cudaMemcpyDeviceToHost ); + + for (int i=0; inoeud_suiv = snake; + snake->noeud_prec = snake_prec; + } + if (i == n-1) { + snake->noeud_suiv = *h_snake; + (*h_snake)->noeud_prec = snake; + } + /* + snake->contrib.sum_1 = snake_nodes[i].sum_1 ; + snake->contrib.sum_x = snake_nodes[i].sum_x ; + snake->contrib.sum_x2 = snake_nodes[i].sum_x2 ; + + snake->code_segment = snake_nodes[i].code_segment ; + snake->freeman_in = snake_nodes[i].freeman_in ; + snake->freeman_out = snake_nodes[i].freeman_out ; + */ + snake->nb_pixels = snake_nodes[i].nb_pixels ; + snake->posi = snake_nodes[i].posi ; + snake->posj = snake_nodes[i].posj ; + /* + snake->centre_i = snake_nodes[i].centre_i ; + snake->centre_j = snake_nodes[i].centre_j ; + snake->last_move = snake_nodes[i].last_move ; + */ + } + + /*verif integrite donnees*/ + + snake = *h_snake ; + for (int i=0; icode_segment ) ; + printf("\tfreeman_in : %d\n", snake->freeman_in ); + printf("\tfreeman_out : %d\n", snake->freeman_out ) ; + */ + printf("\tnb_pixels : %d", snake->nb_pixels ) ; + + printf("\ti = %d ", snake->posi ) ; + printf("\tj = %d \n", snake->posj ) ; + /* + printf("\tcentre i = %d\n", snake->centre_i ) ; + printf("\tcentre j = %d\n", snake->centre_j ) ; + + printf("\tcontribs = %lu - %lu - %lu\n", snake->contrib.sum_1, snake->contrib.sum_x, snake->contrib.sum_x2 ) ; + + printf("\tlast_move : %d\n", snake->last_move ) ; + */ + snake = snake->noeud_suiv; + } + delete snake_nodes; +} + +void dessine_snake(snake_node_gpu * snake, int nnodes, unsigned short ** img, int r){ + int couleur = 255; + int i,j; + for (int node=0;node < nnodes; node++){ + i = snake[node].posi ; + j = snake[node].posj ; + for (int xi=0; xi<=r; xi++){ + img[i-xi][j] = couleur ; + img[i+xi][j] = couleur ; + img[i][j-xi] = couleur ; + img[i][j+xi] = couleur ; + } + } +} \ No newline at end of file diff --git a/src/lib_snake_2_gpu.cu~ b/src/lib_snake_2_gpu.cu~ new file mode 100644 index 0000000..3f44329 --- /dev/null +++ b/src/lib_snake_2_gpu.cu~ @@ -0,0 +1,126 @@ + +extern "C"{ +#include "structures.h" +#include "lib_snake_2_gpu.h" +} +#include "stdio.h" + +void snake2gpu( snake_node_gpu * d_snake, snake_node* h_snake, int n ){ + + snake_node * snake = h_snake; + snake_node_gpu snake_nodes[n]; + + for (int i=0; icontrib.sum_1 ; + snake_nodes[i].sum_x = snake->contrib.sum_x ; + snake_nodes[i].sum_x2 = snake->contrib.sum_x2 ; + + snake_nodes[i].code_segment = snake->code_segment ; + snake_nodes[i].freeman_in = snake->freeman_in ; + snake_nodes[i].freeman_out = snake->freeman_out ; + snake_nodes[i].nb_pixels = snake->nb_pixels ; + + snake_nodes[i].posi = snake->posi ; + snake_nodes[i].posj = snake->posj ; + snake_nodes[i].centre_i = snake->centre_i ; + snake_nodes[i].centre_j = snake->centre_j ; + + snake_nodes[i].last_move = snake->last_move ; + + snake = snake->noeud_suiv ; + } + + cudaMemcpy( d_snake, snake_nodes, n*sizeof(snake_node_gpu), cudaMemcpyHostToDevice ); + + /*verif integrite data*/ + /* + snake_node_gpu new_snake_nodes[n]; + cudaMemcpy( new_snake_nodes , d_snake, n*sizeof(snake_node_gpu), cudaMemcpyDeviceToHost ); + + for (int i=0; inoeud_suiv = snake; + snake->noeud_prec = snake_prec; + } + if (i == n-1) { + snake->noeud_suiv = *h_snake; + (*h_snake)->noeud_prec = snake; + } + /* + snake->contrib.sum_1 = snake_nodes[i].sum_1 ; + snake->contrib.sum_x = snake_nodes[i].sum_x ; + snake->contrib.sum_x2 = snake_nodes[i].sum_x2 ; + + snake->code_segment = snake_nodes[i].code_segment ; + snake->freeman_in = snake_nodes[i].freeman_in ; + snake->freeman_out = snake_nodes[i].freeman_out ; + */ + snake->nb_pixels = snake_nodes[i].nb_pixels ; + snake->posi = snake_nodes[i].posi ; + snake->posj = snake_nodes[i].posj ; + /* + snake->centre_i = snake_nodes[i].centre_i ; + snake->centre_j = snake_nodes[i].centre_j ; + snake->last_move = snake_nodes[i].last_move ; + */ + } + + /*verif integrite donnees*/ + + snake = *h_snake ; + for (int i=0; icode_segment ) ; + printf("\tfreeman_in : %d\n", snake->freeman_in ); + printf("\tfreeman_out : %d\n", snake->freeman_out ) ; + */ + printf("\tnb_pixels : %d", snake->nb_pixels ) ; + + printf("\ti = %d ", snake->posi ) ; + printf("\tj = %d \n", snake->posj ) ; + /* + printf("\tcentre i = %d\n", snake->centre_i ) ; + printf("\tcentre j = %d\n", snake->centre_j ) ; + + printf("\tcontribs = %lu - %lu - %lu\n", snake->contrib.sum_1, snake->contrib.sum_x, snake->contrib.sum_x2 ) ; + + printf("\tlast_move : %d\n", snake->last_move ) ; + */ + snake = snake->noeud_suiv; + } + delete snake_nodes; +} diff --git a/src/lib_snake_2_gpu.h b/src/lib_snake_2_gpu.h new file mode 100644 index 0000000..b4fa104 --- /dev/null +++ b/src/lib_snake_2_gpu.h @@ -0,0 +1,9 @@ +#ifndef __LIB_SNAKE_2_GPU_H__ +#define __LIB_SNAKE_2_GPU_H__ + +void snake2gpu( struct snake_node_gpu * d_snake, struct snake_node * h_snake, int n ); + +void gpu2snake( struct snake_node_gpu * d_snake, struct snake_node ** h_snake, int n ); + +void dessine_snake(snake_node_gpu * snake, int nnodes, unsigned short ** img, int r); +#endif diff --git a/src/lib_snake_2_gpu.h~ b/src/lib_snake_2_gpu.h~ new file mode 100644 index 0000000..506c387 --- /dev/null +++ b/src/lib_snake_2_gpu.h~ @@ -0,0 +1,8 @@ +#ifndef __LIB_SNAKE_2_GPU_H__ +#define __LIB_SNAKE_2_GPU_H__ + +void snake2gpu( struct snake_node_gpu * d_snake, struct snake_node * h_snake, int n ); + +void gpu2snake( struct snake_node_gpu * d_snake, struct snake_node ** h_snake, int n ); + +#endif diff --git a/src/lib_snake_common.c b/src/lib_snake_common.c new file mode 100644 index 0000000..dc2b49e --- /dev/null +++ b/src/lib_snake_common.c @@ -0,0 +1,723 @@ +/** + * \file lib_snake_common.c + * \brief routines de bases pour la gestion du snake + * \author NB - PhyTI + * \version x.x + * \date 25 decembre 2009 + * + */ + +#include + +#include "lib_snake_common.h" +#include "lib_contour.h" +#include "lib_math.h" + + +/* debug */ +#include +#include "lib_images.h" +#include "lib_alloc.h" + + +/** + * \fn struct snake_node* genere_snake_rectangle_bords(int *nb_noeud, int distance_bords, + * int i_dim, int j_dim) + * + * \brief Initialise un snake rectangulaire par rapport au bords de l'image + * \author NB - PhyTI + * + * \param[out] nb_noeud renvoie le nombre de node du snake + * \param[in] distance_bords distance du rectangle par rapport au bords + * \param[in] i_dim dimension verticale de l'image + * \param[in] j_dim dimension horizontale de l'image + * + * \return le pointeur du premier noeud du snake + * + * note : les calculs sse necessite l'alignement memoire des snake_node + */ +struct snake_node* genere_snake_rectangle_bords(uint32 *nb_noeud, uint32 distance_bords, + uint32 i_dim, uint32 j_dim) +{ + struct snake_node *n1, *n2, *n3 ; /* noeuds courant */ + struct snake_node *n0 = malloc(sizeof(struct snake_node)) ; + + /* n0 */ + *nb_noeud = 1 ; + n0->posi = distance_bords ; + n0->posj = distance_bords ; + n0->noeud_suiv = malloc(sizeof(struct snake_node)) ; + (*nb_noeud)++ ; + /* n1 */ + n1 = n0->noeud_suiv ; + n1->posi = i_dim - distance_bords ; + n1->posj = distance_bords ; + n1->noeud_prec = n0 ; + n1->noeud_suiv = malloc(sizeof(struct snake_node)) ; + (*nb_noeud)++ ; + /* n2 */ + n2 = n1->noeud_suiv ; + n2->posi = i_dim - distance_bords ; + n2->posj = j_dim - distance_bords ; + n2->noeud_prec = n1 ; + n2->noeud_suiv = malloc(sizeof(struct snake_node)) ; + (*nb_noeud)++ ; + /* n3 */ + n3 = n2->noeud_suiv ; + n3->posi = distance_bords ; + n3->posj = j_dim - distance_bords ; + n3->noeud_prec = n2 ; + n3->noeud_suiv = n0 ; /* on ferme le snake */ + /* n0, on ferme le snake */ + n0->noeud_prec = n3 ; + + return n0 ; +} + +/** + * \fn struct snake_node* genere_snake_rectangle(int *nb_noeud,int i1,int j1,int i2,int j2, + * int i_dim, int j_dim) + * + * \brief Initialise un snake rectangulaire definie par deux noeuds + * \author NB - PhyTI + * + * \param[out] nb_noeud renvoie le nombre de node du snake + * \param[in] i1 coordonnee du coin haut-gauche + * \param[in] j1 coordonnee du coin haut-gauche + * \param[in] i2 coordonnee du coin bas-droit + * \param[in] j2 coordonnee du coin bas-droit + * \param[in] i_dim dimension verticale de l'image + * \param[in] j_dim dimension horizontale de l'image + * + * \return le pointeur du premier noeud du snake + * + * note : les calculs sse necessite l'alignement memoire des snake_node + */ +struct snake_node* genere_snake_rectangle(int *nb_noeud, uint32 i1, uint32 j1, uint32 i2, uint32 j2, + uint32 i_dim, uint32 j_dim) +{ + struct snake_node *n1, *n2, *n3 ; /* noeuds courant */ + struct snake_node *n0 = malloc(sizeof(struct snake_node)) ; + + /* n0 */ + *nb_noeud = 1 ; + n0->posi = i1 ; + n0->posj = j1 ; + n0->noeud_suiv = malloc(sizeof(struct snake_node)) ; + (*nb_noeud)++ ; + /* n1 */ + n1 = n0->noeud_suiv ; + n1->posi = i2 ; + n1->posj = j1 ; + n1->noeud_prec = n0 ; + n1->noeud_suiv = malloc(sizeof(struct snake_node)) ; + (*nb_noeud)++ ; + /* n2 */ + n2 = n1->noeud_suiv ; + n2->posi = i2 ; + n2->posj = j2 ; + n2->noeud_prec = n1 ; + n2->noeud_suiv = malloc(sizeof(struct snake_node)) ; + (*nb_noeud)++ ; + /* n3 */ + n3 = n2->noeud_suiv ; + n3->posi = i1 ; + n3->posj = j2 ; + n3->noeud_prec = n2 ; + n3->noeud_suiv = n0 ; /* on ferme le snake */ + /* n0, on ferme le snake */ + n0->noeud_prec = n3 ; + + return n0 ; +} + + + + + + +/** + * \fn int affiche_snake(int **image, struct snake_node *snake, + * int valseg, int valnoeud, int *liste_pixel_segment) + * + * \brief Affiche le snake sur une image N&B + * \author NB - PhyTI + * + * \param[out] image image ou le snake doit etre affiche + * \param[in] snake premier noeud du snake + * \param[in] valseg valeur de niveau de gris des segments + * \param[in] valnoeud valeur de niveau de gris des noeuds + * \param[out] liste_pixel_segment pour caluls temporaire + * + * \return nb_noeud le nombre de noeuds du snake + * + */ +void affiche_snake(int **image, struct snake_node *snake, int valseg, int valnoeud, + uint32 *liste_pixel_segment) +{ + uint32 i1, j1, i2, j2 ; + uint32 n, nb_pixel_segment ; + struct snake_node *np, *npp1 ; + + /* les segments */ + np = snake ; + npp1 = snake->noeud_suiv ; + do + { + i1 = np->posi ; j1 = np->posj ; + i2 = npp1->posi ; j2 = npp1->posj ; + + nb_pixel_segment = calcul_liste_pixel_segment(i1,j1,i2,j2, liste_pixel_segment, 0) ; + for (n=1; nnoeud_suiv ; + } + while (np != snake) ; + + /* les deux noeuds */ + np = snake ; + npp1 = snake->noeud_suiv ; + do + { + i1 = np->posi ; j1 = np->posj ; + i2 = npp1->posi ; j2 = npp1->posj ; + + image[i1][j1] = valnoeud ; + image[i2][j2] = valnoeud ; + + np = npp1 ; + npp1 = np->noeud_suiv ; + } + while (np != snake) ; +} + +void affiche_snake_ushort(unsigned short **image, struct snake_node *snake, int valseg, unsigned short valnoeud, + uint32 *liste_pixel_segment) +{ + uint32 i1, j1, i2, j2 ; + uint32 n, nb_pixel_segment ; + struct snake_node *np, *npp1 ; + + /* les segments */ + np = snake ; + npp1 = snake->noeud_suiv ; + + do + { + i1 = np->posi ; j1 = np->posj ; + i2 = npp1->posi ; j2 = npp1->posj ; + + nb_pixel_segment = calcul_liste_pixel_segment(i1,j1,i2,j2, liste_pixel_segment, 0) ; + + for (n=1; nnoeud_suiv ; + + } + while (np != snake) ; + + /* les deux noeuds */ + np = snake ; + npp1 = snake->noeud_suiv ; + /* + do + { + i1 = np->posi ; j1 = np->posj ; + i2 = npp1->posi ; j2 = npp1->posj ; + + image[i1][j1] = valnoeud ; + image[i2][j2] = valnoeud ; + + np = npp1 ; + npp1 = np->noeud_suiv ; + } + while (np != snake) ; + */ +} + +/* ========== DEBUG ================= */ +/* fonction d'affichage pour le debug */ +/* affiche les deux premiers segments avec valseg-1 */ +/* et incremenent les valeurs des noeuds */ +void affiche_snake_couleur(int **image, struct snake_node *snake, int valseg, int valnoeud, + uint32 *liste_pixel_segment) +{ + uint32 i1, j1, i2, j2 ; + uint32 n, nb_pixel_segment ; + struct snake_node *np, *npp1 ; + int cpt = 0; + snake = snake->noeud_prec ; + + /* les segments */ + np = snake ; + npp1 = np->noeud_suiv ; + do + { + i1 = np->posi ; j1 = np->posj ; + i2 = npp1->posi ; j2 = npp1->posj ; + + nb_pixel_segment = calcul_liste_pixel_segment(i1,j1,i2,j2, liste_pixel_segment, 0) ; + if (cpt < 2 ) + for (n=1; nnoeud_suiv ; + } + while (np != snake) ; + + /* les deux noeuds */ + cpt = 0 ; + np = snake ; + npp1 = snake->noeud_suiv ; + do + { + i1 = np->posi ; j1 = np->posj ; + i2 = npp1->posi ; j2 = npp1->posj ; + + image[i1][j1] = valnoeud+cpt ; + image[i2][j2] = valnoeud+cpt++ ; + + np = npp1 ; + npp1 = np->noeud_suiv ; + } + while (np != snake) ; +} + +/* ========= DEBUG ===================== */ +/* copie l'image du snake avec un numero */ +/* de fichier incremente a chaque appel */ +void debug_aff_snake(struct snake_node *snake) +{ + const int idim=256, jdim=256 ; + + int **image = new_matrix_int(idim, jdim) ; + uint32 *liste_pixel = malloc(sizeof(int)*2*(idim+jdim)) ; + static int iter=0 ; + char output[256] ; + int n; + + for (n=0; nposi = node->centre_i ; + najout->posj = node->centre_j ; + + najout->noeud_prec = node ; + najout->noeud_suiv = node->noeud_suiv ; + node->noeud_suiv->noeud_prec = najout ; + node->noeud_suiv = najout ; + + (*nb_noeud)++ ; + return najout ; +} + + + + +/** + * \fn inline int test_croisement_segment_large(int Ai, int Aj, int Bi, int Bj, + * int Ui, int Uj, int Vi, int Vj) + * + * \brief Test qui determine si deux segments croisent + * \author NB - PhyTI + * + * \param[in] Ai + * \param[in] Aj + * \param[in] Bi + * \param[in] Bj + * \param[in] Ui + * \param[in] Uj + * \param[in] Vi + * \param[in] Vj + * + * \return 1 si croisement, 0 sinon + * + * Version large : autorise les triangles nulles + * Test de croisement des segments : + * si deux segments AB et UV croisent, alors + * les triangles ABU et ABV change d'ordre de rotation + * ET + * les triangles UVA et UVB change aussi d'ordre de rotation + * + */ +inline int test_croisement_segment_large(uint32 Ai, uint32 Aj, uint32 Bi, uint32 Bj, + uint32 Ui, uint32 Uj, uint32 Vi, uint32 Vj) +{ + if (sign_diff_strict(sinus_triangle(Ai, Aj, Bi, Bj, Ui, Uj), // Bi-Ai, Uj-Aj, Ui-Ai, Bj-Aj + sinus_triangle(Ai, Aj, Bi, Bj, Vi, Vj))) // Bi-Ai, Vj-Aj, Vi-Ai, Bj-Aj + if (sign_diff_strict(sinus_triangle(Ui, Uj, Vi, Vj, Ai, Aj), // Vi-Ui, Aj-Uj, Ai-Ui, Vj-Uj + sinus_triangle(Ui, Uj, Vi, Vj, Bi, Bj))) // Vi-Ui, Bj-Uj, Bi-Ui, Vj-Uj + return 1 ; + return 0 ; +} + + +/** + * \fn inline int test_croisement_segment_strict(int Ai, int Aj, int Bi, int Bj, + * int Ui, int Uj, int Vi, int Vj) + * + * \brief Test qui determine si deux segments croisent + * \author NB - PhyTI + * + * \param[in] Ai + * \param[in] Aj + * \param[in] Bi + * \param[in] Bj + * \param[in] Ui + * \param[in] Uj + * \param[in] Vi + * \param[in] Vj + * + * \return 1 si croisement, 0 sinon + * + * Version strict : n'autorise pas les triangles nulles + * Test de croisement des segments : + * si deux segments AB et UV croisent, alors + * les triangles ABU et ABV change d'ordre de rotation + * ET + * les triangles UVA et UVB change aussi d'ordre de rotation + * + */ +inline int test_croisement_segment_strict(uint32 Ai, uint32 Aj, uint32 Bi, uint32 Bj, + uint32 Ui, uint32 Uj, uint32 Vi, uint32 Vj) +{ + if (sign_diff_ou_egal_zero(sinus_triangle(Ai, Aj, Bi, Bj, Ui, Uj), + sinus_triangle(Ai, Aj, Bi, Bj, Vi, Vj))) + if (sign_diff_ou_egal_zero(sinus_triangle(Ui, Uj, Vi, Vj, Ai, Aj), + sinus_triangle(Ui, Uj, Vi, Vj, Bi, Bj))) + return 1 ; + return 0 ; +} + + + + + +/** + * \fn int test_croisement_add_noeud_large(struct snake_node *N, int Nxi, int Nxj, int seg) + * + * \brief test si il y a croisement de segments lors de l'ajout d'un noeud + * \author NB - PhyTI + * + * \param[in] N le noeud ou l'on veut ajouter un noeud Nx au milieu de son segment + * \param[in] Nxi coordonnee i du nouveau node Nx + * \param[in] Nxj coordonnee j du nouveau node Nx + * \param[in] seg booleen pour definir quel segment on test: + * Nx --> Nsuiv si seg==1 + * N --> Nx si seg==0 + * + * \return 1 si croisement, 0 sinon + * + * Version large : autorise les triangles nulles + * + */ +int test_croisement_add_noeud_large(struct snake_node *N, uint32 Nxi, uint32 Nxj, int seg) +{ + uint32 Nrefi=0, Nrefj=0 ; /* reference avec Nxi et Nxj */ + uint32 posi, posj, suivi, suivj ; /* segment courant de test */ + struct snake_node *node, *end ; + + if (seg==1) + { + Nrefi = N->noeud_suiv->posi ; + Nrefj = N->noeud_suiv->posj ; + } + else + { + Nrefi = N->posi ; + Nrefj = N->posj ; + } + + node = N->noeud_suiv ; + suivi = node->posi ; + suivj = node->posj ; + + end = N ; + while (node != end) + { + posi = suivi ; + posj = suivj ; + node = node->noeud_suiv ; + suivi = node->posi ; + suivj = node->posj ; + if (test_croisement_segment_large(Nxi,Nxj,Nrefi,Nrefj, posi,posj,suivi,suivj)) + return 1 ; + } + return 0 ; +} + + + +/** + * \fn int test_croisement_add_noeud_strict(struct snake_node *N, int Nxi, int Nxj, int seg) + * + * \brief test si il y a croisement de segments lors de l'ajout d'un noeud + * \author NB - PhyTI + * + * \param[in] N le noeud ou l'on veut ajouter un noeud Nx au milieu de son segment + * \param[in] Nxi coordonnee i du nouveau node Nx + * \param[in] Nxj coordonnee j du nouveau node Nx + * \param[in] seg booleen pour definir quel segment on test: + * Nx --> Nsuiv si seg==1 + * N --> Nx si seg==0 + * + * \return 1 si croisement, 0 sinon + * + * Version strict : n'autorise pas les triangles nulles + * + */ +int test_croisement_add_noeud_strict(struct snake_node *N, uint32 Nxi, uint32 Nxj, int seg) +{ + uint32 Nrefi=0, Nrefj=0 ; /* reference avec Nxi et Nxj */ + uint32 posi, posj, suivi, suivj ; /* segment courant de test */ + struct snake_node *node, *end ; + + /* segment de reference */ + if (seg) + { + Nrefi = N->noeud_suiv->posi ; + Nrefj = N->noeud_suiv->posj ; + } + else + { + Nrefi = N->posi ; + Nrefj = N->posj ; + } + + /* segments de tests */ + node = N->noeud_suiv ; + suivi = node->posi ; + suivj = node->posj ; + + if (seg) + { + /* premier segment : il touche le segment de ref */ + /* pour Nx --> Nsuiv(ref) */ + posi = suivi ; + posj = suivj ; + node = node->noeud_suiv ; + suivi = node->posi ; + suivj = node->posj ; + if (test_croisement_segment_large(Nxi,Nxj,Nrefi,Nrefj,posi,posj,suivi,suivj)) + return 1 ; + end = N ; /* pour boucle while */ + } + else + /* pour N --> Nx */ + end = N->noeud_prec ; /* pour boucle while */ + + /* boucle sur les segments */ + while (node != end) + { + posi = suivi ; + posj = suivj ; + node = node->noeud_suiv ; + suivi = node->posi ; + suivj = node->posj ; + if (test_croisement_segment_strict(posi,posj,suivi,suivj,Nxi,Nxj,Nrefi,Nrefj)) + return 1 ; + } + + /* dernier segment */ + /* cas N --> Nx */ + if (!seg) + { + posi = suivi ; + posj = suivj ; + node = node->noeud_suiv ; + suivi = node->posi ; + suivj = node->posj ; + if (test_croisement_segment_large(Nxi,Nxj,Nrefi,Nrefj, posi,posj,suivi,suivj)) + return 1 ; + } + return 0 ; +} + + + + + + +/** + * \fn int test_croisement_move_seg_large(struct snake_node *Nx, int Nxi, int Nxj, int seg) + * + * \brief test si il y a croisement de segments lors du deplacement d'un noeud + * \author NB - PhyTI + * + * \param[in] Nx le noeud que l'on veut deplacer + * \param[in] Nxi coordonnee i du nouveau node Nx + * \param[in] Nxj coordonnee j du nouveau node Nx + * \param[in] seg booleen pour definir quel segment on test: + * Nx --> Nsuiv si seg==1 + * Nprec --> Nx si seg==0 + * + * \return 1 si croisement, 0 sinon + * + * Version large : autorise les triangles nulles + * Version non optimisee car elle test systematiquement tout les segments du snake ! + * + */ +int test_croisement_move_seg_large(struct snake_node *Nx, uint32 Nxi, uint32 Nxj, int seg) +{ + uint32 Nrefi=0, Nrefj=0 ; /* reference avec Nxi et Nxj */ + uint32 posi, posj, suivi, suivj ; /* segment courant de test */ + struct snake_node *node, *end ; + + if (seg==1) + { + Nrefi = Nx->noeud_suiv->posi ; + Nrefj = Nx->noeud_suiv->posj ; + } + else + { + Nrefi = Nx->noeud_prec->posi ; + Nrefj = Nx->noeud_prec->posj ; + } + + node = Nx->noeud_suiv ; + suivi = node->posi ; + suivj = node->posj ; + + end = Nx->noeud_prec ; + while (node != end) + { + posi = suivi ; + posj = suivj ; + node = node->noeud_suiv ; + suivi = node->posi ; + suivj = node->posj ; + if (test_croisement_segment_large(Nxi,Nxj,Nrefi,Nrefj, posi,posj,suivi,suivj)) + return 1 ; + } + return 0 ; +} + + + +/** + * \fn int test_croisement_move_seg_strict(struct snake_node *Nx, int Nxi, int Nxj, int seg) + * + * \brief test si il y a croisement de segments lors du deplacement d'un noeud + * \author NB - PhyTI + * + * \param[in] Nx le noeud que l'on veut deplacer + * \param[in] Nxi coordonnee i du nouveau node Nx + * \param[in] Nxj coordonnee j du nouveau node Nx + * \param[in] seg booleen pour definir quel segment on test: + * Nx --> Nsuiv si seg==1 + * Nprec --> Nx si seg==0 + * + * \return 1 si croisement, 0 sinon + * + * Version strict : n'autorise pas les triangles nulles + * Version non optimisee car elle test systematiquement tout les segments du snake ! + */ +int test_croisement_move_seg_strict(struct snake_node *Nx, uint32 Nxi, uint32 Nxj, int seg) +{ + uint32 Nrefi=0, Nrefj=0 ; /* reference avec Nxi et Nxj */ + uint32 posi, posj, suivi, suivj ; /* segment courant de test */ + struct snake_node *node, *end ; + + /* segment de reference */ + if (seg) + { + Nrefi = Nx->noeud_suiv->posi ; + Nrefj = Nx->noeud_suiv->posj ; + } + else + { + Nrefi = Nx->noeud_prec->posi ; + Nrefj = Nx->noeud_prec->posj ; + } + + /* segments de tests */ + node = Nx->noeud_suiv ; + suivi = node->posi ; + suivj = node->posj ; + + if (seg) + { + /* premier segment : il touche le segment de ref */ + /* pour Nx --> Nsuiv(ref) */ + posi = suivi ; + posj = suivj ; + node = node->noeud_suiv ; + suivi = node->posi ; + suivj = node->posj ; + if (test_croisement_segment_large(Nxi,Nxj,Nrefi,Nrefj,posi,posj,suivi,suivj)) + return 1 ; + + end = Nx->noeud_prec ; /* pour boucle while */ + } + else + /* pour Nprec --> Nx */ + end = Nx->noeud_prec->noeud_prec ; /* pour boucle while */ + + /* boucle sur les segments */ + while (node != end) + { + posi = suivi ; + posj = suivj ; + node = node->noeud_suiv ; + suivi = node->posi ; + suivj = node->posj ; + if (test_croisement_segment_strict(posi,posj,suivi,suivj,Nxi,Nxj,Nrefi,Nrefj)) + return 1 ; + } + + /* dernier segment */ + /* cas Nprec --> Nx */ + if (!seg) + { + posi = suivi ; + posj = suivj ; + node = node->noeud_suiv ; + suivi = node->posi ; + suivj = node->posj ; + if (test_croisement_segment_large(Nxi,Nxj,Nrefi,Nrefj, posi,posj,suivi,suivj)) + return 1 ; + } + return 0 ; +} + diff --git a/src/lib_snake_common.c~ b/src/lib_snake_common.c~ new file mode 100644 index 0000000..ed1bfc8 --- /dev/null +++ b/src/lib_snake_common.c~ @@ -0,0 +1,718 @@ +/** + * \file lib_snake_common.c + * \brief routines de bases pour la gestion du snake + * \author NB - PhyTI + * \version x.x + * \date 25 decembre 2009 + * + */ + +#include + +#include "lib_snake_common.h" +#include "lib_contour.h" +#include "lib_math.h" + + +/* debug */ +#include +#include "lib_images.h" +#include "lib_alloc.h" + + +/** + * \fn struct snake_node* genere_snake_rectangle_bords(int *nb_noeud, int distance_bords, + * int i_dim, int j_dim) + * + * \brief Initialise un snake rectangulaire par rapport au bords de l'image + * \author NB - PhyTI + * + * \param[out] nb_noeud renvoie le nombre de node du snake + * \param[in] distance_bords distance du rectangle par rapport au bords + * \param[in] i_dim dimension verticale de l'image + * \param[in] j_dim dimension horizontale de l'image + * + * \return le pointeur du premier noeud du snake + * + * note : les calculs sse necessite l'alignement memoire des snake_node + */ +struct snake_node* genere_snake_rectangle_bords(uint32 *nb_noeud, uint32 distance_bords, + uint32 i_dim, uint32 j_dim) +{ + struct snake_node *n1, *n2, *n3 ; /* noeuds courant */ + struct snake_node *n0 = malloc(sizeof(struct snake_node)) ; + + /* n0 */ + *nb_noeud = 1 ; + n0->posi = distance_bords ; + n0->posj = distance_bords ; + n0->noeud_suiv = malloc(sizeof(struct snake_node)) ; + (*nb_noeud)++ ; + /* n1 */ + n1 = n0->noeud_suiv ; + n1->posi = i_dim - distance_bords ; + n1->posj = distance_bords ; + n1->noeud_prec = n0 ; + n1->noeud_suiv = malloc(sizeof(struct snake_node)) ; + (*nb_noeud)++ ; + /* n2 */ + n2 = n1->noeud_suiv ; + n2->posi = i_dim - distance_bords ; + n2->posj = j_dim - distance_bords ; + n2->noeud_prec = n1 ; + n2->noeud_suiv = malloc(sizeof(struct snake_node)) ; + (*nb_noeud)++ ; + /* n3 */ + n3 = n2->noeud_suiv ; + n3->posi = distance_bords ; + n3->posj = j_dim - distance_bords ; + n3->noeud_prec = n2 ; + n3->noeud_suiv = n0 ; /* on ferme le snake */ + /* n0, on ferme le snake */ + n0->noeud_prec = n3 ; + + return n0 ; +} + +/** + * \fn struct snake_node* genere_snake_rectangle(int *nb_noeud,int i1,int j1,int i2,int j2, + * int i_dim, int j_dim) + * + * \brief Initialise un snake rectangulaire definie par deux noeuds + * \author NB - PhyTI + * + * \param[out] nb_noeud renvoie le nombre de node du snake + * \param[in] i1 coordonnee du coin haut-gauche + * \param[in] j1 coordonnee du coin haut-gauche + * \param[in] i2 coordonnee du coin bas-droit + * \param[in] j2 coordonnee du coin bas-droit + * \param[in] i_dim dimension verticale de l'image + * \param[in] j_dim dimension horizontale de l'image + * + * \return le pointeur du premier noeud du snake + * + * note : les calculs sse necessite l'alignement memoire des snake_node + */ +struct snake_node* genere_snake_rectangle(int *nb_noeud, uint32 i1, uint32 j1, uint32 i2, uint32 j2, + uint32 i_dim, uint32 j_dim) +{ + struct snake_node *n1, *n2, *n3 ; /* noeuds courant */ + struct snake_node *n0 = malloc(sizeof(struct snake_node)) ; + + /* n0 */ + *nb_noeud = 1 ; + n0->posi = i1 ; + n0->posj = j1 ; + n0->noeud_suiv = malloc(sizeof(struct snake_node)) ; + (*nb_noeud)++ ; + /* n1 */ + n1 = n0->noeud_suiv ; + n1->posi = i2 ; + n1->posj = j1 ; + n1->noeud_prec = n0 ; + n1->noeud_suiv = malloc(sizeof(struct snake_node)) ; + (*nb_noeud)++ ; + /* n2 */ + n2 = n1->noeud_suiv ; + n2->posi = i2 ; + n2->posj = j2 ; + n2->noeud_prec = n1 ; + n2->noeud_suiv = malloc(sizeof(struct snake_node)) ; + (*nb_noeud)++ ; + /* n3 */ + n3 = n2->noeud_suiv ; + n3->posi = i1 ; + n3->posj = j2 ; + n3->noeud_prec = n2 ; + n3->noeud_suiv = n0 ; /* on ferme le snake */ + /* n0, on ferme le snake */ + n0->noeud_prec = n3 ; + + return n0 ; +} + + + + + + +/** + * \fn int affiche_snake(int **image, struct snake_node *snake, + * int valseg, int valnoeud, int *liste_pixel_segment) + * + * \brief Affiche le snake sur une image N&B + * \author NB - PhyTI + * + * \param[out] image image ou le snake doit etre affiche + * \param[in] snake premier noeud du snake + * \param[in] valseg valeur de niveau de gris des segments + * \param[in] valnoeud valeur de niveau de gris des noeuds + * \param[out] liste_pixel_segment pour caluls temporaire + * + * \return nb_noeud le nombre de noeuds du snake + * + */ +void affiche_snake(int **image, struct snake_node *snake, int valseg, int valnoeud, + uint32 *liste_pixel_segment) +{ + uint32 i1, j1, i2, j2 ; + uint32 n, nb_pixel_segment ; + struct snake_node *np, *npp1 ; + + /* les segments */ + np = snake ; + npp1 = snake->noeud_suiv ; + do + { + i1 = np->posi ; j1 = np->posj ; + i2 = npp1->posi ; j2 = npp1->posj ; + + nb_pixel_segment = calcul_liste_pixel_segment(i1,j1,i2,j2, liste_pixel_segment, 0) ; + for (n=1; nnoeud_suiv ; + } + while (np != snake) ; + + /* les deux noeuds */ + np = snake ; + npp1 = snake->noeud_suiv ; + do + { + i1 = np->posi ; j1 = np->posj ; + i2 = npp1->posi ; j2 = npp1->posj ; + + image[i1][j1] = valnoeud ; + image[i2][j2] = valnoeud ; + + np = npp1 ; + npp1 = np->noeud_suiv ; + } + while (np != snake) ; +} + +void affiche_snake_ushort(unsigned short **image, struct snake_node *snake, int valseg, unsigned short valnoeud, + uint32 *liste_pixel_segment) +{ + uint32 i1, j1, i2, j2 ; + uint32 n, nb_pixel_segment ; + struct snake_node *np, *npp1 ; + + /* les segments */ + np = snake ; + npp1 = snake->noeud_suiv ; + do + { + i1 = np->posi ; j1 = np->posj ; + i2 = npp1->posi ; j2 = npp1->posj ; + + nb_pixel_segment = calcul_liste_pixel_segment(i1,j1,i2,j2, liste_pixel_segment, 0) ; + for (n=1; nnoeud_suiv ; + } + while (np != snake) ; + + /* les deux noeuds */ + np = snake ; + npp1 = snake->noeud_suiv ; + do + { + i1 = np->posi ; j1 = np->posj ; + i2 = npp1->posi ; j2 = npp1->posj ; + + image[i1][j1] = valnoeud ; + image[i2][j2] = valnoeud ; + + np = npp1 ; + npp1 = np->noeud_suiv ; + } + while (np != snake) ; +} + +/* ========== DEBUG ================= */ +/* fonction d'affichage pour le debug */ +/* affiche les deux premiers segments avec valseg-1 */ +/* et incremenent les valeurs des noeuds */ +void affiche_snake_couleur(int **image, struct snake_node *snake, int valseg, int valnoeud, + uint32 *liste_pixel_segment) +{ + uint32 i1, j1, i2, j2 ; + uint32 n, nb_pixel_segment ; + struct snake_node *np, *npp1 ; + int cpt = 0; + snake = snake->noeud_prec ; + + /* les segments */ + np = snake ; + npp1 = np->noeud_suiv ; + do + { + i1 = np->posi ; j1 = np->posj ; + i2 = npp1->posi ; j2 = npp1->posj ; + + nb_pixel_segment = calcul_liste_pixel_segment(i1,j1,i2,j2, liste_pixel_segment, 0) ; + if (cpt < 2 ) + for (n=1; nnoeud_suiv ; + } + while (np != snake) ; + + /* les deux noeuds */ + cpt = 0 ; + np = snake ; + npp1 = snake->noeud_suiv ; + do + { + i1 = np->posi ; j1 = np->posj ; + i2 = npp1->posi ; j2 = npp1->posj ; + + image[i1][j1] = valnoeud+cpt ; + image[i2][j2] = valnoeud+cpt++ ; + + np = npp1 ; + npp1 = np->noeud_suiv ; + } + while (np != snake) ; +} + +/* ========= DEBUG ===================== */ +/* copie l'image du snake avec un numero */ +/* de fichier incremente a chaque appel */ +void debug_aff_snake(struct snake_node *snake) +{ + const int idim=256, jdim=256 ; + + int **image = new_matrix_int(idim, jdim) ; + uint32 *liste_pixel = malloc(sizeof(int)*2*(idim+jdim)) ; + static int iter=0 ; + char output[256] ; + int n; + + for (n=0; nposi = node->centre_i ; + najout->posj = node->centre_j ; + + najout->noeud_prec = node ; + najout->noeud_suiv = node->noeud_suiv ; + node->noeud_suiv->noeud_prec = najout ; + node->noeud_suiv = najout ; + + (*nb_noeud)++ ; + return najout ; +} + + + + +/** + * \fn inline int test_croisement_segment_large(int Ai, int Aj, int Bi, int Bj, + * int Ui, int Uj, int Vi, int Vj) + * + * \brief Test qui determine si deux segments croisent + * \author NB - PhyTI + * + * \param[in] Ai + * \param[in] Aj + * \param[in] Bi + * \param[in] Bj + * \param[in] Ui + * \param[in] Uj + * \param[in] Vi + * \param[in] Vj + * + * \return 1 si croisement, 0 sinon + * + * Version large : autorise les triangles nulles + * Test de croisement des segments : + * si deux segments AB et UV croisent, alors + * les triangles ABU et ABV change d'ordre de rotation + * ET + * les triangles UVA et UVB change aussi d'ordre de rotation + * + */ +inline int test_croisement_segment_large(uint32 Ai, uint32 Aj, uint32 Bi, uint32 Bj, + uint32 Ui, uint32 Uj, uint32 Vi, uint32 Vj) +{ + if (sign_diff_strict(sinus_triangle(Ai, Aj, Bi, Bj, Ui, Uj), // Bi-Ai, Uj-Aj, Ui-Ai, Bj-Aj + sinus_triangle(Ai, Aj, Bi, Bj, Vi, Vj))) // Bi-Ai, Vj-Aj, Vi-Ai, Bj-Aj + if (sign_diff_strict(sinus_triangle(Ui, Uj, Vi, Vj, Ai, Aj), // Vi-Ui, Aj-Uj, Ai-Ui, Vj-Uj + sinus_triangle(Ui, Uj, Vi, Vj, Bi, Bj))) // Vi-Ui, Bj-Uj, Bi-Ui, Vj-Uj + return 1 ; + return 0 ; +} + + +/** + * \fn inline int test_croisement_segment_strict(int Ai, int Aj, int Bi, int Bj, + * int Ui, int Uj, int Vi, int Vj) + * + * \brief Test qui determine si deux segments croisent + * \author NB - PhyTI + * + * \param[in] Ai + * \param[in] Aj + * \param[in] Bi + * \param[in] Bj + * \param[in] Ui + * \param[in] Uj + * \param[in] Vi + * \param[in] Vj + * + * \return 1 si croisement, 0 sinon + * + * Version strict : n'autorise pas les triangles nulles + * Test de croisement des segments : + * si deux segments AB et UV croisent, alors + * les triangles ABU et ABV change d'ordre de rotation + * ET + * les triangles UVA et UVB change aussi d'ordre de rotation + * + */ +inline int test_croisement_segment_strict(uint32 Ai, uint32 Aj, uint32 Bi, uint32 Bj, + uint32 Ui, uint32 Uj, uint32 Vi, uint32 Vj) +{ + if (sign_diff_ou_egal_zero(sinus_triangle(Ai, Aj, Bi, Bj, Ui, Uj), + sinus_triangle(Ai, Aj, Bi, Bj, Vi, Vj))) + if (sign_diff_ou_egal_zero(sinus_triangle(Ui, Uj, Vi, Vj, Ai, Aj), + sinus_triangle(Ui, Uj, Vi, Vj, Bi, Bj))) + return 1 ; + return 0 ; +} + + + + + +/** + * \fn int test_croisement_add_noeud_large(struct snake_node *N, int Nxi, int Nxj, int seg) + * + * \brief test si il y a croisement de segments lors de l'ajout d'un noeud + * \author NB - PhyTI + * + * \param[in] N le noeud ou l'on veut ajouter un noeud Nx au milieu de son segment + * \param[in] Nxi coordonnee i du nouveau node Nx + * \param[in] Nxj coordonnee j du nouveau node Nx + * \param[in] seg booleen pour definir quel segment on test: + * Nx --> Nsuiv si seg==1 + * N --> Nx si seg==0 + * + * \return 1 si croisement, 0 sinon + * + * Version large : autorise les triangles nulles + * + */ +int test_croisement_add_noeud_large(struct snake_node *N, uint32 Nxi, uint32 Nxj, int seg) +{ + uint32 Nrefi=0, Nrefj=0 ; /* reference avec Nxi et Nxj */ + uint32 posi, posj, suivi, suivj ; /* segment courant de test */ + struct snake_node *node, *end ; + + if (seg==1) + { + Nrefi = N->noeud_suiv->posi ; + Nrefj = N->noeud_suiv->posj ; + } + else + { + Nrefi = N->posi ; + Nrefj = N->posj ; + } + + node = N->noeud_suiv ; + suivi = node->posi ; + suivj = node->posj ; + + end = N ; + while (node != end) + { + posi = suivi ; + posj = suivj ; + node = node->noeud_suiv ; + suivi = node->posi ; + suivj = node->posj ; + if (test_croisement_segment_large(Nxi,Nxj,Nrefi,Nrefj, posi,posj,suivi,suivj)) + return 1 ; + } + return 0 ; +} + + + +/** + * \fn int test_croisement_add_noeud_strict(struct snake_node *N, int Nxi, int Nxj, int seg) + * + * \brief test si il y a croisement de segments lors de l'ajout d'un noeud + * \author NB - PhyTI + * + * \param[in] N le noeud ou l'on veut ajouter un noeud Nx au milieu de son segment + * \param[in] Nxi coordonnee i du nouveau node Nx + * \param[in] Nxj coordonnee j du nouveau node Nx + * \param[in] seg booleen pour definir quel segment on test: + * Nx --> Nsuiv si seg==1 + * N --> Nx si seg==0 + * + * \return 1 si croisement, 0 sinon + * + * Version strict : n'autorise pas les triangles nulles + * + */ +int test_croisement_add_noeud_strict(struct snake_node *N, uint32 Nxi, uint32 Nxj, int seg) +{ + uint32 Nrefi=0, Nrefj=0 ; /* reference avec Nxi et Nxj */ + uint32 posi, posj, suivi, suivj ; /* segment courant de test */ + struct snake_node *node, *end ; + + /* segment de reference */ + if (seg) + { + Nrefi = N->noeud_suiv->posi ; + Nrefj = N->noeud_suiv->posj ; + } + else + { + Nrefi = N->posi ; + Nrefj = N->posj ; + } + + /* segments de tests */ + node = N->noeud_suiv ; + suivi = node->posi ; + suivj = node->posj ; + + if (seg) + { + /* premier segment : il touche le segment de ref */ + /* pour Nx --> Nsuiv(ref) */ + posi = suivi ; + posj = suivj ; + node = node->noeud_suiv ; + suivi = node->posi ; + suivj = node->posj ; + if (test_croisement_segment_large(Nxi,Nxj,Nrefi,Nrefj,posi,posj,suivi,suivj)) + return 1 ; + end = N ; /* pour boucle while */ + } + else + /* pour N --> Nx */ + end = N->noeud_prec ; /* pour boucle while */ + + /* boucle sur les segments */ + while (node != end) + { + posi = suivi ; + posj = suivj ; + node = node->noeud_suiv ; + suivi = node->posi ; + suivj = node->posj ; + if (test_croisement_segment_strict(posi,posj,suivi,suivj,Nxi,Nxj,Nrefi,Nrefj)) + return 1 ; + } + + /* dernier segment */ + /* cas N --> Nx */ + if (!seg) + { + posi = suivi ; + posj = suivj ; + node = node->noeud_suiv ; + suivi = node->posi ; + suivj = node->posj ; + if (test_croisement_segment_large(Nxi,Nxj,Nrefi,Nrefj, posi,posj,suivi,suivj)) + return 1 ; + } + return 0 ; +} + + + + + + +/** + * \fn int test_croisement_move_seg_large(struct snake_node *Nx, int Nxi, int Nxj, int seg) + * + * \brief test si il y a croisement de segments lors du deplacement d'un noeud + * \author NB - PhyTI + * + * \param[in] Nx le noeud que l'on veut deplacer + * \param[in] Nxi coordonnee i du nouveau node Nx + * \param[in] Nxj coordonnee j du nouveau node Nx + * \param[in] seg booleen pour definir quel segment on test: + * Nx --> Nsuiv si seg==1 + * Nprec --> Nx si seg==0 + * + * \return 1 si croisement, 0 sinon + * + * Version large : autorise les triangles nulles + * Version non optimisee car elle test systematiquement tout les segments du snake ! + * + */ +int test_croisement_move_seg_large(struct snake_node *Nx, uint32 Nxi, uint32 Nxj, int seg) +{ + uint32 Nrefi=0, Nrefj=0 ; /* reference avec Nxi et Nxj */ + uint32 posi, posj, suivi, suivj ; /* segment courant de test */ + struct snake_node *node, *end ; + + if (seg==1) + { + Nrefi = Nx->noeud_suiv->posi ; + Nrefj = Nx->noeud_suiv->posj ; + } + else + { + Nrefi = Nx->noeud_prec->posi ; + Nrefj = Nx->noeud_prec->posj ; + } + + node = Nx->noeud_suiv ; + suivi = node->posi ; + suivj = node->posj ; + + end = Nx->noeud_prec ; + while (node != end) + { + posi = suivi ; + posj = suivj ; + node = node->noeud_suiv ; + suivi = node->posi ; + suivj = node->posj ; + if (test_croisement_segment_large(Nxi,Nxj,Nrefi,Nrefj, posi,posj,suivi,suivj)) + return 1 ; + } + return 0 ; +} + + + +/** + * \fn int test_croisement_move_seg_strict(struct snake_node *Nx, int Nxi, int Nxj, int seg) + * + * \brief test si il y a croisement de segments lors du deplacement d'un noeud + * \author NB - PhyTI + * + * \param[in] Nx le noeud que l'on veut deplacer + * \param[in] Nxi coordonnee i du nouveau node Nx + * \param[in] Nxj coordonnee j du nouveau node Nx + * \param[in] seg booleen pour definir quel segment on test: + * Nx --> Nsuiv si seg==1 + * Nprec --> Nx si seg==0 + * + * \return 1 si croisement, 0 sinon + * + * Version strict : n'autorise pas les triangles nulles + * Version non optimisee car elle test systematiquement tout les segments du snake ! + */ +int test_croisement_move_seg_strict(struct snake_node *Nx, uint32 Nxi, uint32 Nxj, int seg) +{ + uint32 Nrefi=0, Nrefj=0 ; /* reference avec Nxi et Nxj */ + uint32 posi, posj, suivi, suivj ; /* segment courant de test */ + struct snake_node *node, *end ; + + /* segment de reference */ + if (seg) + { + Nrefi = Nx->noeud_suiv->posi ; + Nrefj = Nx->noeud_suiv->posj ; + } + else + { + Nrefi = Nx->noeud_prec->posi ; + Nrefj = Nx->noeud_prec->posj ; + } + + /* segments de tests */ + node = Nx->noeud_suiv ; + suivi = node->posi ; + suivj = node->posj ; + + if (seg) + { + /* premier segment : il touche le segment de ref */ + /* pour Nx --> Nsuiv(ref) */ + posi = suivi ; + posj = suivj ; + node = node->noeud_suiv ; + suivi = node->posi ; + suivj = node->posj ; + if (test_croisement_segment_large(Nxi,Nxj,Nrefi,Nrefj,posi,posj,suivi,suivj)) + return 1 ; + + end = Nx->noeud_prec ; /* pour boucle while */ + } + else + /* pour Nprec --> Nx */ + end = Nx->noeud_prec->noeud_prec ; /* pour boucle while */ + + /* boucle sur les segments */ + while (node != end) + { + posi = suivi ; + posj = suivj ; + node = node->noeud_suiv ; + suivi = node->posi ; + suivj = node->posj ; + if (test_croisement_segment_strict(posi,posj,suivi,suivj,Nxi,Nxj,Nrefi,Nrefj)) + return 1 ; + } + + /* dernier segment */ + /* cas Nprec --> Nx */ + if (!seg) + { + posi = suivi ; + posj = suivj ; + node = node->noeud_suiv ; + suivi = node->posi ; + suivj = node->posj ; + if (test_croisement_segment_large(Nxi,Nxj,Nrefi,Nrefj, posi,posj,suivi,suivj)) + return 1 ; + } + return 0 ; +} + diff --git a/src/lib_snake_common.h b/src/lib_snake_common.h new file mode 100644 index 0000000..7fa395a --- /dev/null +++ b/src/lib_snake_common.h @@ -0,0 +1,21 @@ +#include "structures.h" + + +struct snake_node* genere_snake_rectangle_bords(uint32 *nb_noeud, uint32 distance_bords, uint32 i_dim, uint32 j_dim) ; +struct snake_node* genere_snake_rectangle(int *nb_noeud, uint32 i1, uint32 j1, uint32 i2, uint32 j2, + uint32 i_dim, uint32 j_dim) ; + + +void affiche_snake(int **image, struct snake_node *snake, int valseg, int valnoeud, uint32 *liste_pixel_segment) ; +void affiche_snake_ushort(unsigned short **image, struct snake_node *snake, int valseg, unsigned short valnoeud, uint32 *liste_pixel_segment) ; + + +struct snake_node* ajout_noeud_snake(struct snake_node *node, uint32 *nb_noeud) ; +int test_croisement_add_noeud_large(struct snake_node *N, uint32 Nxi, uint32 Nxj, int seg); +int test_croisement_add_noeud_strict(struct snake_node *N, uint32 Nxi, uint32 Nxj, int seg); + +int test_croisement_move_seg_strict(struct snake_node *Nx, uint32 Nxi, uint32 Nxj, int seg); +int test_croisement_move_seg_large(struct snake_node *Nx, uint32 Nxi, uint32 Nxj, int seg); + + +void debug_aff_snake(struct snake_node *snake); diff --git a/src/lib_snake_common.h~ b/src/lib_snake_common.h~ new file mode 100644 index 0000000..ba8e011 --- /dev/null +++ b/src/lib_snake_common.h~ @@ -0,0 +1,21 @@ +#include "structures.h" + + +struct snake_node* genere_snake_rectangle_bords(uint32 *nb_noeud, uint32 distance_bords, uint32 i_dim, uint32 j_dim) ; +struct snake_node* genere_snake_rectangle(int *nb_noeud, uint32 i1, uint32 j1, uint32 i2, uint32 j2, + uint32 i_dim, uint32 j_dim) ; + + +void affiche_snake(int **image, struct snake_node *snake, int valseg, int valnoeud, uint32 *liste_pixel_segment) ; +void affiche_snake_ushort(unsigned short **image, struct snake_node *snake, int valseg, int valnoeud, uint32 *liste_pixel_segment) ; + + +struct snake_node* ajout_noeud_snake(struct snake_node *node, uint32 *nb_noeud) ; +int test_croisement_add_noeud_large(struct snake_node *N, uint32 Nxi, uint32 Nxj, int seg); +int test_croisement_add_noeud_strict(struct snake_node *N, uint32 Nxi, uint32 Nxj, int seg); + +int test_croisement_move_seg_strict(struct snake_node *Nx, uint32 Nxi, uint32 Nxj, int seg); +int test_croisement_move_seg_large(struct snake_node *Nx, uint32 Nxi, uint32 Nxj, int seg); + + +void debug_aff_snake(struct snake_node *snake); diff --git a/src/lib_test_gpu.cu b/src/lib_test_gpu.cu new file mode 100644 index 0000000..c65ea16 --- /dev/null +++ b/src/lib_test_gpu.cu @@ -0,0 +1,78 @@ +#include "stdio.h" +#include "structures.h" +#include "lib_test_gpu.h" + +void verif_cumuls(int ** img_in, int H, int L, uint64 ** d_img_1, uint64 ** d_img_x, uint64 ** d_img_x2, int BS, bool DISPLAY){ + int taille = H*L ; + //allocation memoire CPU + uint64 img_1[H][L]; + uint64 img_x[H][L]; + uint64 img_x2[H][L]; + + /*pour test comparaison*/ + uint64 img_1b[H][L]; + uint64 img_xb[H][L]; + uint64 img_x2b[H][L]; + cudaMemcpy( img_1b, *d_img_1, taille*sizeof(uint64), cudaMemcpyDeviceToHost ); + cudaMemcpy( img_xb, *d_img_x, taille*sizeof(uint64), cudaMemcpyDeviceToHost); + cudaMemcpy( img_x2b, *d_img_x2, taille*sizeof(uint64), cudaMemcpyDeviceToHost); + + for (int i=0; i +#include +#include "structures.h" +extern "C"{ +#include "lib_alloc.h" +#include "lib_images.h" +#include "lib_snake_common.h" +#include "lib_math.h" +#include "lib_gpu.h" +#include "defines.h" +#include "lib_snake_2_gpu.h" +} +#include "lib_kernels_maths.cu" +#include "lib_kernels_contribs.cu" + + + + +int main(int argc, char **argv) +{ + /* declaration des variables */ + int ret ; + int Prof ; /* profondeur en octets */ + uint32 I_dim ; /* hauteur de l'image */ + uint32 J_dim ; /* largeur de l'image */ + int Nb_level ; /* dynamique de l'image */ + char *File_name ; + + + /* images */ + unsigned short **Image_in; + struct timeval chrono, chrono_all ; + + /* lecture argument entree (basique!) */ + File_name = argv[3] ; + + /* verif type image (pgm 8/16) */ + ret = type_image_ppm(&Prof, &I_dim, &J_dim, &Nb_level, File_name) ; + + if ((ret == 0) | (Prof == 3)) + { + printf("format non pris en charge ... exit\n") ; + return(0) ; + } + + /* infos */ + printf("Image : %s\n", File_name) ; + printf("lecture OK : %d\n", ret) ; + printf("Image (%d x %d) pixels\n", I_dim, J_dim) ; + printf("Dynamique : %d\n", Nb_level) ; + + /* Allocation */ + Image_in = new_matrix_ushort(I_dim, J_dim) ; + + /* chargement image d'entree */ + load_pgm2ushort(Image_in, I_dim, J_dim, Nb_level, File_name) ; + + //POINTEURS VARIABLES MEMOIRE GLOBALE GPU + unsigned short * d_img ; // image + t_cumul_x * d_img_x ; // images cumulees + t_cumul_x2 * d_img_x2; // + + snake_node_gpu * d_snake ; //image du snake CPU dans un tableau en gmem GPUe + + int * d_freemanDiDj ; // table de correspondance [Di][Dj]->Freemans + int * d_codeNoeud ; // table de correspondance [F_in][F_out]->codeNoeud + + uint4 * d_positions ; // positions de test autour des noeuds + + uint2 * d_listes_pixels ; // coordonnees des pixels des segments correspondants aux 8 posiionstest + uint2 * d_liste_temp ; + uint32 * d_nb_pix_max ; // taille max des segments a tester + + uint64 * d_contribs_segments_blocs ;// sommes des contribs pixels par blocs de calcul + uint64 * d_contribs_segments ; // contribs segments 1, x et x2 + uint64 * d_sompart ; // vecteur de resultats intermediaires (sommes partielles = sommes par blocs) + + int64 * d_stats, * d_stats_ref ; // stats des positions de test, du snake sans les segments en test + int64 * d_stats_snake; // stats du snake + stats de l'image complete + double * d_vrais, * d_vrais_snake ; // valeurs de la log-vraisemblance des positions de test, du snake + + uint4 * d_freemans_centres ; // valeurs des F_in, F_out et coord. + // centres des 16 segments associes aux 8 positions de test + + int * d_codes_segments ; // valeurs de codes des 16 segments + bool * d_move ; // nb de deplacement effectues lors d'une iteration + int * d_nb_nodes ; // nb de noeuds du snake + + snake_node_gpu * d_snake_tmp ; // snake tampon pour l'etape d'ajout de noeuds + + /* pointeurs sur mem CPU */ + int *h_nb_nodes = new int; // image CPU du nb de noeud du snake + snake_node_gpu h_snake[MAX_NODES]; + double h_vrais_snake, h_vrais_mem ; // image CPU de la log-vraisemblance + bool * h_move = new bool[MAX_NODES];// image CPU du vecteur identifiant les noeuds qui ont bouge + uint32 h_nb_pix_max, npixmax ; // taille max des segments a tester : utile pour determiner les params d'execution + int nnodes = 4 ; // 4 ou 40 pour l'instant + + + /*allocation memoire GPU */ + cudaMalloc((void**) &d_nb_nodes, sizeof(int)); + cudaMalloc((void**) &d_sompart, MAX_NODES*256*16*sizeof(uint64)); + cudaMalloc((void**) &d_liste_temp, MAX_NODES*5*16*sizeof(uint2)); + cudaMalloc((void**) &d_snake_tmp, MAX_NODES*sizeof(snake_node_gpu) ); + + /*init snake (positions/contribs/stats/freemans/centres/codes)*/ + cuda_init_img_cumul(Image_in, I_dim, J_dim, nnodes, + &d_img, &d_img_x, &d_img_x2, + &d_freemanDiDj, &d_codeNoeud, + &d_snake, &d_nb_pix_max, + &d_positions, &d_contribs_segments, &d_freemans_centres, + &d_codes_segments, &d_stats_snake, + &d_stats, &d_stats_ref, &d_vrais, &d_vrais_snake, + &d_listes_pixels, &d_contribs_segments_blocs, + &d_move + ); + + /* debug : affichage snake */ + int Verbose = 1 ; + int VERBOSE = 1 ; + int Display = 1 ; + + //snake_node * h_snake_ll; + uint64 h_stats_snake[6]; + //gpu2snake(d_snake, &h_snake_ll, nnodes); + + + // variables de debug + int nb_move, iter, i ; + int nb_move_total=0, nb_test_total=0 ; + int NB_iter_max = atoi(argv[1]); + int Pas = atoi(argv[2]) ; // distance entre la position actuelle et les positions de test + int Dist_min_entre_noeud = 4*Pas ; + int bs, nblocs_seg, tpb, bps ; // nb de threads par blocs pour l'execution des kernels, nb de blocs de threads par segment a tester + dim3 threads, grid ; // params d'execution des kernels + int n_interval ; // nombre d'intervalles Na--Nx--Nb concernes + int taille_smem ; // quantite de shared memory allouee pour le calcul des contribs des segments de test + bool pairs = true ; // mouvement des noeuds pairs/impairs + + if (Verbose) { + printf("nb noeuds : %d\n", nnodes) ; + tic(&chrono_all, NULL) ; + } + + for (iter=1; (iter<=NB_iter_max)&&(Pas>0); iter++, Pas>>=1) + { + + if (VERBOSE) + { + cudaMemcpy( &h_vrais_snake, d_vrais_snake, sizeof(double), cudaMemcpyDeviceToHost); + printf("\n#%d : pas %d pixels, LV = %lf \n", iter, Pas, h_vrais_snake) ; + tic(&chrono, NULL) ; + } + // DEBUT MOVE SNAKE + do { + + //memorisation precedente LV + h_vrais_mem = h_vrais_snake ; + // calcul stats sans les paires de segments a bouger + soustrait_aux_stats_2N_segments_noeud<<< nnodes , 1 >>>(d_snake, d_stats_snake, d_stats_ref, + d_img_x, d_img_x2, + d_codeNoeud, J_dim + ); + + // calcul des coordonnées de toutes les positions possibles des noeud a l'etape N+1 + liste_positions_a_tester<<>>(d_snake, d_positions, d_nb_pix_max, Pas, nnodes, I_dim, J_dim) ; + + // recupere la taille maxi des segments + cudaMemcpy( &h_nb_pix_max, d_nb_pix_max, sizeof(uint32), cudaMemcpyDeviceToHost) ; + + // determination des parametres des kernels + bs = nextPow2(h_nb_pix_max) ; + if (bs>=BSMAX) bs = BSMAX ; // /!\ le kernel <<< calcul_contrib...>>> ne supporte pas un bs>256 a cause de la shared-mem nécessaire + if (bs<32) bs = 32 ; + nblocs_seg = (h_nb_pix_max+bs-1)/bs ; + + pairs = false ; + n_interval = nnodes/2 + pairs*(nnodes%2) ; + taille_smem = CFI(bs)*sizeof(tcontribs) ; + threads = dim3(bs,1,1) ; + grid = dim3( n_interval*16*nblocs_seg ,1,1) ; + + //calcul listes pix + contrib partielles + freemans + centres + calcul_contribs_segments_blocs_full<<< grid , threads, taille_smem >>>( d_snake, nnodes, d_positions, h_nb_pix_max, + d_img_x, d_img_x2, d_codes_segments, + J_dim, d_listes_pixels, d_contribs_segments_blocs, + pairs); + + calcul_freemans_centre<<>>( d_listes_pixels, d_freemanDiDj, d_freemans_centres); + //printf("EXEC impairs : %d max pix - %d intervalles => %d blocs de %d threads - %d octets de smem\n", h_nb_pix_max, n_interval, grid.x, threads.x, taille_smem); + //sommes des contribs partielles -> contribs segments + somsom_full<<< 16*n_interval , 1>>>(d_contribs_segments_blocs, nnodes, nblocs_seg, d_contribs_segments) ; + + //calcul des stats associees a chaque position de test + calcul_stats_full<<< n_interval, 8 >>>(d_snake, nnodes, pairs, d_stats_snake, d_stats_ref, d_stats, d_contribs_segments, + d_positions, d_codes_segments, d_freemans_centres, d_codeNoeud, + d_img_x, d_img_x2, I_dim, J_dim, d_vrais, d_vrais_snake, d_move); + + pairs = true ; + n_interval = nnodes/2 + pairs*(nnodes%2) ; + grid = dim3( n_interval*16*nblocs_seg ,1,1) ; + + //calcul listes pix + contrib partielles + freemans + centres + calcul_contribs_segments_blocs_full<<< grid , threads, taille_smem >>>( d_snake, nnodes, d_positions, h_nb_pix_max, + d_img_x, d_img_x2, d_codes_segments, + J_dim, d_listes_pixels, d_contribs_segments_blocs, + pairs); + calcul_freemans_centre<<>>( d_listes_pixels, d_freemanDiDj, d_freemans_centres); + //printf("EXEC pairs : %d max pix - %d intervalles => %d blocs de %d threads - %d octets de smem\n", h_nb_pix_max, n_interval, grid.x, threads.x, taille_smem); + //sommes des contribs partielles -> contribs segments + somsom_full<<< 16*n_interval , 1>>>(d_contribs_segments_blocs, nnodes, nblocs_seg, d_contribs_segments) ; + + //calcul des stats associees a chaque position de test + calcul_stats_full<<< n_interval, 8 >>>(d_snake, nnodes, pairs, d_stats_snake, d_stats_ref, d_stats, d_contribs_segments, + d_positions, d_codes_segments, d_freemans_centres, d_codeNoeud, + d_img_x, d_img_x2, I_dim, J_dim, d_vrais, d_vrais_snake, d_move); + + + //il faut recalculer les stats du snake apres modif + recalcul_stats_snake<<< 1 , 1 >>>(d_snake, nnodes, d_stats_snake, d_vrais_snake, + d_img_x, d_img_x2, + d_codeNoeud, J_dim + ); + + cudaMemcpy( &h_vrais_snake, d_vrais_snake, sizeof(double), cudaMemcpyDeviceToHost); + //printf("iter %d apres recalcul du move LV = %lf - ", iter, h_vrais_snake) ; + + nb_move = 0; + //recup move + cudaMemcpy( h_move, d_move, nnodes*sizeof(bool), cudaMemcpyDeviceToHost); + i = 0; + while (i>>(d_snake, d_snake_tmp, nnodes, Dist_min_entre_noeud, d_nb_nodes ); + //recup nb de nouveaux noeuds + cudaMemcpy( h_nb_nodes, d_nb_nodes, sizeof(int), cudaMemcpyDeviceToHost); + //mise a jour nb de noeuds + nnodes += (*h_nb_nodes) ; + + //parametres d'execution des kernels pour le recalcul des contribs et stats du snake + npixmax = h_nb_pix_max ; + tpb = nextPow2(npixmax) ; + if (tpb >= BSMAX) tpb = BSMAX ;// /!\ le kernel <<< calcul_contrib...>>> ne supporte pas un bs>BSMAX a cause de la shared-mem nécessaire + if (tpb < 32 ) tpb = 32 ; + bps = (npixmax+tpb-1)/tpb ; + + //calcul sommes partielles des contribs + codes segments + recalcul_contribs_segments_snake<<< nnodes*bps, tpb, CFI(tpb)*sizeof(tcontribs)>>>(d_snake, nnodes, + d_img_x, d_img_x2, + J_dim, d_liste_temp, d_sompart ); + //calcul des freemans et des centres a partir des 5 points stockes par segment dans 'd_liste_temp' + recalcul_freemans_centre<<>>(d_snake, d_liste_temp, d_freemanDiDj); + //somme des sommes partielles + resomsom_snake<<< nnodes , 1 >>>(d_sompart, nnodes, bps, d_snake); + //calcul des stats + recalcul_stats_snake<<< 1 , 1 >>>(d_snake, nnodes, d_stats_snake, d_vrais_snake, + d_img_x, d_img_x2, + d_codeNoeud, J_dim + ); + //tant que l'on peut ajouter des noeuds + if (*h_nb_nodes == 0) break ; + //recup LogVraisemblance + cudaMemcpy( &h_vrais_snake, d_vrais_snake, sizeof(double), cudaMemcpyDeviceToHost); + + } + + if (VERBOSE) + { + toc(chrono, "temps sequence move"); + + printf("nb deplacements : %d\n", nb_move) ; + printf("nb deplacements total/test : %d/%d\n", nb_move_total, nb_test_total) ; + printf("nb nouveaux noeuds : %d (total: %d)\n", *h_nb_nodes, nnodes) ; + printf("\nlongueur de codage de gl : %lf \n", h_vrais_snake) ; + } + } + + if (Verbose) { + toc(chrono_all, "temps move mv") ; + cudaMemcpy( h_stats_snake, d_stats_snake, 6*sizeof(uint64), cudaMemcpyDeviceToHost); + cudaMemcpy( &h_vrais_snake, d_vrais_snake, sizeof(double), cudaMemcpyDeviceToHost); + printf("\nFIN : longueur de codage de gl : %lf (%d)\n", h_vrais_snake, h_stats_snake[0]) ; + printf("nb noeuds : %d, nb_iter : %d\n", nnodes, iter-1) ; + printf("nb deplacements total/test : %d/%d\n", nb_move_total, nb_test_total) ; + } + + + if (Display) { + /* old fashion way to draw the snake + gpu2snake(d_snake, &h_snake_ll, nnodes); + uint32 * Liste_pixel_segment = new uint32[I_dim+J_dim]; + affiche_snake_ushort(Image_in, h_snake_ll, 255, 0, Liste_pixel_segment) ; + delete Liste_pixel_segment ; + delete h_snake_ll; + */ + cudaMemcpy( h_snake, d_snake, nnodes*sizeof(snake_node_gpu), cudaMemcpyDeviceToHost); + //affiche coordonnees + for (int node=0; node +#include +#include "structures.h" +extern "C"{ +#include "lib_alloc.h" +#include "lib_images.h" +#include "lib_snake_common.h" +#include "lib_math.h" +#include "lib_gpu.h" +#include "defines.h" +#include "lib_snake_2_gpu.h" +} +#include "lib_kernels_maths.cu" +#include "lib_kernels_contribs.cu" + + + + +int main(int argc, char **argv) +{ + /* declaration des variables */ + int ret ; + int Prof ; /* profondeur en octets */ + uint32 I_dim ; /* hauteur de l'image */ + uint32 J_dim ; /* largeur de l'image */ + int Nb_level ; /* dynamique de l'image */ + char *File_name ; + + + /* images */ + unsigned short **Image_in; + struct timeval chrono, chrono2, chrono_all ; + + /* lecture argument entree (basique!) */ + File_name = argv[3] ; + + /* verif type image (pgm 8/16) */ + ret = type_image_ppm(&Prof, &I_dim, &J_dim, &Nb_level, File_name) ; + + if ((ret == 0) | (Prof == 3)) + { + printf("format non pris en charge ... exit\n") ; + return(0) ; + } + + /* infos */ + printf("Image : %s\n", File_name) ; + printf("lecture OK : %d\n", ret) ; + printf("Image (%d x %d) pixels\n", I_dim, J_dim) ; + printf("Dynamique : %d\n", Nb_level) ; + + /* Allocation */ + Image_in = new_matrix_ushort(I_dim, J_dim) ; + + /* chargement image d'entree */ + load_pgm2ushort(Image_in, I_dim, J_dim, Nb_level, File_name) ; + + //POINTEURS VARIABLES MEMOIRE GLOBALE GPU + unsigned short * d_img ; // image + t_cumul_x * d_img_x ; // images cumulees + t_cumul_x2 * d_img_x2; // + + snake_node_gpu * d_snake ; //image du snake CPU dans un tableau en gmem GPUe + + int * d_freemanDiDj ; // table de correspondance [Di][Dj]->Freemans + int * d_codeNoeud ; // table de correspondance [F_in][F_out]->codeNoeud + + uint4 * d_positions ; // positions de test autour des noeuds + + uint2 * d_listes_pixels ; // coordonnees des pixels des segments correspondants aux 8 posiionstest + uint2 * d_liste_temp ; + uint32 * d_nb_pix_max ; // taille max des segments a tester + + uint64 * d_contribs_segments_blocs ;// sommes des contribs pixels par blocs de calcul + uint64 * d_contribs_segments ; // contribs segments 1, x et x2 + uint64 * d_sompart ; // vecteur de resultats intermediaires (sommes partielles = sommes par blocs) + + int64 * d_stats, * d_stats_ref ; // stats des positions de test, du snake sans les segments en test + int64 * d_stats_snake; // stats du snake + stats de l'image complete + double * d_vrais, * d_vrais_snake ; // valeurs de la log-vraisemblance des positions de test, du snake + + uint4 * d_freemans_centres ; // valeurs des F_in, F_out et coord. + // centres des 16 segments associes aux 8 positions de test + + int * d_codes_segments ; // valeurs de codes des 16 segments + bool * d_move ; // nb de deplacement effectues lors d'une iteration + int * d_nb_nodes ; // nb de noeuds du snake + + snake_node_gpu * d_snake_tmp ; // snake tampon pour l'etape d'ajout de noeuds + + /* pointeurs sur mem CPU */ + int *h_nb_nodes = new int; // image CPU du nb de noeud du snake + snake_node_gpu h_snake[MAX_NODES] ; + uint2 h_listes_pixels[MAX_NODES*16*5] ; + double h_vrais_snake, h_vrais_mem, h_vrais[8*MAX_NODES] ; // image CPU de la log-vraisemblance + bool * h_move = new bool[MAX_NODES];// image CPU du vecteur identifiant les noeuds qui ont bouge + uint32 h_nb_pix_max, npixmax ; // taille max des segments a tester : utile pour determiner les params d'execution + int nnodes = 4 ; // 4 ou 40 pour l'instant + + + /*allocation memoire GPU */ + int retour_cmd = 0; + cudaMalloc((void**) &d_nb_nodes, sizeof(int)); + cudaMalloc((void**) &d_sompart, MAX_NODES*256*16*sizeof(uint64)); + cudaMalloc((void**) &d_liste_temp, MAX_NODES*5*16*sizeof(uint2)); + retour_cmd = cudaMalloc((void**) &d_snake_tmp, MAX_NODES*sizeof(snake_node_gpu) ); + printf("RESULTAT ALLOC snake_tmp = %d\n", retour_cmd); + + + /*init snake (positions/contribs/stats/freemans/centres/codes)*/ + cuda_init_img_cumul(Image_in, I_dim, J_dim, nnodes, + &d_img, &d_img_x, &d_img_x2, + &d_freemanDiDj, &d_codeNoeud, + &d_snake, &d_nb_pix_max, + &d_positions, &d_contribs_segments, &d_freemans_centres, + &d_codes_segments, &d_stats_snake, + &d_stats, &d_stats_ref, &d_vrais, &d_vrais_snake, + &d_listes_pixels, &d_contribs_segments_blocs, + &d_move + ); + + /* debug : affichage snake */ + int Verbose = 1 ; + int VERBOSE = 1 ; + int Display = 1 ; + + /* debug : tests fonctions*/ + int H= I_dim, L= J_dim ; + + //snake_node * h_snake_ll; + uint64 h_stats_snake[6]; + //gpu2snake(d_snake, &h_snake_ll, nnodes); + + + // variables de debug + int nb_move, nb_newnode, iter, i ; + int nb_move_total=0, nb_test_total=0 ; + int NB_iter_max = atoi(argv[1]); + int dist = (I_dim+J_dim)/5; + int Pas = atoi(argv[2]) ; // dist entre la position actuelle et les positions de test + int Dist_min_entre_noeud = 4*Pas ; + int bs, nblocs_seg, tpb, bps ; // nb de threads par blocs pour l'execution des kernels, nb de blocs de threads par segment a tester + dim3 threads, grid ; // params d'execution des kernels + int n_interval ; // nombre d'intervalles Na--Nx--Nb concernes + int taille_smem ; // quantite de shared memory allouee pour le calcul des contribs des segments de test + bool pairs = true ; // mouvement des noeuds pairs/impairs + + if (Verbose) { + printf("nb noeuds : %d\n", nnodes) ; + tic(&chrono_all, NULL) ; + } + + for (iter=1; (iter<=NB_iter_max)&&(Pas>0); iter++, Pas>>=1) + { + + if (VERBOSE) + { + cudaMemcpy( &h_vrais_snake, d_vrais_snake, sizeof(double), cudaMemcpyDeviceToHost); + printf("\n#%d : pas %d pixels, LV = %lf \n", iter, Pas, h_vrais_snake) ; + tic(&chrono, NULL) ; + } + // DEBUT MOVE SNAKE + do { + + //memorisation precedente LV + h_vrais_mem = h_vrais_snake ; + // calcul stats sans les paires de segments a bouger + soustrait_aux_stats_2N_segments_noeud<<< nnodes , 1 >>>(d_snake, d_stats_snake, d_stats_ref, + d_img_x, d_img_x2, + d_codeNoeud, J_dim + ); + + // calcul des coordonnées de toutes les positions possibles des noeud a l'etape N+1 + liste_positions_a_tester<<>>(d_snake, d_positions, d_nb_pix_max, Pas, nnodes, I_dim, J_dim) ; + + // recupere la taille maxi des segments + cudaMemcpy( &h_nb_pix_max, d_nb_pix_max, sizeof(uint32), cudaMemcpyDeviceToHost) ; + + // determination des parametres des kernels + bs = nextPow2(h_nb_pix_max) ; + if (bs>=BSMAX) bs = BSMAX ; // /!\ le kernel <<< calcul_contrib...>>> ne supporte pas un bs>256 a cause de la shared-mem nécessaire + if (bs<32) bs = 32 ; + nblocs_seg = (h_nb_pix_max+bs-1)/bs ; + + pairs = false ; + n_interval = nnodes/2 + pairs*(nnodes%2) ; + taille_smem = CFI(bs)*sizeof(tcontribs) ; + threads = dim3(bs,1,1) ; + grid = dim3( n_interval*16*nblocs_seg ,1,1) ; + + //calcul listes pix + contrib partielles + freemans + centres + calcul_contribs_segments_blocs_full<<< grid , threads, taille_smem >>>( d_snake, nnodes, d_positions, h_nb_pix_max, + d_img_x, d_img_x2, d_codes_segments, + J_dim, d_listes_pixels, d_contribs_segments_blocs, + pairs); + /*debug*/ + cudaMemcpy( h_listes_pixels, d_listes_pixels, 16*5*n_interval*sizeof(uint2), cudaMemcpyDeviceToHost); + for(int inter=0; inter < 3; inter++){ + for(int seg=0; seg<16; seg++){ + printf(" intervalle %d segment %d : (%d,%d)-(%d,%d)-(%d,%d)-(%d,%d)-(%d,%d)\n", + inter, seg, h_listes_pixels[5*(16*inter+seg)].x,h_listes_pixels[5*(16*inter+seg)].y,h_listes_pixels[5*(16*inter+seg)+1].x, + h_listes_pixels[5*(16*inter+seg)+1].y,h_listes_pixels[5*(16*inter+seg)+2].x,h_listes_pixels[5*(16*inter+seg)+2].y, + h_listes_pixels[5*(16*inter+seg)+3].x,h_listes_pixels[5*(16*inter+seg)+3].y,h_listes_pixels[5*(16*inter+seg)+4].x, + h_listes_pixels[5*(16*inter+seg)+4].y); + } + } + /*fin*/ + calcul_freemans_centre<<>>( d_listes_pixels, d_freemanDiDj, d_freemans_centres); + //printf("EXEC impairs : %d max pix - %d intervalles => %d blocs de %d threads - %d octets de smem\n", h_nb_pix_max, n_interval, grid.x, threads.x, taille_smem); + //sommes des contribs partielles -> contribs segments + somsom_full<<< 16*n_interval , 1>>>(d_contribs_segments_blocs, nnodes, nblocs_seg, d_contribs_segments) ; + + //calcul des stats associees a chaque position de test + calcul_stats_full<<< n_interval, 8 >>>(d_snake, nnodes, pairs, d_stats_snake, d_stats_ref, d_stats, d_contribs_segments, + d_positions, d_codes_segments, d_freemans_centres, d_codeNoeud, + d_img_x, d_img_x2, I_dim, J_dim, d_vrais, d_vrais_snake, d_move); + + pairs = true ; + n_interval = nnodes/2 + pairs*(nnodes%2) ; + grid = dim3( n_interval*16*nblocs_seg ,1,1) ; + + //calcul listes pix + contrib partielles + freemans + centres + calcul_contribs_segments_blocs_full<<< grid , threads, taille_smem >>>( d_snake, nnodes, d_positions, h_nb_pix_max, + d_img_x, d_img_x2, d_codes_segments, + J_dim, d_listes_pixels, d_contribs_segments_blocs, + pairs); + calcul_freemans_centre<<>>( d_listes_pixels, d_freemanDiDj, d_freemans_centres); + //printf("EXEC pairs : %d max pix - %d intervalles => %d blocs de %d threads - %d octets de smem\n", h_nb_pix_max, n_interval, grid.x, threads.x, taille_smem); + //sommes des contribs partielles -> contribs segments + somsom_full<<< 16*n_interval , 1>>>(d_contribs_segments_blocs, nnodes, nblocs_seg, d_contribs_segments) ; + + //calcul des stats associees a chaque position de test + calcul_stats_full<<< n_interval, 8 >>>(d_snake, nnodes, pairs, d_stats_snake, d_stats_ref, d_stats, d_contribs_segments, + d_positions, d_codes_segments, d_freemans_centres, d_codeNoeud, + d_img_x, d_img_x2, I_dim, J_dim, d_vrais, d_vrais_snake, d_move); + + + //il faut recalculer les stats du snake apres modif + recalcul_stats_snake<<< 1 , 1 >>>(d_snake, nnodes, d_stats_snake, d_vrais_snake, + d_img_x, d_img_x2, + d_codeNoeud, J_dim + ); + + cudaMemcpy( &h_vrais_snake, d_vrais_snake, sizeof(double), cudaMemcpyDeviceToHost); + //printf("iter %d apres recalcul du move LV = %lf - ", iter, h_vrais_snake) ; + + nb_move = 0; + //recup move + cudaMemcpy( h_move, d_move, nnodes*sizeof(bool), cudaMemcpyDeviceToHost); + i = 0; + while (i>>(d_snake, d_snake_tmp, nnodes, Dist_min_entre_noeud, d_nb_nodes ); + cudaMemcpy( h_nb_nodes, d_nb_nodes, sizeof(int), cudaMemcpyDeviceToHost); + nnodes += (*h_nb_nodes) ; + + cudaMemcpy( d_snake, d_snake_tmp, nnodes*sizeof(snake_node_gpu), cudaMemcpyDeviceToDevice); + + npixmax = h_nb_pix_max ; + tpb = nextPow2(npixmax) ; + if (tpb >= BSMAX) tpb = BSMAX ;// /!\ le kernel <<< calcul_contrib...>>> ne supporte pas un bs>256 a cause de la shared-mem nécessaire + if (tpb < 32 ) tpb = 32 ; + bps = (npixmax+tpb-1)/tpb ; + + recalcul_contribs_segments_snake<<< nnodes*bps, tpb, CFI(tpb)*sizeof(tcontribs)>>>(d_snake, nnodes, + d_img_x, d_img_x2, + J_dim, d_liste_temp, d_sompart ); + + recalcul_freemans_centre<<>>(d_snake, d_liste_temp, d_freemanDiDj); + resomsom_snake<<< nnodes , 1 >>>(d_sompart, nnodes, bps, d_snake); + + recalcul_stats_snake<<< 1 , 1 >>>(d_snake, nnodes, d_stats_snake, d_vrais_snake, + d_img_x, d_img_x2, + d_codeNoeud, J_dim + ); + + if (*h_nb_nodes == 0) break ; + cudaMemcpy( &h_vrais_snake, d_vrais_snake, sizeof(double), cudaMemcpyDeviceToHost); + printf("\niter %d LV apres ajout noeuds = %lf \n ", iter, h_vrais_snake) ; + } + + if (VERBOSE) + { + toc(chrono, "temps sequence move"); + + printf("nb deplacements : %d\n", nb_move) ; + printf("nb deplacements total/test : %d/%d\n", nb_move_total, nb_test_total) ; + printf("nb nouveaux noeuds : %d (total: %d)\n", *h_nb_nodes, nnodes) ; + printf("\nlongueur de codage de gl : %lf \n", h_vrais_snake) ; + } + } + + if (Verbose) { + toc(chrono_all, "temps move mv") ; + cudaMemcpy( h_stats_snake, d_stats_snake, 6*sizeof(uint64), cudaMemcpyDeviceToHost); + cudaMemcpy( &h_vrais_snake, d_vrais_snake, sizeof(double), cudaMemcpyDeviceToHost); + printf("\nFIN : longueur de codage de gl : %lf (%d)\n", h_vrais_snake, h_stats_snake[0]) ; + printf("nb noeuds : %d, nb_iter : %d\n", nnodes, iter-1) ; + printf("nb deplacements total/test : %d/%d\n", nb_move_total, nb_test_total) ; + } + + + if (Display) { + /* old fashion way to draw the snake + gpu2snake(d_snake, &h_snake_ll, nnodes); + uint32 * Liste_pixel_segment = new uint32[I_dim+J_dim]; + affiche_snake_ushort(Image_in, h_snake_ll, 255, 0, Liste_pixel_segment) ; + delete Liste_pixel_segment ; + delete h_snake_ll; + */ + cudaMemcpy( h_snake, d_snake, nnodes*sizeof(snake_node_gpu), cudaMemcpyDeviceToHost); + //affiche coordonnees + for (int node=0; node taill image sur 14 bits soit 16000 x 16000 \n + * longueur des segments sur 15 bits + * \verbatim + sum_1 : 0/1 + 14b + 15b = 29b => unsigned int + sum_x : 16b + 14b + 15b = 45b => unsigned long int + sum_x2 : 32b + 14b + 15b = 61b => unsigned long int + \endverbatim + * + * Avec la definition suivante, les contributions des segments + * ne pourrons etre que positives. Le signe associe au segment devra + * etre memorise par une autre variable (code_segment) + */ +struct pixel_cumul +{ + uint32 sum_1; + uint64 sum_x; + uint64 sum_x2; + } ; + +/* + * structure pour la smem des kernels cumuls + * + */ +struct tcumuls { + t_cumul_x x; + t_cumul_x2 x2; +}; + + +/* + * structure pour le smem des kernels contribs + * + */ + +struct tcontribs { + t_sum_1 c1; + t_sum_x cx; + t_sum_x2 cx2; +}; + +/** + * \struct snake_node structures.h + * + * \brief noeud du snake defini par liste chainee + * + * Cette structure memorise la position du noeud + * ET les informations concernant le segment qui + * part de ce noeud et va au noeud suivant dans + * l'ordre trigo + */ + +struct snake_node +{ + /* contribution du segment allant de ce noeud */ + /* au noeud suivant, defini dans l'ordre trigo */ + /* l'union pixel_cumul est definie en premier */ + /* pour permettre l'alignement memoire */ + struct pixel_cumul contrib ; + + int code_segment ; /* signe de la contrib */ + int freeman_in ; /* du noeud d'arrivee du segment (ordre trigo) */ + int freeman_out ; /* du noeud de depart du segment (ordre trigo) */ + uint32 nb_pixels ; + + uint32 posi ; /* position i du noeud */ + uint32 posj ; /* position j du noeud */ + uint32 centre_i ; /* centre i du segment */ + uint32 centre_j ; /* centre j du segment */ + + int last_move ; /* dernier test deplacement accepte */ + + /* lien liste chainee snake2D */ + struct snake_node *noeud_suiv ; /* dans le sens trigo */ + struct snake_node *noeud_prec ; + + + /* lien liste chainee snake3D */ +}; + + +struct snake_node_gpu +{ + t_sum_1 sum_1 ; + t_sum_x sum_x ; + t_sum_x2 sum_x2; + + int code_segment ; /* signe de la contrib */ + int freeman_in ; /* du noeud d'arrivee du segment (ordre trigo) */ + int freeman_out ; /* du noeud de depart du segment (ordre trigo) */ + uint32 nb_pixels ; + + uint32 posi ; /* position i du noeud */ + uint32 posj ; /* position j du noeud */ + uint32 centre_i ; /* centre i du segment */ + uint32 centre_j ; /* centre j du segment */ + + int last_move ; /* dernier test deplacement accepte */ +}; + + +#endif diff --git a/src/structures.h~ b/src/structures.h~ new file mode 100644 index 0000000..40b16dd --- /dev/null +++ b/src/structures.h~ @@ -0,0 +1,129 @@ +/** + * \file structures.h + * \author NB - PhyTI + * \version x.x + * \date 20 decembre 2009 + * + * + */ + +#ifndef _STRUCTURES_H +#define _STRUCTURES_H + + +/** + * \def uint64 entier non signe 64 bits + * \def int64 entier signe 64 bits + * \def uint32 entier non signe 32 bits + */ +typedef unsigned long long int uint64 ; +typedef unsigned int uint32; +typedef long long int int64 ; +typedef long int int32 ; + +typedef unsigned short t_cumul_1 ; +typedef unsigned int t_cumul_x ; +typedef unsigned long long t_cumul_x2 ; + +typedef unsigned int t_sum_1 ; +typedef unsigned long long t_sum_x ; +typedef unsigned long long t_sum_x2 ; + + +/** + * \struct pixel_cumul structures.h + * + * \brief structure des images cumulees + * + * Version d'algorithme sans SSE2 \n + * les images cumulees correspondent a \n + * [sum 1, sum x, sum x^2] \n + * + * Trois donnees a stocker de dynamique differente \n + * + * cas d'images en profondeur 16 bits \n + * avec xum_x2 sur 64 bits => taill image sur 14 bits soit 16000 x 16000 \n + * longueur des segments sur 15 bits + * \verbatim + sum_1 : 0/1 + 14b + 15b = 29b => unsigned int + sum_x : 16b + 14b + 15b = 45b => unsigned long int + sum_x2 : 32b + 14b + 15b = 61b => unsigned long int + \endverbatim + * + * Avec la definition suivante, les contributions des segments + * ne pourrons etre que positives. Le signe associe au segment devra + * etre memorise par une autre variable (code_segment) + */ +struct pixel_cumul +{ + uint32 sum_1; + uint64 sum_x; + uint64 sum_x2; + } ; + +struct tcumuls { + t_cumul_x x; + t_cumul_x2 x2; +}; + +/** + * \struct snake_node structures.h + * + * \brief noeud du snake defini par liste chainee + * + * Cette structure memorise la position du noeud + * ET les informations concernant le segment qui + * part de ce noeud et va au noeud suivant dans + * l'ordre trigo + */ + +struct snake_node +{ + /* contribution du segment allant de ce noeud */ + /* au noeud suivant, defini dans l'ordre trigo */ + /* l'union pixel_cumul est definie en premier */ + /* pour permettre l'alignement memoire */ + struct pixel_cumul contrib ; + + int code_segment ; /* signe de la contrib */ + int freeman_in ; /* du noeud d'arrivee du segment (ordre trigo) */ + int freeman_out ; /* du noeud de depart du segment (ordre trigo) */ + uint32 nb_pixels ; + + uint32 posi ; /* position i du noeud */ + uint32 posj ; /* position j du noeud */ + uint32 centre_i ; /* centre i du segment */ + uint32 centre_j ; /* centre j du segment */ + + int last_move ; /* dernier test deplacement accepte */ + + /* lien liste chainee snake2D */ + struct snake_node *noeud_suiv ; /* dans le sens trigo */ + struct snake_node *noeud_prec ; + + + /* lien liste chainee snake3D */ +}; + + +struct snake_node_gpu +{ + t_sum_1 sum_1 ; + t_sum_x sum_x ; + t_sum_x2 sum_x2; + + int code_segment ; /* signe de la contrib */ + int freeman_in ; /* du noeud d'arrivee du segment (ordre trigo) */ + int freeman_out ; /* du noeud de depart du segment (ordre trigo) */ + uint32 nb_pixels ; + + uint32 posi ; /* position i du noeud */ + uint32 posj ; /* position j du noeud */ + uint32 centre_i ; /* centre i du segment */ + uint32 centre_j ; /* centre j du segment */ + + int last_move ; /* dernier test deplacement accepte */ +}; + + +#endif