Mandelbrot.cpp | MandelbrotCUDA.cpp | |||
---|---|---|---|---|
456 lines 14440 bytes Last modified : Tue Jul 22 17:20:58 2008 |
358 lines 10307 bytes Last modified : Tue Jul 22 17:20:43 2008 |
|||
1 | // Mandelbrot sample | 1 | // Mandelbrot sample | |
2 | // submitted by Mark Granger, NewTek | 2 | // submitted by Mark Granger, NewTek | |
3 | 3 | |||
4 | #include <stdio.h> | 4 | #include <stdio.h> | |
5 | #include <stdlib.h> | 5 | #include <stdlib.h> | |
6 | #include <string.h> | 6 | #include <string.h> | |
7 | #include <GL/glew.h> | 7 | #include <GL/glew.h> | |
8 | #include <GL/glut.h> | 8 | #include <GL/glut.h> | |
9 | #include <cuda_runtime_api.h> | 9 | #include <cuda_runtime_api.h> | |
10 | #include <cuda_gl_interop.h> | 10 | #include <cuda_gl_interop.h> | |
11 | #include "cutil.h" | 11 | #include "cutil.h" | |
12 | #include "Mandelbrot_kernel.h" | 12 | #include "Mandelbrot_kernel.h" | |
13 | #include "Mandelbrot_gold.h" | 13 | #include "Mandelbrot_gold.h" | |
14 | 14 | |||
15 | ||||
16 | ///////////////////////////// | |||
17 | #include <sys/types.h> | |||
18 | #include <sys/stat.h> | |||
19 | #include <fcntl.h> | |||
20 | #include <unistd.h> | |||
21 | #include <netinet/in.h> | |||
22 | #include <sys/socket.h> | |||
23 | #include <arpa/inet.h> | |||
24 | ///////////////////////////// | |||
25 | // | |||
26 | // | |||
27 | ||||
28 | /**/ | |||
29 | int sanity=0; | |||
30 | int portNumber; | |||
31 | int sockfd; | |||
32 | /**/ | |||
33 | ||||
15 | // Set to 1 to run on the CPU instead of the GPU for timing comparison. | 34 | // Set to 1 to run on the CPU instead of the GPU for timing comparison. | |
16 | #define RUN_CPU 0 | 35 | #define RUN_CPU 0 | |
17 | 36 | |||
18 | // Set to 1 to time frame generation | 37 | // Set to 1 to time frame generation | |
19 | #define RUN_TIMING 0 | 38 | #define RUN_TIMING 0 | |
20 | 39 | |||
21 | // Random number macros | 40 | // Random number macros | |
22 | #define RANDOMSEED(seed) ((seed) = ((seed) * 1103515245 + 12345)) | 41 | #define RANDOMSEED(seed) ((seed) = ((seed) * 1103515245 + 12345)) | |
23 | #define RANDOMBITS(seed, bits) ((unsigned int)RANDOMSEED(seed) >> (32 - (bits))) | 42 | #define RANDOMBITS(seed, bits) ((unsigned int)RANDOMSEED(seed) >> (32 - (bits))) | |
24 | 43 | |||
44 | // Define types of requests | |||
45 | #define GETNEWFRAME 0x0 | |||
46 | #define ZOOMIN 0x2 | |||
47 | #define ZOOMOUT 0x3 | |||
48 | #define MOVERIGHT 0x4 | |||
49 | #define MOVEUP 0x5 | |||
50 | #define MOVELEFT 0x6 | |||
51 | #define MOVEDOWN 0x7 | |||
52 | #define TERMINATE 0x8 | |||
53 | #define MOUSE 0x9 | |||
54 | #define CLICK 0x1 | |||
55 | #define MOTION 0x2 | |||
56 | #define LEFTCLICK 0x0 | |||
57 | #define RIGHTCLICK 0x1 | |||
58 | ||||
25 | //OpenGL PBO and texture "names" | 59 | //OpenGL PBO and texture "names" | |
26 | GLuint gl_PBO, gl_Tex; | 60 | GLuint gl_PBO, gl_Tex; | |
27 | 61 | |||
28 | //Source image on the host side | 62 | //Mandelbrot data | |
29 | uchar4 *h_Src; | 63 | uchar4 * mandelbrot_data; | |
64 | uchar4 * gpu_mandelbrot_data; | |||
30 | 65 | |||
31 | //Original image width and height | 66 | //Original image width and height | |
32 | int imageW, imageH; | 67 | int imageW, imageH; | |
33 | 68 | |||
34 | // Starting iteration limit | 69 | // Starting iteration limit | |
35 | int crunch = 512; | 70 | int crunch = 512; | |
36 | 71 | |||
37 | // Starting position and scale | 72 | // Starting position and scale | |
38 | double xOff = -0.5; | 73 | double xOff = -0.5; | |
39 | double yOff = 0.0; | 74 | double yOff = 0.0; | |
40 | double scale = 3.2; | 75 | double scale = 3.2; | |
41 | 76 | |||
42 | // Starting stationary position and scale motion | 77 | // Starting stationary position and scale motion | |
43 | double xdOff = 0.0; | 78 | double xdOff = 0.0; | |
44 | double ydOff = 0.0; | 79 | double ydOff = 0.0; | |
45 | double dscale = 1.0; | 80 | double dscale = 1.0; | |
46 | 81 | |||
47 | // Starting animation frame and anti-aliasing pass | 82 | // Starting animation frame and anti-aliasing pass | |
48 | int animationFrame = 0; | 83 | int animationFrame = 0; | |
49 | int animationStep = 0; | 84 | int animationStep = 0; | |
50 | int pass = 0; | 85 | int pass = 0; | |
51 | 86 | |||
52 | // Starting color multipliers and random seed | 87 | // Starting color multipliers and random seed | |
53 | int colorSeed = 0; | 88 | int colorSeed = 0; | |
54 | uchar4 colors; | 89 | uchar4 colors; | |
55 | 90 | |||
56 | // Timer ID | 91 | // Timer ID | |
57 | unsigned int hTimer; | 92 | unsigned int hTimer; | |
58 | 93 | |||
59 | // User interface variables | 94 | // User interface variables | |
60 | int lastx = 0; | 95 | int lastx = 0; | |
61 | int lasty = 0; | 96 | int lasty = 0; | |
62 | bool leftClicked = false; | 97 | bool leftClicked = false; | |
63 | bool rightClicked = false; | 98 | bool rightClicked = false; | |
64 | 99 | |||
100 | // Environment Variables | |||
101 | int rec_width, rec_heigh, max_pass = 8; | |||
102 | ||||
65 | #define BUFFER_DATA(i) ((char *)0 + i) | 103 | #define BUFFER_DATA(i) ((char *)0 + i) | |
66 | 104 | |||
67 | // Get a sub-pixel sample location | 105 | // Get a sub-pixel sample location | |
68 | void GetSample(int sampleIndex, float &x, float &y) | 106 | void GetSample(int sampleIndex, float &x, float &y) | |
69 | { | 107 | { | |
70 | static const unsigned char pairData[128][2] = { | 108 | static const unsigned char pairData[128][2] = { | |
71 | { 64, 64}, { 0, 0}, { 1, 63}, { 63, 1}, { 96, 32}, { 97, 95}, { 36, 96}, { 30, 31}, | 109 | { 64, 64}, { 0, 0}, { 1, 63}, { 63, 1}, { 96, 32}, { 97, 95}, { 36, 96}, { 30, 31}, | |
72 | { 95, 127}, { 4, 97}, { 33, 62}, { 62, 33}, { 31, 126}, { 67, 99}, { 99, 65}, { 2, 34}, | 110 | { 95, 127}, { 4, 97}, { 33, 62}, { 62, 33}, { 31, 126}, { 67, 99}, { 99, 65}, { 2, 34}, | |
73 | { 81, 49}, { 19, 80}, {113, 17}, {112, 112}, { 80, 16}, {115, 81}, { 46, 15}, { 82, 79}, | 111 | { 81, 49}, { 19, 80}, {113, 17}, {112, 112}, { 80, 16}, {115, 81}, { 46, 15}, { 82, 79}, | |
74 | { 48, 78}, { 16, 14}, { 49, 113}, {114, 48}, { 45, 45}, { 18, 47}, { 20, 109}, { 79, 115}, | 112 | { 48, 78}, { 16, 14}, { 49, 113}, {114, 48}, { 45, 45}, { 18, 47}, { 20, 109}, { 79, 115}, | |
75 | { 65, 82}, { 52, 94}, { 15, 124}, { 94, 111}, { 61, 18}, { 47, 30}, { 83, 100}, { 98, 50}, | 113 | { 65, 82}, { 52, 94}, { 15, 124}, { 94, 111}, { 61, 18}, { 47, 30}, { 83, 100}, { 98, 50}, | |
76 | {110, 2}, {117, 98}, { 50, 59}, { 77, 35}, { 3, 114}, { 5, 77}, { 17, 66}, { 32, 13}, | 114 | {110, 2}, {117, 98}, { 50, 59}, { 77, 35}, { 3, 114}, { 5, 77}, { 17, 66}, { 32, 13}, | |
77 | {127, 20}, { 34, 76}, { 35, 110}, {100, 12}, {116, 67}, { 66, 46}, { 14, 28}, { 23, 93}, | 115 | {127, 20}, { 34, 76}, { 35, 110}, {100, 12}, {116, 67}, { 66, 46}, { 14, 28}, { 23, 93}, | |
78 | {102, 83}, { 86, 61}, { 44, 125}, { 76, 3}, {109, 36}, { 6, 51}, { 75, 89}, { 91, 21}, | 116 | {102, 83}, { 86, 61}, { 44, 125}, { 76, 3}, {109, 36}, { 6, 51}, { 75, 89}, { 91, 21}, | |
79 | { 60, 117}, { 29, 43}, {119, 29}, { 74, 70}, {126, 87}, { 93, 75}, { 71, 24}, {106, 102}, | 117 | { 60, 117}, { 29, 43}, {119, 29}, { 74, 70}, {126, 87}, { 93, 75}, { 71, 24}, {106, 102}, | |
80 | {108, 58}, { 89, 9}, {103, 23}, { 72, 56}, {120, 8}, { 88, 40}, { 11, 88}, {104, 120}, | 118 | {108, 58}, { 89, 9}, {103, 23}, { 72, 56}, {120, 8}, { 88, 40}, { 11, 88}, {104, 120}, | |
81 | { 57, 105}, {118, 122}, { 53, 6}, {125, 44}, { 43, 68}, { 58, 73}, { 24, 22}, { 22, 5}, | 119 | { 57, 105}, {118, 122}, { 53, 6}, {125, 44}, { 43, 68}, { 58, 73}, { 24, 22}, { 22, 5}, | |
82 | { 40, 86}, {122, 108}, { 87, 90}, { 56, 42}, { 70, 121}, { 8, 7}, { 37, 52}, { 25, 55}, | 120 | { 40, 86}, {122, 108}, { 87, 90}, { 56, 42}, { 70, 121}, { 8, 7}, { 37, 52}, { 25, 55}, | |
83 | { 69, 11}, { 10, 106}, { 12, 38}, { 26, 69}, { 27, 116}, { 38, 25}, { 59, 54}, {107, 72}, | 121 | { 69, 11}, { 10, 106}, { 12, 38}, { 26, 69}, { 27, 116}, { 38, 25}, { 59, 54}, {107, 72}, | |
84 | {121, 57}, { 39, 37}, { 73, 107}, { 85, 123}, { 28, 103}, {123, 74}, { 55, 85}, {101, 41}, | 122 | {121, 57}, { 39, 37}, { 73, 107}, { 85, 123}, { 28, 103}, {123, 74}, { 55, 85}, {101, 41}, | |
85 | { 42, 104}, { 84, 27}, {111, 91}, { 9, 19}, { 21, 39}, { 90, 53}, { 41, 60}, { 54, 26}, | 123 | { 42, 104}, { 84, 27}, {111, 91}, { 9, 19}, { 21, 39}, { 90, 53}, { 41, 60}, { 54, 26}, | |
86 | { 92, 119}, { 51, 71}, {124, 101}, { 68, 92}, { 78, 10}, { 13, 118}, { 7, 84}, {105, 4} | 124 | { 92, 119}, { 51, 71}, {124, 101}, { 68, 92}, { 78, 10}, { 13, 118}, { 7, 84}, {105, 4} | |
87 | }; | 125 | }; | |
88 | 126 | |||
89 | x = (1.0f / 128.0f) * (0.5f + (float)pairData[sampleIndex][0]); | 127 | x = (1.0f / 128.0f) * (0.5f + (float)pairData[sampleIndex][0]); | |
90 | y = (1.0f / 128.0f) * (0.5f + (float)pairData[sampleIndex][1]); | 128 | y = (1.0f / 128.0f) * (0.5f + (float)pairData[sampleIndex][1]); | |
91 | } // GetSample | 129 | } // GetSample | |
92 | 130 | |||
93 | // OpenGL display function | 131 | // OpenGL update function | |
94 | void displayFunc(void) | 132 | void update(void) | |
95 | { | 133 | { | |
134 | // uchar4 *d_dst = NULL; | |||
96 | if ((xdOff != 0.0) || (ydOff != 0.0)) { | 135 | if ((xdOff != 0.0) || (ydOff != 0.0)) { | |
97 | xOff += xdOff; | 136 | xOff += xdOff; | |
98 | yOff += ydOff; | 137 | yOff += ydOff; | |
99 | pass = 0; | 138 | pass = 0; | |
100 | } | 139 | } | |
101 | if (dscale != 1.0) { | 140 | if (dscale != 1.0) { | |
102 | scale *= dscale; | 141 | scale *= dscale; | |
103 | pass = 0; | 142 | pass = 0; | |
104 | } | 143 | } | |
105 | if (animationStep) { | 144 | ||
106 | animationFrame -= animationStep; | 145 | do { | |
107 | pass = 0; | 146 | // Render anti-aliasing passes until we run out time (60fps approximately) | |
108 | } | 147 | float xs, ys; | |
109 | #if RUN_TIMING | 148 | ||
110 | pass = 0; | 149 | // Get the anti-alias sub-pixel sample location | |
111 | #endif | 150 | GetSample(pass & 127, xs, ys); | |
112 | #if RUN_CPU | 151 | ||
113 | if (pass < 128) { | 152 | // Get the pixel scale and offset | |
114 | int startPass = pass; | 153 | double s = scale / (float)imageW; | |
115 | uchar4 *d_dst = NULL; | 154 | double x = (xs - (double)imageW * 0.5f) * s + xOff; | |
116 | float xs, ys; | 155 | double y = (ys - (double)imageH * 0.5f) * s + yOff; | |
117 | cutResetTimer(hTimer); | 156 | ||
118 | CUDA_SAFE_CALL(cudaGLMapBufferObject((void**)&d_dst, gl_PBO)); | 157 | // Run the mandelbrot generator | |
119 | 158 | RunMandelbrot0(gpu_mandelbrot_data, imageW, imageH, crunch, x, y, s, colors, pass++, animationFrame); | ||
120 | // Get the anti-alias sub-pixel sample location | 159 | cudaThreadSynchronize(); | |
121 | GetSample(pass & 127, xs, ys); | 160 | } while(pass < max_pass); | |
122 | 161 | cudaMemcpy(mandelbrot_data, gpu_mandelbrot_data, imageW * imageH * 4 * sizeof(char), cudaMemcpyDeviceToHost); | ||
123 | // Get the pixel scale and offset | 162 | } // displayFunc | |
124 | double s = scale / (double)imageW; | |||
125 | double x = (xs - (double)imageW * 0.5f) * s + xOff; | |||
126 | double y = (ys - (double)imageH * 0.5f) * s + yOff; | |||
127 | ||||
128 | // Run the mandelbrot generator | |||
129 | if (pass && !startPass) // Use the adaptive sampling version when animating. | |||
130 | RunMandelbrotDSGold1(h_Src, imageW, imageH, crunch, x, y, s, colors, pass++, animationFrame); | |||
131 | else | |||
132 | RunMandelbrotDSGold0(h_Src, imageW, imageH, crunch, x, y, s, colors, pass++, animationFrame); | |||
133 | CUDA_SAFE_CALL(cudaMemcpy(d_dst, h_Src, imageW * imageH * sizeof(uchar4), cudaMemcpyHostToDevice)); | |||
134 | CUDA_SAFE_CALL(cudaGLUnmapBufferObject(gl_PBO)); | |||
135 | #if RUN_TIMING | |||
136 | printf("CPU = %5.8f\n", 0.001f * cutGetTimerValue(hTimer)); | |||
137 | #endif | |||
138 | } | |||
139 | 163 | |||
140 | #else | |||
141 | if (pass < 128) { | |||
142 | float timeEstimate; | |||
143 | int startPass = pass; | |||
144 | uchar4 *d_dst = NULL; | |||
145 | cutResetTimer(hTimer); | |||
146 | CUDA_SAFE_CALL(cudaGLMapBufferObject((void**)&d_dst, gl_PBO)); | |||
147 | ||||
148 | // Render anti-aliasing passes until we run out time (60fps approximately) | |||
149 | do { | |||
150 | float xs, ys; | |||
151 | ||||
152 | // Get the anti-alias sub-pixel sample location | |||
153 | GetSample(pass & 127, xs, ys); | |||
154 | ||||
155 | // Get the pixel scale and offset | |||
156 | double s = scale / (float)imageW; | |||
157 | double x = (xs - (double)imageW * 0.5f) * s + xOff; | |||
158 | double y = (ys - (double)imageH * 0.5f) * s + yOff; | |||
159 | ||||
160 | // Run the mandelbrot generator | |||
161 | if (pass && !startPass) // Use the adaptive sampling version when animating. | |||
162 | RunMandelbrot1(d_dst, imageW, imageH, crunch, x, y, s, colors, pass++, animationFrame); | |||
163 | else | |||
164 | RunMandelbrot0(d_dst, imageW, imageH, crunch, x, y, s, colors, pass++, animationFrame); | |||
165 | cudaThreadSynchronize(); | |||
166 | ||||
167 | // Estimate the total time of the frame if one more pass is rendered | |||
168 | timeEstimate = 0.001f * cutGetTimerValue(hTimer) * ((float)(pass + 1 - startPass) / (float)(pass - startPass)); | |||
169 | } while ((pass < 128) && (timeEstimate < 1.0f / 60.0f) && !RUN_TIMING); | |||
170 | CUDA_SAFE_CALL(cudaGLUnmapBufferObject(gl_PBO)); | |||
171 | #if RUN_TIMING | |||
172 | printf("GPU = %5.8f\n", 0.001f * cutGetTimerValue(hTimer)); | |||
173 | #endif | |||
174 | } | |||
175 | #endif | |||
176 | 164 | |||
177 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, imageW, imageH, GL_RGBA, GL_UNSIGNED_BYTE, BUFFER_DATA(0)); | 165 | /**********Network Functions*****************/ | |
178 | glBegin(GL_TRIANGLES); | 166 | void waitForConnection(int port) { | |
179 | glTexCoord2f(0.0f, 0.0f); | 167 | int mySocket; | |
180 | glVertex2f(-1.0f, -1.0f); | 168 | if((mySocket=socket(PF_INET,SOCK_STREAM,0))==-1) { | |
181 | glTexCoord2f(2.0f, 0.0f); | 169 | perror("socket()"); | |
182 | glVertex2f(3.0f, -1.0f); | 170 | exit(1); | |
183 | glTexCoord2f(0.0f, 2.0f); | 171 | } | |
184 | glVertex2f(-1.0f, 3.0f); | |||
185 | glEnd(); | |||
186 | 172 | |||
187 | glutSwapBuffers(); | 173 | int yes=1; | |
188 | } // displayFunc | 174 | if(setsockopt(mySocket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int))==-1) { | |
175 | perror("setsockopt()"); | |||
176 | exit(1); | |||
177 | } | |||
189 | 178 | |||
190 | // OpenGL keyboard function | 179 | struct sockaddr_in my_addr; | |
191 | void keyboardFunc(unsigned char k, int, int) | 180 | my_addr.sin_family=AF_INET; | |
192 | { | 181 | my_addr.sin_port=htons(port); | |
193 | int seed; | 182 | my_addr.sin_addr.s_addr=INADDR_ANY; | |
194 | switch (k){ | 183 | memset(my_addr.sin_zero, '\0', sizeof my_addr.sin_zero); | |
195 | case '\033': | 184 | ||
196 | case 'q': | 185 | if(bind(mySocket,(struct sockaddr*)&my_addr, sizeof(struct sockaddr))==-1) { | |
197 | case 'Q': | 186 | perror("bind()"); | |
198 | printf("Shutting down...\n"); | 187 | exit(1); | |
199 | CUT_SAFE_CALL(cutStopTimer(hTimer) ); | |||
200 | CUT_SAFE_CALL(cutDeleteTimer(hTimer)); | |||
201 | CUDA_SAFE_CALL(cudaGLUnregisterBufferObject(gl_PBO)); | |||
202 | glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0); | |||
203 | glDeleteBuffers(1, &gl_PBO); | |||
204 | glDeleteTextures(1, &gl_Tex); | |||
205 | free(h_Src); | |||
206 | printf("Shutdown done.\n"); | |||
207 | exit(0); | |||
208 | break; | |||
209 | ||||
210 | case '?': | |||
211 | printf("xOff = %5.8f\n", xOff); | |||
212 | printf("yOff = %5.8f\n", yOff); | |||
213 | printf("scale = %5.8f\n", scale); | |||
214 | printf("detail = %d\n", crunch); | |||
215 | printf("color = %d\n", colorSeed); | |||
216 | printf("\n"); | |||
217 | break; | |||
218 | ||||
219 | case 'r': case 'R': | |||
220 | // Reset all values to their defaults | |||
221 | xOff = -0.5; | |||
222 | yOff = 0.0; | |||
223 | scale = 3.2; | |||
224 | xdOff = 0.0; | |||
225 | ydOff = 0.0; | |||
226 | dscale = 1.0; | |||
227 | colorSeed = 0; | |||
228 | colors.x = 3; | |||
229 | colors.y = 5; | |||
230 | colors.z = 7; | |||
231 | crunch = 512; | |||
232 | animationFrame = 0; | |||
233 | animationStep = 0; | |||
234 | pass = 0; | |||
235 | break; | |||
236 | ||||
237 | case 'c': | |||
238 | seed = ++colorSeed; | |||
239 | if (seed) { | |||
240 | colors.x = RANDOMBITS(seed, 4); | |||
241 | colors.y = RANDOMBITS(seed, 4); | |||
242 | colors.z = RANDOMBITS(seed, 4); | |||
243 | } else { | |||
244 | colors.x = 3; | |||
245 | colors.y = 5; | |||
246 | colors.z = 7; | |||
247 | } | |||
248 | pass = 0; | |||
249 | break; | |||
250 | ||||
251 | case 'C': | |||
252 | seed = --colorSeed; | |||
253 | if (seed) { | |||
254 | colors.x = RANDOMBITS(seed, 4); | |||
255 | colors.y = RANDOMBITS(seed, 4); | |||
256 | colors.z = RANDOMBITS(seed, 4); | |||
257 | } else { | |||
258 | colors.x = 3; | |||
259 | colors.y = 5; | |||
260 | colors.z = 7; | |||
261 | } | |||
262 | pass = 0; | |||
263 | break; | |||
264 | ||||
265 | case 'a': | |||
266 | if (animationStep < 0) | |||
267 | animationStep = 0; | |||
268 | else { | |||
269 | animationStep++; | |||
270 | if (animationStep > 8) | |||
271 | animationStep = 8; | |||
272 | } | |||
273 | break; | |||
274 | ||||
275 | case 'A': | |||
276 | if (animationStep > 0) | |||
277 | animationStep = 0; | |||
278 | else { | |||
279 | animationStep--; | |||
280 | if (animationStep < -8) | |||
281 | animationStep = -8; | |||
282 | } | |||
283 | break; | |||
284 | ||||
285 | case 'd': | |||
286 | if (crunch < 0x40000000) { | |||
287 | crunch *= 2; | |||
288 | pass = 0; | |||
289 | } | |||
290 | break; | |||
291 | ||||
292 | case 'D': | |||
293 | if (crunch > 2) { | |||
294 | crunch /= 2; | |||
295 | pass = 0; | |||
296 | } | |||
297 | break; | |||
298 | ||||
299 | case '4': // Left arrow key | |||
300 | xOff -= 0.05f * scale; | |||
301 | pass = 0; | |||
302 | break; | |||
303 | ||||
304 | case '8': // Up arrow key | |||
305 | yOff += 0.05f * scale; | |||
306 | pass = 0; | |||
307 | break; | |||
308 | ||||
309 | case '6': // Right arrow key | |||
310 | xOff += 0.05f * scale; | |||
311 | pass = 0; | |||
312 | break; | |||
313 | ||||
314 | case '2': // Down arrow key | |||
315 | yOff -= 0.05f * scale; | |||
316 | pass = 0; | |||
317 | break; | |||
318 | ||||
319 | case '+': | |||
320 | scale /= 1.1f; | |||
321 | pass = 0; | |||
322 | break; | |||
323 | ||||
324 | case '-': | |||
325 | scale *= 1.1f; | |||
326 | pass = 0; | |||
327 | break; | |||
328 | ||||
329 | default: | |||
330 | break; | |||
331 | } | 188 | } | |
332 | } // keyboardFunc | |||
333 | 189 | |||
334 | // OpenGL mouse click function | 190 | if(listen(mySocket,5)==-1) { | |
335 | void clickFunc(int button, int, int x, int y) | 191 | perror("listen()"); | |
336 | { | 192 | exit(1); | |
337 | if (button == 0) | 193 | } | |
338 | leftClicked = !leftClicked; | |||
339 | if (button == 2) | |||
340 | rightClicked = !rightClicked; | |||
341 | lastx = x; | |||
342 | lasty = y; | |||
343 | xdOff = 0.0; | |||
344 | ydOff = 0.0; | |||
345 | dscale = 1.0; | |||
346 | } // clickFunc | |||
347 | 194 | |||
348 | // OpenGL mouse motion function | 195 | struct sockaddr_in remote_addr; | |
349 | void motionFunc(int x, int y) | 196 | int sin_size=sizeof remote_addr; | |
350 | { | 197 | ||
351 | double fx = (double)((x - lastx) / 10) / (double)(imageW); | 198 | fprintf(stdout,"Waiting for connection on port %d...\n",port); | |
352 | double fy = (double)((lasty - y) / 10) / (double)(imageW); | 199 | if((sockfd=accept(mySocket, (struct sockaddr*)&remote_addr, (socklen_t*)&sin_size))==-1) { | |
200 | perror("accept()"); | |||
201 | exit(1); | |||
202 | } | |||
353 | 203 | |||
354 | if (leftClicked) { | 204 | fprintf(stdout, "Accepted connection from %s\n",inet_ntoa(remote_addr.sin_addr)); | |
355 | xdOff = fx * scale; | 205 | } | |
356 | ydOff = fy * scale; | |||
357 | } else { | |||
358 | xdOff = 0.0f; | |||
359 | ydOff = 0.0f; | |||
360 | } | |||
361 | ||||
362 | if (rightClicked) | |||
363 | if (fy > 0.0f) { | |||
364 | dscale = 1.0 - fy; | |||
365 | dscale = dscale < 1.05 ? dscale : 1.05; | |||
366 | } else { | |||
367 | dscale = 1.0 / (1.0 + fy); | |||
368 | dscale = dscale > (1.0 / 1.05) ? dscale : (1.0 / 1.05); | |||
369 | } | |||
370 | else | |||
371 | dscale = 1.0; | |||
372 | } // motionFunc | |||
373 | 206 | |||
374 | void idleFunc() | 207 | void initEnvironmentVariables(void) { | |
375 | { | 208 | int env[3]; | |
376 | glutPostRedisplay(); | 209 | recv(sockfd, env, 3*sizeof(int), 0); | |
210 | imageW = env[0]; | |||
211 | imageH = env[1]; | |||
212 | max_pass = env[2]; | |||
213 | printf("Received environment variables: imageW = %d, imageH = %d, max_pass = %d\n", imageW, imageH, max_pass); | |||
377 | } | 214 | } | |
378 | 215 | |||
216 | void requestLoop() { | |||
217 | ||||
218 | char requestBuffer[16]; | |||
219 | int bytesRead,bytesSent; | |||
220 | char request; | |||
221 | ||||
222 | // fprintf(stdout,"Waiting for requests...\n"); | |||
223 | while(true) { | |||
224 | bytesRead=recv(sockfd, (void*)requestBuffer,16 * sizeof(char),0); | |||
225 | if(bytesRead==-1) { | |||
226 | perror("recv()"); | |||
227 | exit(0); | |||
228 | } | |||
229 | if(bytesRead==0) exit(0); | |||
230 | ||||
231 | request=requestBuffer[0]; | |||
232 | ||||
233 | if(request == GETNEWFRAME) { | |||
234 | fprintf(stderr,"New frame requested\n"); | |||
235 | update( ); | |||
236 | bytesSent=send(sockfd,(void*)mandelbrot_data, imageW * imageH * 4 * sizeof(char),0); | |||
237 | if(bytesSent==-1) {perror("send()"); exit(1);} | |||
238 | // fprintf(stderr,"Sent %d bytes\n",bytesSent); | |||
239 | } | |||
240 | else if(request==ZOOMIN) { | |||
241 | // fprintf(stdout, "Received request to zoom in\n"); | |||
242 | scale /= 1.1; | |||
243 | pass = 0; | |||
244 | } | |||
245 | else if(request==ZOOMOUT) { | |||
246 | // fprintf(stdout, "Received request to zoom out\n"); | |||
247 | scale *= 1.1; | |||
248 | pass = 0; | |||
249 | } | |||
250 | else if(request==MOVELEFT) { | |||
251 | // fprintf(stdout, "Received request to move left\n"); | |||
252 | xOff -= 0.05f * scale; | |||
253 | pass = 0; | |||
254 | } | |||
255 | else if(request==MOVERIGHT) { | |||
256 | // fprintf(stdout, "Received request to move right\n"); | |||
257 | xOff += 0.05f * scale; | |||
258 | pass = 0; | |||
259 | } | |||
260 | else if(request==MOVEUP) { | |||
261 | // fprintf(stdout, "Received request to move up\n"); | |||
262 | yOff += 0.05f * scale; | |||
263 | pass = 0; | |||
264 | } | |||
265 | else if(request==MOVEDOWN) { | |||
266 | // fprintf(stdout, "Received request to move down\n"); | |||
267 | yOff -= 0.05f * scale; | |||
268 | pass = 0; | |||
269 | } | |||
270 | else if(request==MOUSE) { | |||
271 | // fprintf(stdout, "Received mouse event\n"); | |||
272 | if(requestBuffer[1] == MOTION) { | |||
273 | int x_y[2]; | |||
274 | memcpy(x_y, &requestBuffer[2], 2*sizeof(int)); | |||
275 | ||||
276 | double fx = (double)((x_y[0] - lastx) / 10) / (double)(imageW); | |||
277 | double fy = (double)((x_y[1] - lasty) / 10) / (double)(imageH); | |||
278 | ||||
279 | if(leftClicked) { | |||
280 | xdOff = fx * scale; | |||
281 | ydOff = fy * scale; | |||
282 | } | |||
283 | else { | |||
284 | xdOff = 0.0f; | |||
285 | ydOff = 0.0f; | |||
286 | } | |||
287 | ||||
288 | if(rightClicked) { | |||
289 | if(fy > 0.0f) { | |||
290 | dscale = 1.0 - fy; | |||
291 | dscale = dscale < 1.05 ? dscale : 1.05f; | |||
292 | } | |||
293 | else { | |||
294 | dscale = 1.0 / (1.0 + fy); | |||
295 | dscale = dscale > (1.0 / 1.05) ? dscale : (1.0 / 1.05); | |||
296 | } | |||
297 | } | |||
298 | else { | |||
299 | dscale = 1.0; | |||
300 | } | |||
301 | ||||
302 | // fprintf(stdout, "Received a motion event at %d, %d\n", x_y[0], x_y[1]); | |||
303 | } | |||
304 | else if(requestBuffer[1] == CLICK) { | |||
305 | if(requestBuffer[2] == LEFTCLICK) { | |||
306 | leftClicked = !leftClicked; | |||
307 | } | |||
308 | else if(requestBuffer[2] == RIGHTCLICK) { | |||
309 | rightClicked = !rightClicked; | |||
310 | } | |||
311 | int x_y[2]; | |||
312 | memcpy(x_y, &requestBuffer[3], 2*sizeof(int)); | |||
313 | ||||
314 | lastx = x_y[0]; | |||
315 | lasty = x_y[1]; | |||
316 | ||||
317 | xdOff = 0.0; | |||
318 | ydOff = 0.0; | |||
319 | dscale = 1.0; | |||
320 | // fprintf(stdout, "Received a click event %d, %d, %d\n", requestBuffer[2], x_y[0], x_y[1]); | |||
321 | } | |||
322 | else { | |||
323 | fprintf(stdout, "Received an incorrect mouse request\n"); | |||
324 | } | |||
325 | } | |||
326 | else if(request==TERMINATE) { | |||
327 | fprintf(stdout,"Received request to terminate. Exiting...\n"); | |||
328 | exit(0); | |||
329 | } | |||
330 | else { | |||
331 | fprintf(stderr,"Received invalid command %d\n",request); | |||
332 | exit(1); | |||
333 | } | |||
334 | } | |||
335 | } | |||
336 | ||||
337 | ||||
379 | //////////////////////////////////////////////////////////////////////////////// | 338 | //////////////////////////////////////////////////////////////////////////////// | |
380 | // Main program | 339 | // Main program | |
381 | //////////////////////////////////////////////////////////////////////////////// | 340 | //////////////////////////////////////////////////////////////////////////////// | |
382 | int main(int argc, char **argv) | 341 | int main(int argc, char **argv) | |
383 | { | 342 | { | |
384 | CUT_DEVICE_INIT(); | 343 | if(argc != 2) { | |
385 | imageW = 800; | 344 | printf("USAGE: %s <port_number>\n", argv[0]); | |
386 | imageH = 600; | 345 | exit(0); | |
387 | h_Src = (uchar4*)malloc(imageW * imageH * 4); | 346 | } | |
347 | waitForConnection(atoi(argv[1])); | |||
348 | ||||
349 | initEnvironmentVariables( ); | |||
350 | mandelbrot_data = (uchar4*) malloc(imageW * imageH * 4); | |||
351 | cudaMalloc((void**)&gpu_mandelbrot_data, imageW * imageH * sizeof(uchar4)); | |||
388 | colors.w = 0; | 352 | colors.w = 0; | |
389 | colors.x = 3; | 353 | colors.x = 3; | |
390 | colors.y = 5; | 354 | colors.y = 5; | |
391 | colors.z = 7; | 355 | colors.z = 7; | |
392 | printf("Data init done.\n"); | 356 | // printf("Data init done.\n"); | |
393 | 357 | requestLoop( ); | ||
394 | printf("Initializing GLUT...\n"); | |||
395 | glutInit(&argc, argv); | |||
396 | glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); | |||
397 | glutInitWindowSize(imageW, imageH); | |||
398 | glutInitWindowPosition(512 - imageW / 2, 384 - imageH / 2); | |||
399 | glutCreateWindow(argv[0]); | |||
400 | printf("Loading extensions: %s\n", glewGetErrorString(glewInit())); | |||
401 | if(!glewIsSupported( | |||
402 | "GL_VERSION_2_0 " | |||
403 | "GL_ARB_pixel_buffer_object " | |||
404 | "GL_EXT_framebuffer_object " | |||
405 | )){ | |||
406 | fprintf(stderr, "ERROR: Support for necessary OpenGL extensions missing."); | |||
407 | fflush(stderr); | |||
408 | return CUTFalse; | |||
409 | } | |||
410 | printf("OpenGL window created.\n"); | |||
411 | ||||
412 | printf("Creating GL texture...\n"); | |||
413 | glEnable(GL_TEXTURE_2D); | |||
414 | glGenTextures(1, &gl_Tex); | |||
415 | glBindTexture(GL_TEXTURE_2D, gl_Tex); | |||
416 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); | |||
417 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); | |||
418 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |||
419 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |||
420 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, imageW, imageH, 0, GL_RGBA, GL_UNSIGNED_BYTE, h_Src); | |||
421 | printf("Texture created.\n"); | |||
422 | ||||
423 | printf("Creating PBO...\n"); | |||
424 | glGenBuffers(1, &gl_PBO); | |||
425 | glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, gl_PBO); | |||
426 | glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, imageW * imageH * 4, h_Src, GL_STREAM_COPY); | |||
427 | //While a PBO is registered to CUDA, it can't be used | |||
428 | //as the destination for OpenGL drawing calls. | |||
429 | //But in our particular case OpenGL is only used | |||
430 | //to display the content of the PBO, specified by CUDA kernels, | |||
431 | //so we need to register/unregister it only once. | |||
432 | CUDA_SAFE_CALL( cudaGLRegisterBufferObject(gl_PBO) ); | |||
433 | printf("PBO created.\n"); | |||
434 | ||||
435 | printf("Starting GLUT main loop...\n"); | |||
436 | printf("\n"); | |||
437 | printf("Press [?] to print location and scale\n"); | |||
438 | printf("Press [q] to exit\n"); | |||
439 | printf("Press [r] to reset\n"); | |||
440 | printf("Press [a] or [A] to animate the colors\n"); | |||
441 | printf("Press [c] or [C] to change the colors\n"); | |||
442 | printf("Press [d] or [D] to increase/decrease the detail\n"); | |||
443 | printf("Left mouse button + drag = Scroll\n"); | |||
444 | printf("Right mouse button + drag = Zoom\n"); | |||
445 | printf("\n"); | |||
446 | glutDisplayFunc(displayFunc); | |||
447 | glutIdleFunc(idleFunc); | |||
448 | glutKeyboardFunc(keyboardFunc); | |||
449 | glutMouseFunc(clickFunc); | |||
450 | glutMotionFunc(motionFunc); | |||
451 | CUT_SAFE_CALL(cutCreateTimer(&hTimer)); | |||
452 | CUT_SAFE_CALL(cutStartTimer(hTimer)); | |||
453 | glutMainLoop(); | |||
454 | ||||
455 | CUT_EXIT(argc, argv); | |||
456 | } // main | 358 | } // main |