#include #include #include #include #include #include #include #include "images/src/images.h" #include "src/scene.h" #include "src/camera.h" #include "src/point.h" #define BENCH_VERSION "1.0" /* Mandelbulb scene object Currently cannot be set at a specific location, always resides at origin (0,0,0) Color function is just a flat shader, detail is displayed with ambient occlusion */ double mandelbulb_dist(struct point pt, struct scene_object *self) { int iters = (int) self->args[0]; double power = self->args[1]; struct point z = pt; double dr = 1.0; double r = 0.0; for (int i = 0; i < iters ; i++) { r = pt_length(z); if (r>2) { break; } // convert to polar coordinates 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 double zr = pow(r, power); theta = theta*power; phi = phi*power; // convert back to cartesian coordinates z = (struct point) { .x = sin(theta)*cos(phi) * zr + pt.x, .y = sin(phi)*sin(theta) * zr + pt.y, .z = cos(theta) * zr + pt.z }; } return 0.5*log(r)*r/dr; } Color mandelbulb_color(struct point hit, struct point direction, struct scene_object *self) { return self->color; } // constructs the scene object struct scene_object mandelbulb_new(struct point location, int iters, double power) { struct scene_object so; so.location = location; so.args = malloc(sizeof(double) * 3); so.args[0] = iters; // iterations so.args[1] = power; // power so.args[2] = -1; // reserved for color calculations so.distance = mandelbulb_dist; so.get_color = mandelbulb_color; so.color = color_new(255,255,255); return so; } 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; double threshold = 0.0001; struct camera cam; cam.fov = 90; camera_set_looking_at(&cam, (struct point){.x = cam_position, .y = cam_position, .z = cam_position}, PT_ZERO); // create basic scene with up to 10 objects struct scene scene = scene_new(size, size, 1); scene.perf_opts.max_steps = steps; scene.perf_opts.threshold = threshold; scene.perf_opts.speed_cutoff = 10; scene.background = color_new(0,0,0); scene_add_obj(&scene, mandelbulb_new(PT_ZERO, iters, pow)); Image *img = render_scene(&scene, &cam, threads); if (save) { image_save_bmp(*img, path); } image_destroy(*img); scene_destroy(scene); return 0; } struct timer { struct timeval start; struct timeval end; char *name; }; void timer_start(struct timer *t) { printf("\nStarting bench %s\n", t->name); gettimeofday(&t->start, NULL); } void timer_end(struct timer *t) { gettimeofday(&t->end, NULL); } void timer_print(struct timer t) { long time, secs, usecs; secs = t.end.tv_sec - t.start.tv_sec; usecs = t.end.tv_usec - t.start.tv_usec; time = ((secs) * 1000 + usecs/1000.0) + 0.5; printf("\nBenchmark %s took %ldms (%.2fs)\n", t.name, time, time / 1000.0f); } int main() { int threads = get_nprocs() / 2; struct timer bench; printf("Mandelbulb Benchmark v%s\n\nDetected %d threads...\n", BENCH_VERSION, threads); sleep(2); bench.name = "1080px render with saving"; timer_start(&bench); run_bench(1080, 3.0, threads, "bench-pow3-1080p.bmp", 1); timer_end(&bench); timer_print(bench); sleep(2); bench.name = "1080px render without saving"; timer_start(&bench); run_bench(1080, 3.0, threads, "", 0); timer_end(&bench); timer_print(bench); sleep(2); bench.name = "10 megapixel render with saving"; timer_start(&bench); run_bench(3162, 3.0, threads, "bench-pow3-10mpx.bmp", 1); timer_end(&bench); timer_print(bench); sleep(2); bench.name = "40 megapixel render with saving"; timer_start(&bench); run_bench(6324, 3.0, threads, "bench-pow3-40mpx.bmp", 1); timer_end(&bench); timer_print(bench); sleep(2); bench.name = "1080px render single threaded without saving"; timer_start(&bench); run_bench(1080, 3.0, 1, "", 0); timer_end(&bench); timer_print(bench); return 0; }