summaryrefslogtreecommitdiffstats
path: root/libdimension
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@gmail.com>2009-06-29 22:12:36 +0000
committerTavian Barnes <tavianator@gmail.com>2009-06-29 22:12:36 +0000
commitbc178c264d12f73dc43357814056f571eb886102 (patch)
treef33d06b3310d26a65d632490bd438c3d9368bac4 /libdimension
parentabee3c9414ebf80c22b31a96c067788fbd13dbf7 (diff)
downloaddimension-bc178c264d12f73dc43357814056f571eb886102.tar.xz
Make raytracing multi-threaded again.
Diffstat (limited to 'libdimension')
-rw-r--r--libdimension/dimension/raytrace.h2
-rw-r--r--libdimension/raytrace.c129
2 files changed, 116 insertions, 15 deletions
diff --git a/libdimension/dimension/raytrace.h b/libdimension/dimension/raytrace.h
index b58a39b..2be79a8 100644
--- a/libdimension/dimension/raytrace.h
+++ b/libdimension/dimension/raytrace.h
@@ -25,7 +25,7 @@
#ifndef DIMENSION_RAYTRACE_H
#define DIMENSION_RAYTRACE_H
-void dmnsn_raytrace_scene(dmnsn_scene *scene);
+int dmnsn_raytrace_scene(dmnsn_scene *scene);
dmnsn_progress *dmnsn_raytrace_scene_async(dmnsn_scene *scene);
#endif /* DIMENSION_RAYTRACE_H */
diff --git a/libdimension/raytrace.c b/libdimension/raytrace.c
index aa3a445..d634747 100644
--- a/libdimension/raytrace.c
+++ b/libdimension/raytrace.c
@@ -26,17 +26,20 @@
typedef struct {
dmnsn_progress *progress;
dmnsn_scene *scene;
+
+ /* For multithreading */
+ unsigned int index, threads;
} dmnsn_raytrace_payload;
/* Thread callback */
static void *dmnsn_raytrace_scene_thread(void *ptr);
/* Raytrace a scene */
-void
+int
dmnsn_raytrace_scene(dmnsn_scene *scene)
{
dmnsn_progress *progress = dmnsn_raytrace_scene_async(scene);
- dmnsn_finish_progress(progress);
+ return dmnsn_finish_progress(progress);
}
/* Raytrace a scene in the background */
@@ -68,9 +71,8 @@ dmnsn_raytrace_scene_async(dmnsn_scene *scene)
return progress;
}
-/* Actual raytracing implementation */
-static void dmnsn_raytrace_scene_impl(dmnsn_progress *progress,
- dmnsn_scene *scene);
+/* Start the multi-threaded implementation */
+static int dmnsn_raytrace_scene_multithread(dmnsn_raytrace_payload *payload);
/* Thread callback */
static void *
@@ -79,17 +81,111 @@ dmnsn_raytrace_scene_thread(void *ptr)
dmnsn_raytrace_payload *payload = ptr;
int *retval = malloc(sizeof(int));
if (retval) {
- dmnsn_raytrace_scene_impl(payload->progress, payload->scene);
- *retval = 0;
+ *retval = dmnsn_raytrace_scene_multithread(payload);
}
dmnsn_done_progress(payload->progress);
free(payload);
return retval;
}
+/* Thread callback */
+static void *dmnsn_raytrace_scene_multithread_thread(void *ptr);
+
+/* Set up the multi-threaded engine */
+static int
+dmnsn_raytrace_scene_multithread(dmnsn_raytrace_payload *payload)
+{
+ int i, j, nthreads;
+ void *ptr;
+ int retval = 0;
+ dmnsn_raytrace_payload *payloads;
+ pthread_t *threads;
+
+ /* TODO: do this portably */
+ nthreads = sysconf(_SC_NPROCESSORS_ONLN);
+ if (nthreads < 1) {
+ nthreads = 1;
+ }
+ /* End non-portable section */
+
+ payloads = malloc(nthreads*sizeof(dmnsn_raytrace_payload));
+ if (!payloads) {
+ return 1;
+ }
+
+ threads = malloc(nthreads*sizeof(pthread_t));
+ if (!threads) {
+ free(payloads);
+ return 1;
+ }
+
+ /* Set up the progress object */
+ dmnsn_new_progress_element(payload->progress,
+ nthreads*payload->scene->canvas->y);
+
+ /* Create the threads */
+ for (i = 0; i < nthreads; ++i) {
+ payloads[i] = *payload;
+ payloads[i].index = i;
+ payloads[i].threads = nthreads;
+
+ if (pthread_create(&threads[i], NULL,
+ &dmnsn_raytrace_scene_multithread_thread, &payloads[i])
+ != 0) {
+ for (j = 0; j < i; ++j) {
+ if (pthread_join(threads[i], &ptr)) {
+ dmnsn_error(DMNSN_SEVERITY_MEDIUM,
+ "Couldn't join worker thread in failed raytrace engine"
+ " initialization.");
+ } else {
+ free(ptr);
+ }
+ }
+
+ free(payloads);
+ return 1;
+ }
+ }
+
+ for (i = 0; i < nthreads; ++i) {
+ if (pthread_join(threads[i], &ptr)) {
+ dmnsn_error(DMNSN_SEVERITY_MEDIUM,
+ "Couldn't join worker thread in raytrace engine.");
+ } else {
+ if (retval == 0) {
+ retval = *(int *)ptr;
+ }
+ free(ptr);
+ }
+ }
+
+ free(threads);
+ free(payloads);
+ return retval;
+}
+
+/* Actual raytracing implementation */
+static int dmnsn_raytrace_scene_impl(dmnsn_progress *progress,
+ dmnsn_scene *scene,
+ unsigned int index, unsigned int threads);
+
+/* Multi-threading thread callback */
+static void *
+dmnsn_raytrace_scene_multithread_thread(void *ptr)
+{
+ dmnsn_raytrace_payload *payload = ptr;
+ int *retval = malloc(sizeof(int));
+ if (retval) {
+ *retval = dmnsn_raytrace_scene_impl(payload->progress, payload->scene,
+ payload->index, payload->threads);
+ }
+ return retval;
+}
+
/* Actually raytrace a scene */
-static void
-dmnsn_raytrace_scene_impl(dmnsn_progress *progress, dmnsn_scene *scene)
+static int
+dmnsn_raytrace_scene_impl(dmnsn_progress *progress, dmnsn_scene *scene,
+ unsigned int index, unsigned int threads)
{
unsigned int i, j, k, l;
unsigned int width, height;
@@ -103,14 +199,17 @@ dmnsn_raytrace_scene_impl(dmnsn_progress *progress, dmnsn_scene *scene)
width = scene->canvas->x;
height = scene->canvas->y;
- dmnsn_new_progress_element(progress, height);
-
/* Iterate through each pixel */
for (j = 0; j < height; ++j) {
for (i = 0; i < width; ++i) {
+ /* Only do the work which we were assigned */
+ if ((j*width + i)%threads != index) {
+ continue;
+ }
+
/* Set the pixel to the background color */
color = scene->background;
- t = 0.0;
+ t = -1.0;
/* Get the ray corresponding to the (i,j)th pixel */
ray = (*scene->camera->ray_fn)(scene->camera, scene->canvas, i, j);
@@ -126,13 +225,13 @@ dmnsn_raytrace_scene_impl(dmnsn_progress *progress, dmnsn_scene *scene)
/* Find the closest intersection */
for (l = 0; l < dmnsn_array_size(intersections); ++l) {
dmnsn_array_get(intersections, l, &t_temp);
- if (t_temp < t || t == 0.0) t = t_temp;
+ if ((t_temp < t && t_temp >= 0.0) || t < 0.0) t = t_temp;
}
dmnsn_delete_array(intersections);
}
/* Shade according to distance from camera */
- if (t != 0.0) {
+ if (t >= 0.0) {
sRGB.R = 1.0 - (t - 2.25)/2.25;
sRGB.G = sRGB.R;
sRGB.B = sRGB.R;
@@ -144,4 +243,6 @@ dmnsn_raytrace_scene_impl(dmnsn_progress *progress, dmnsn_scene *scene)
dmnsn_increment_progress(progress);
}
+
+ return 0;
}