diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..79b3c94 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/raymarcher.iml b/.idea/raymarcher.iml deleted file mode 100644 index bc2cd87..0000000 --- a/.idea/raymarcher.iml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/Makefile b/Makefile index 273fe2f..311d849 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ -OPTIMIZATION=-O3 +OPTIMIZATION=-O3 -flto CC=gcc -CFLAGS=-Isrc/ -lm -Wall -Wextra -pedantic-errors $(OPTIMIZATION) +CFLAGS=-Isrc/ -lm -lpthread -Wall -Wextra -pedantic-errors $(OPTIMIZATION) .PHONY: directories @@ -21,7 +21,6 @@ obj/camera.o: src/camera.c src/camera.h obj/images.o: images/src/images.c images/src/images.h $(CC) $(CFLAGS) -c -o $@ images/src/images.c - march: obj/camera.o obj/scene.o obj/point.o obj/images.o $(CC) $(CFLAGS) -o out/march $^ marcher.c diff --git a/bench.c b/bench.c index 20bc774..138e588 100644 --- a/bench.c +++ b/bench.c @@ -11,10 +11,6 @@ #include "src/point.h" -typedef int bool; -#define true 1 -#define false 0 - #define BENCH_VERSION "1.0" @@ -28,12 +24,12 @@ typedef int bool; */ double mandelbulb_dist(struct point pt, struct scene_object *self) { - int iters = self->args[0]; + int iters = (int) self->args[0]; double power = self->args[1]; struct point z = pt; - float dr = 1.0; - float r = 0.0; + double dr = 1.0; + double r = 0.0; for (int i = 0; i < iters ; i++) { r = pt_length(z); @@ -42,12 +38,12 @@ double mandelbulb_dist(struct point pt, struct scene_object *self) { } // convert to polar coordinates - float theta = acos(z.z/r); - float phi = atan2(z.y,z.x); + double theta = acos(z.z/r); + double phi = atan2(z.y,z.x); dr = pow(r, power-1.0)*power*dr + 1.0; // scale and rotate the point - float zr = pow(r, power); + double zr = pow(r, power); theta = theta*power; phi = phi*power; @@ -81,11 +77,11 @@ struct scene_object mandelbulb_new(struct point location, int iters, double powe return so; } -int run_bench(int size, float pow, int threads, const char path[], bool save) { - float cam_position = 1.15; +int run_bench(int size, double pow, int threads, const char path[], int save) { + double cam_position = 1.15; int steps = 2000; int iters = 1000; - float threshold = 0.0001; + double threshold = 0.0001; struct camera cam; cam.fov = 90; @@ -107,7 +103,7 @@ int run_bench(int size, float pow, int threads, const char path[], bool save) { image_save_bmp(*img, path); } - image_destroy_shared(*img); + image_destroy(*img); scene_destroy(scene); return 0; @@ -134,11 +130,10 @@ void timer_print(struct timer t) { printf("\nBenchmark %s took %ldms (%.2fs)\n", t.name, time, time / 1000.0f); } -int main(int argc, char *argv[]) +int main() { - int threads = get_nprocs(); + int threads = get_nprocs() / 2; struct timer bench; - int size = 1080; printf("Mandelbulb Benchmark v%s\n\nDetected %d threads...\n", BENCH_VERSION, threads); @@ -146,7 +141,7 @@ int main(int argc, char *argv[]) bench.name = "1080px render with saving"; timer_start(&bench); - run_bench(1080, 3.0, threads, "bench-pow3-1080p.bmp", true); + run_bench(1080, 3.0, threads, "bench-pow3-1080p.bmp", 1); timer_end(&bench); timer_print(bench); @@ -154,7 +149,7 @@ int main(int argc, char *argv[]) bench.name = "1080px render without saving"; timer_start(&bench); - run_bench(1080, 3.0, threads, "", false); + run_bench(1080, 3.0, threads, "", 0); timer_end(&bench); timer_print(bench); @@ -162,7 +157,7 @@ int main(int argc, char *argv[]) bench.name = "10 megapixel render with saving"; timer_start(&bench); - run_bench(3162, 3.0, threads, "bench-pow3-10mpx.bmp", true); + run_bench(3162, 3.0, threads, "bench-pow3-10mpx.bmp", 1); timer_end(&bench); timer_print(bench); @@ -170,7 +165,7 @@ int main(int argc, char *argv[]) bench.name = "40 megapixel render with saving"; timer_start(&bench); - run_bench(6324, 3.0, threads, "bench-pow3-40mpx.bmp", true); + run_bench(6324, 3.0, threads, "bench-pow3-40mpx.bmp", 1); timer_end(&bench); timer_print(bench); @@ -178,7 +173,7 @@ int main(int argc, char *argv[]) bench.name = "1080px render single threaded without saving"; timer_start(&bench); - run_bench(1080, 3.0, 1, "", false); + run_bench(1080, 3.0, 1, "", 0); timer_end(&bench); timer_print(bench); diff --git a/marcher.c b/marcher.c index c32562b..4a786ae 100644 --- a/marcher.c +++ b/marcher.c @@ -160,7 +160,7 @@ int main(int argc, char* argv[]) { image_save_bmp(*img, path); - image_destroy_shared(*img); + image_destroy(*img); scene_destroy(scene); return 0; diff --git a/src/camera.c b/src/camera.c index 54a493b..7bcfe6e 100644 --- a/src/camera.c +++ b/src/camera.c @@ -1,11 +1,25 @@ -#include #include #include #include #include +#include #include "point.h" #include "camera.h" +struct thread_args { + struct point start; + int thread_id; + int thread_count; + int height; + int width; + struct point move_up; + struct point move_right; + void (*callback)(struct point, int, int); +}; + +static void * camera_iterate_rays_const_dist_thread(void* args); + + struct camera camera_new(struct point direction, unsigned int fov) { struct camera camera; camera.location = (struct point) { @@ -26,10 +40,9 @@ void camera_set_looking_at(struct camera *cam, struct point origin, struct point cam->direction = pt_normalize(pt_sub(thing, origin)); } - -void camera_iterate_rays_const_dist(struct camera camera, int width, int height, int threads, void (*callback)(struct point, int, int)) { - // negative threads => single threaded. - if (threads < 0) threads = 0; +void camera_iterate_rays_const_dist(struct camera camera, int width, int height, int thread_count, void (*callback)(struct point, int, int)) { + // negative thread_count => single threaded. + if (thread_count < 0) thread_count = 0; struct point span_z, span_xy; @@ -52,46 +65,88 @@ void camera_iterate_rays_const_dist(struct camera camera, int width, int height, starting_point = pt_add(starting_point, pt_mult(move_right, - width / (double) 2)); starting_point = pt_add(starting_point, pt_mult(move_up, - height / (double) 2)); - // initialize threads - int thread_id = 0; - for (int i = 0; i < threads - 1; i++) { - if (fork() == 0) { - thread_id = i + 1; - break; - } + if (thread_count < 2) { + //TODO implement single threaded work here + struct thread_args arg = { + .start = starting_point, + .thread_id = 0, + .thread_count = 1, + .height = height, + .width = width, + .move_up = move_up, + .move_right = move_right, + .callback = callback + }; + + camera_iterate_rays_const_dist_thread(&arg); + + return; + } + + // initialize thread_count + pthread_t * threads = malloc(sizeof(pthread_t) * thread_count); + struct thread_args* args = malloc(sizeof(struct thread_args) * thread_count); + + for (int i = 0; i < thread_count; i++) { + args[i] = (struct thread_args) { + .start = starting_point, + .thread_id = i, + .thread_count = thread_count, + .height = height, + .width = width, + .move_up = move_up, + .move_right = move_right, + .callback = callback + }; + + pthread_create(threads + i, NULL, camera_iterate_rays_const_dist_thread, (void*) (args + i)); + } + + //struct thread_args { + // struct point start; + // int thread_id; + // int thread_count; + // int height; + // int width; + // struct point move_up; + // struct point move_right; + // void (*callback)(struct point, int, int); + //}; + + + for (int i = 0; i < thread_count; i++) { + pthread_join(threads[i], NULL); } +} + +static void * camera_iterate_rays_const_dist_thread(void* arg_ptr) { + // explicit cast to make gcc happy + struct thread_args* args = (struct thread_args*) arg_ptr; // this point is moved for every pixel - struct point curr_pt = starting_point; + struct point curr_pt = args->start; // (0,0) screenspace is bottom left corner - for (int y = 0; y < height; y++) { + for (int y = 0; y < args->height; y++) { // move one row up (this has to be done in every thread!) - starting_point = pt_add(starting_point, move_up); + args->start = pt_add(args->start, args->move_up); // only render the lines this thread is responsible for - if (y % threads != thread_id) continue; - + if (y % args->thread_count != args->thread_id) continue; + // display progress in percent - if (height > 200 && y % (height / 100) == 0 && y != 0) { - printf("\r%02i%%", (y * 100) / height); + if (args->height > 200 && y % (args->height / 100) == 0 && y != 0) { + printf("\r%02i%%", (y * 100) / args->height); fflush(stdout); } // actually iterate this line - curr_pt = starting_point; - for (int x = 0; x < width; x++) { - callback(curr_pt, x, y); - curr_pt = pt_add(curr_pt, move_right); // move pt right to next pt + curr_pt = args->start; + for (int x = 0; x < args->width; x++) { + args->callback(curr_pt, x, y); + curr_pt = pt_add(curr_pt, args->move_right); // move pt right to next pt } } - if (thread_id != 0) { - exit(0); - } - - int status; - for (int i = 0; i < threads - 1; i++) { - while(wait(&status) > 0) {} - } -} \ No newline at end of file + return NULL; +} diff --git a/src/camera.h b/src/camera.h index b766c3f..2fb6318 100644 --- a/src/camera.h +++ b/src/camera.h @@ -8,4 +8,4 @@ struct camera { struct camera camera_new(struct point direction, unsigned int fov); void camera_set_looking_at(struct camera *cam, struct point origin, struct point thing); -void camera_iterate_rays_const_dist(struct camera camera, int width, int height, int threads, void (*callback)(struct point, int, int)); \ No newline at end of file +void camera_iterate_rays_const_dist(struct camera camera, int width, int height, int thread_count, void (*callback)(struct point, int, int)); \ No newline at end of file diff --git a/src/point.c b/src/point.c index 219a70c..bb928f4 100644 --- a/src/point.c +++ b/src/point.c @@ -2,17 +2,10 @@ #include #include "point.h" -// scale vector to length -struct point pt_scale(struct point pt, double length) { - double f = length / pt_length(pt); - return (struct point) { - .x = pt.x * f, - .y = pt.y * f, - .z = pt.z * f - }; -} +// get the length of vector +inline double pt_length_inline (struct point pt) __attribute__((always_inline)); -struct point pt_mult(struct point pt, double scalar) { +inline struct point pt_mult(struct point pt, double scalar) { return (struct point) { .x = pt.x * scalar, .y = pt.y * scalar, @@ -21,7 +14,7 @@ struct point pt_mult(struct point pt, double scalar) { } // return internal angle between a and b -double pt_angle(struct point a, struct point b) { +inline double pt_angle(struct point a, struct point b) { return acos(pt_dot( pt_normalize(a), pt_normalize(b) @@ -29,12 +22,16 @@ double pt_angle(struct point a, struct point b) { } // get the length of vector -double pt_length(struct point pt) { +inline double pt_length_inline (struct point pt) { return sqrt((pt.x * pt.x) + (pt.y * pt.y) + (pt.z * pt.z)); } +double pt_length(struct point pt) { + return pt_length_inline(pt); +} + // add the vector add to the vector pt -struct point pt_add(struct point pt, struct point add) { +inline struct point pt_add(struct point pt, struct point add) { return (struct point) { .x = pt.x + add.x, .y = pt.y + add.y, @@ -43,7 +40,7 @@ struct point pt_add(struct point pt, struct point add) { } // add the vector add to the vector pt -struct point pt_sub(struct point pt, struct point sub) { +inline struct point pt_sub(struct point pt, struct point sub) { return (struct point) { .x = pt.x - sub.x, .y = pt.y - sub.y, @@ -51,22 +48,38 @@ struct point pt_sub(struct point pt, struct point sub) { }; } -double pt_dist(struct point p1, struct point p2) { - return pt_length(pt_sub(p1, p2)); +inline double pt_dist(struct point p1, struct point p2) { + return pt_length_inline(pt_sub(p1, p2)); } // normalize a vector -struct point pt_normalize(struct point pt) { - return pt_scale(pt, 1); +inline struct point pt_normalize(struct point pt) { + double length = pt_length(pt); + + return (struct point) { + .x = pt.x / length, + .y = pt.y / length, + .z = pt.z / length + }; +} + +// scale vector to length +inline struct point pt_scale(struct point pt, double length) { + double f = length / pt_length_inline(pt); + return (struct point) { + .x = pt.x * f, + .y = pt.y * f, + .z = pt.z * f + }; } // dot product of two vectors -double pt_dot(struct point a, struct point b) { +inline double pt_dot(struct point a, struct point b) { return a.x*b.x + a.y*b.y + a.z*b.z; } // cross product of two vectors -struct point pt_cross(struct point a, struct point b) { +inline struct point pt_cross(struct point a, struct point b) { return (struct point) { .x = a.y*b.z - a.z*b.y, .y = a.z*b.x - a.x*b.z, @@ -74,29 +87,29 @@ struct point pt_cross(struct point a, struct point b) { }; } -void pt_print(struct point pt) { +inline void pt_print(struct point pt) { printf("(%f, %f, %f)\n", pt.x, pt.y, pt.z); } -void pt_print_n(const char* name, struct point pt) { +inline void pt_print_n(const char* name, struct point pt) { printf("%s: (%f, %f, %f)\n", name, pt.x, pt.y, pt.z); } // find two vectors that span the orthogonal plane, where // span_xy is a vector lying on the xy-plane (and pointing left) // and span_z is orthogonal to span_xy pointing "upwards" -void pt_orthogonal_plane(struct point pt, struct point *span_z, struct point *span_xy) { +inline void pt_orthogonal_plane(struct point pt, struct point *span_z, struct point *span_xy) { pt = pt_normalize(pt); // get the vector lying on the xy axis - // this is done by - *span_xy = pt_normalize(pt_cross((struct point){.x = 0, .y = 0, .z = 1}, pt)); // points to the "left" (of the viewing direction) + // this is done by + *span_xy = pt_normalize(pt_cross(PT_NEW(0,0,1), pt)); // points to the "left" (of the viewing direction) // now use this, to find the vector *span_z = pt_normalize(pt_cross(pt, *span_xy)); } -struct point pt_mod(struct point pt, double mod) { +inline struct point pt_mod(struct point pt, double mod) { return (struct point) { .x = fabs(fmod(pt.x, mod)), .y = fabs(fmod(pt.y, mod)), diff --git a/src/point.h b/src/point.h index 69cb378..62bde2d 100644 --- a/src/point.h +++ b/src/point.h @@ -8,6 +8,7 @@ struct point { }; #define PT_ZERO ((struct point) {.x=0, .y=0, .z=0}) +#define PT_NEW(x,y,z) ((struct point){(x), (y), (z)}) struct point pt_scale(struct point pt, double length); struct point pt_normalize(struct point pt); diff --git a/src/scene.c b/src/scene.c index bad4222..b62fab6 100644 --- a/src/scene.c +++ b/src/scene.c @@ -51,7 +51,7 @@ Image* render_scene(struct scene *scene, struct camera *camera, unsigned int thr current_camera= camera; // initialize shared pixel buffer - image_new_shared(scene->width, scene->height, current_image); + image_new(scene->width, scene->height, current_image); // iterate over the rays camera_iterate_rays_const_dist(*camera, scene->width, scene->height, threads, camera_iter_callback);