--- /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
--- 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
--- /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.
--- 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
--- 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 <pthread.h>
+#endif
+
#include <stdio.h>
#include <malloc.h>
#include <float.h>
@@ -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;
}
--- 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);