Ajout du support du multi-GPU pour Mandelbrot.
[GPU.git] / WCudaMSE / Student_Cuda_Image / src / cpp / core / 02_Mandelbrot_Julia / moo / host / Fractal.cu
1 #include "Fractal.h"\r
2 \r
3 #include <iostream>\r
4 #include <sstream>\r
5 #include <assert.h>\r
6 using namespace std;\r
7 \r
8 #include <omp.h>\r
9 \r
10 #include "FractalDevice.h"\r
11 #include "Device.h"\r
12 \r
13 Fractal::Fractal(int w, int h) :\r
14         w(w), h(h),\r
15         dg(8, 8, 1),\r
16         db(16, 16, 1)\r
17     {\r
18     //print(dg, db);\r
19     Device::assertDim(dg, db);\r
20     }\r
21 \r
22 Fractal::~Fractal()\r
23     {\r
24     delete this->ptrDomaineMathInit;\r
25     }\r
26 \r
27 /**\r
28  * Override\r
29  */\r
30 int Fractal::getW()\r
31     {\r
32     return this->w;\r
33     }\r
34 \r
35 /**\r
36  * Override\r
37  */\r
38 int Fractal::getH()\r
39     {\r
40     return this->h;\r
41     }\r
42 \r
43 DomaineMath* Fractal::getDomaineMathInit()\r
44     {\r
45     return this->ptrDomaineMathInit;\r
46     }\r
47 \r
48 /////\r
49 \r
50 FractalMandelbrot::FractalMandelbrot(int w, int h, int dn, bool multiGPU) :\r
51         Fractal(w, h),\r
52         variateurAnimationN(IntervalI(10, 100), dn),\r
53         n(0),\r
54         multiGPU(multiGPU)\r
55     {\r
56     // Constuit le titre dynamiquement.\r
57     ostringstream titleStream;\r
58     titleStream << "Fractal Mandelbrot (multi-GPU " << (this->multiGPU ? "activated" : "not activated") << ")";\r
59     this->title = titleStream.str();\r
60 \r
61     this->ptrDomaineMathInit = new DomaineMath(-2, -1.3, 0.8, 1.3);\r
62 \r
63     if (this->multiGPU)\r
64         {\r
65         const int nbDevice = Device::getDeviceCount();\r
66 \r
67         this->hDevices = h / nbDevice;\r
68         this->hFirstDevice = h - ((nbDevice - 1) * this->hDevices);\r
69 \r
70         // Allocation de la mémoire sur chaque GPU (sauf le premier pour lequel 'ptrDevPixels' est automatiquement alloué à l'appel de 'runGPU(..)').\r
71         this->ptrDevPixelsMultGPU = new uchar4*[nbDevice - 1];\r
72         for (int i = 0; i < nbDevice - 1; ++i)\r
73             {\r
74             HANDLE_ERROR(cudaSetDevice(i + 1));\r
75             HANDLE_ERROR(cudaMalloc(&this->ptrDevPixelsMultGPU[i], sizeof(uchar4) * w * this->hDevices));\r
76             }\r
77 \r
78         HANDLE_ERROR(cudaSetDevice(0));\r
79         }\r
80     }\r
81 \r
82 void FractalMandelbrot::animationStep()\r
83     {\r
84     this->n = this->variateurAnimationN.varierAndGet();\r
85     }\r
86 \r
87 vector<string> FractalMandelbrot::getNames()\r
88     {\r
89     vector<string> name;\r
90     name.push_back("n = ");\r
91     return name;\r
92     }\r
93 \r
94 void FractalMandelbrot::getValues(float* values)\r
95     {\r
96     values[0] = float(this->n);\r
97     }\r
98 \r
99 string FractalMandelbrot::getTitle()\r
100     {\r
101     return this->title;\r
102     }\r
103 \r
104 void FractalMandelbrot::runGPU(uchar4* ptrDevPixels, const DomaineMath& domaineMath)\r
105     {\r
106 \r
107     if (this->multiGPU)\r
108         {\r
109         HANDLE_ERROR(cudaSetDevice(0));\r
110         fractalMandelbrot<<<dg,db>>>(ptrDevPixels, this->w, 0, this->hFirstDevice, domaineMath, this->n);\r
111 \r
112         const int nbDevice = Device::getDeviceCount();\r
113 \r
114         // Rend chaque tranche par un GPU différent puis copie chaque tranche dans la mémoire du premier GPU.\r
115         #pragma omp parallel for\r
116         for (int i = 0; i < nbDevice - 1; ++i)\r
117             {\r
118             HANDLE_ERROR(cudaSetDevice(i + 1));\r
119             fractalMandelbrot<<<dg,db>>>(this->ptrDevPixelsMultGPU[i], this->w, i * this->hDevices + this->hFirstDevice, (i + 1) * this->hDevices + this->hFirstDevice, domaineMath, this->n);\r
120             HANDLE_ERROR(cudaMemcpy(ptrDevPixels + this->w * this->hFirstDevice + i * this->w * this->hDevices, this->ptrDevPixelsMultGPU[i], sizeof(uchar4) * this->w * this->hDevices, cudaMemcpyDeviceToDevice));\r
121             }\r
122 \r
123         HANDLE_ERROR(cudaSetDevice(0));\r
124         }\r
125     else\r
126         {\r
127         fractalMandelbrot<<<dg,db>>>(ptrDevPixels, this->w, 0, this->h, domaineMath, this->n);\r
128         }\r
129     }\r
130 \r
131 /////\r
132 \r
133 FractalJulia::FractalJulia(int w, int h, int n, float z_r_min, float z_r_max, float z_i_min, float z_i_max) :\r
134         Fractal(w, h),\r
135         n(n),\r
136         z_r(z_r_min),\r
137         z_i(z_i_min),\r
138         variateurAnimationR(IntervalF(-0.8, -0.7), 0.0005),\r
139         variateurAnimationI(IntervalF(-0.3, 0.3), 0.0004)\r
140     {\r
141     this->ptrDomaineMathInit = new DomaineMath(-1.7, -1.4, 1.7, 1.4);\r
142     }\r
143 \r
144 void FractalJulia::animationStep()\r
145     {\r
146     this->z_r = this->variateurAnimationR.varierAndGet();\r
147     this->z_i = this->variateurAnimationI.varierAndGet();\r
148     }\r
149 \r
150 vector<string> FractalJulia::getNames()\r
151     {\r
152     vector<string> name;\r
153     name.push_back("z_r = ");\r
154     name.push_back("z_i = ");\r
155     return name;\r
156     }\r
157 \r
158 void FractalJulia::getValues(float* values)\r
159     {\r
160     values[0] = this->z_r;\r
161     values[1] = this->z_i;\r
162     }\r
163 \r
164 string FractalJulia::getTitle()\r
165     {\r
166     return "Fractal Julia";\r
167     }\r
168 \r
169 void FractalJulia::runGPU(uchar4* ptrDevPixels, const DomaineMath& domaineMath)\r
170     {\r
171     fractalJulia<<<dg,db>>>(ptrDevPixels, this->w, this->h, domaineMath, this->n, this->z_r, this->z_i);\r
172     }\r
173 \r