| 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 |