# HG changeset patch # User Radek Brich # Date 1195316436 -3600 # Node ID c73bc405ee7a04656a4b043f9c824f8f41851b8a # Parent 8f9cb0526c471aee8b7e5f7dd90dd93bb5e4d37b multi-threaded rendering via pthreads added README diff -r 8f9cb0526c47 -r c73bc405ee7a .bzrignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.bzrignore Sat Nov 17 17:20:36 2007 +0100 @@ -0,0 +1,1 @@ +demos/*.png diff -r 8f9cb0526c47 -r c73bc405ee7a Makefile --- a/Makefile Fri Nov 16 10:25:12 2007 +0100 +++ b/Makefile Sat Nov 17 17:20:36 2007 +0100 @@ -1,4 +1,4 @@ -CCFLAGS=-Wall -O3 -I./src +CCFLAGS=-Wall -O3 -I./src -DPTHREADS -pthread -fno-strict-aliasing LDFLAGS= ifeq ($(OS), Windows_NT) @@ -10,7 +10,7 @@ MODULENAME=raytracermodule.so endif -# optimisations +# optimizations #CCFLAGS+=-pipe -fomit-frame-pointer -ffast-math -msse3 diff -r 8f9cb0526c47 -r c73bc405ee7a README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README Sat Nov 17 17:20:36 2007 +0100 @@ -0,0 +1,11 @@ +================== + Pyrit Ray Tracer +================== + +Pthreads +-------- +Threads can be used to render rows of picture paralelly. Arbitrary number +of threads can be used, even numbers like 17 are acceptable. + +To completely disable this feature just remove "-DPTHREADS -pthreads" +from flags in makefile. diff -r 8f9cb0526c47 -r c73bc405ee7a TODO --- a/TODO Fri Nov 16 10:25:12 2007 +0100 +++ b/TODO Sat Nov 17 17:20:36 2007 +0100 @@ -1,4 +1,4 @@ - * pthreads (pro Windows http://sources.redhat.com/pthreads-win32/) + * pthreads for Windows: http://sources.redhat.com/pthreads-win32/ * kd-tree diff -r 8f9cb0526c47 -r c73bc405ee7a src/raytracer.cc --- a/src/raytracer.cc Fri Nov 16 10:25:12 2007 +0100 +++ b/src/raytracer.cc Sat Nov 17 17:20:36 2007 +0100 @@ -5,6 +5,10 @@ * Radek Brich, 2006 */ +#ifdef PTHREADS +#include +#endif + #include #include #include @@ -165,10 +169,47 @@ } } +static void *renderrow(void *data) +{ + RenderrowData *d = (RenderrowData*) data; + for (int x = 0; x < d->w; x++) { + // generate a ray from eye passing through this pixel +#if 1 + // no oversampling + Vector3 dir = Vector3(d->vx, d->vy, 0) - d->eye; + dir.normalize(); + Ray ray(d->eye, dir); + Colour c = d->rt->raytrace(ray, 0, NULL); +#else + // 5x oversampling + Vector3 dir = Vector3(); + Colour c = Colour(); + + for (int i = 0; i < 5; i++) + { + float osax[] = {0.0, -0.4, +0.4, +0.4, -0.4}; + float osay[] = {0.0, -0.4, -0.4, +0.4, +0.4}; + dir = Vector3(d->vx + osax[i] * d->dx, + d->vy + osay[i]*d->dy , 0) - d->eye; + dir.normalize(); + Ray ray(d->eye, dir); + c += d->rt->raytrace(ray, 0, NULL); + } + c = c * (1./5); +#endif + *(d->iter++) = c.r; + *d->iter++ = c.g; + *d->iter++ = c.b; + d->vx += d->dx; + } +#ifdef PTHREADS + pthread_exit((void *)d); +#endif +} + float *Raytracer::render(int w, int h) { - int x, y; - float *data, *iter; + float *data; data = (float *) malloc(w*h*3*sizeof(float)); if (!data) @@ -176,7 +217,8 @@ float startx = -1.0 * 4, starty = (float)h/w * 4; float dx = -2*startx/w, dy = -2*starty/h; - float vx, vy; + float vy; + RenderrowData *d; //srand(time(NULL)); @@ -184,43 +226,59 @@ Vector3 eye(0, 0, -5); // for each pixel... - iter = data; - for (vy = starty, y = 0; y < h; y++) { - vx = startx; - for (x = 0; x < w; x++) { - // generate a ray from eye passing through this pixel -#if 1 - // no oversampling - Vector3 dir = Vector3(vx, vy, 0) - eye; - dir.normalize(); - Ray ray(eye, dir); - Colour c = raytrace(ray, 0, NULL); -#else - // 5x oversampling - Vector3 dir = Vector3(); - Colour c = Colour(); + vy = starty; + +#ifdef PTHREADS + int num_threads = 20; + printf("* pthreads enabled, using %d threads\n", num_threads); + pthread_t threads[num_threads]; + for (int t = 0; t < num_threads; t++) + threads[t] = NULL; + int t = 0; +#endif - for (int i = 0; i < 5; i++) - { - float osax[] = {0.0, -0.4, +0.4, +0.4, -0.4}; - float osay[] = {0.0, -0.4, -0.4, +0.4, +0.4}; - dir = Vector3(vx + osax[i]*dx, - vy + osay[i]*dy , 0) - eye; - dir.normalize(); - Ray ray(eye, dir); - c += raytrace(ray, 0, NULL); - } - c = c * (1./5); + printf("* rendering row 0 ( 0% done)"); + for (int y = 0; y < h; y++) { + d = (RenderrowData*) malloc(sizeof(RenderrowData)); + d->rt = this; + d->w = w; + d->vx = startx; + d->vy = vy; + d->dx = dx; + d->dy = dy; + d->eye = eye; + d->iter = data + y*3*w; +#ifdef PTHREADS + /* create new thread and increase 't' */ + int rc = pthread_create(&threads[t++], NULL, renderrow, (void *)d); + if (rc) { + printf("\nERROR: return code from pthread_create() is %d\n", rc); + exit(1); + } + /* when 't' owerflows, reset it */ + if (t >= num_threads) + t = 0; + /* wait for next thread in fifo queue, so the descriptor can be reused; + this also limits number of running threads */ + if (threads[t] != NULL) + if (pthread_join(threads[t], (void**)&d) == 0) + free(d); +#else + renderrow((void *)d); + free(d); #endif - *iter++ = c.r; - *iter++ = c.g; - *iter++ = c.b; - vx += dx; - } vy += dy; - printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b%2d%% done (row %4d)", y*100/(h-1), y); + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b%4d (%2d%% done)", y, y*100/(h-1)); } printf("\n"); + +#ifdef PTHREADS + printf("* waiting for threads to finish\n"); + for (t = 0; t < num_threads; t++) + if (pthread_join(threads[t], (void**)&d) == 0) + free(d); +#endif + return data; } diff -r 8f9cb0526c47 -r c73bc405ee7a src/raytracer.h --- a/src/raytracer.h Fri Nov 16 10:25:12 2007 +0100 +++ b/src/raytracer.h Sat Nov 17 17:20:36 2007 +0100 @@ -24,6 +24,16 @@ AABB extends() { return AABB(); }; }; +class Raytracer; +struct RenderrowData { + Raytracer *rt; + int w; + float vx, vy, dx, dy; + Vector3 eye; + float *iter; +}; +static void *renderrow(void *data); + class Raytracer { ShapeList shapes; @@ -35,11 +45,11 @@ Vector3 SphereDistribute(int i, int n, float extent, Vector3 &normal); inline Shape *nearest_intersection(const Shape *origin_shape, const Ray &ray, float &nearest_distance); - Colour raytrace(Ray &ray, int depth, Shape *origin_shape); public: Raytracer(): shapes(), lights(), bg_colour(0.0, 0.0, 0.0), ao_samples(0) {}; ~Raytracer() {}; float *render(int w, int h); + Colour raytrace(Ray &ray, int depth, Shape *origin_shape); void addshape(Shape *shape); void addlight(Light *light);