|
|
|
#include <math.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/sysinfo.h>
|
|
|
|
#include "images/src/images.h"
|
|
|
|
#include "src/scene.h"
|
|
|
|
#include "src/camera.h"
|
|
|
|
#include "src/point.h"
|
|
|
|
|
|
|
|
|
|
|
|
typedef int bool;
|
|
|
|
#define true 1
|
|
|
|
#define false 0
|
|
|
|
|
|
|
|
#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 = self->args[0];
|
|
|
|
double power = self->args[1];
|
|
|
|
|
|
|
|
struct point z = pt;
|
|
|
|
float dr = 1.0;
|
|
|
|
float r = 0.0;
|
|
|
|
for (int i = 0; i < iters ; i++) {
|
|
|
|
r = pt_length(z);
|
|
|
|
|
|
|
|
if (r>2) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// convert to polar coordinates
|
|
|
|
float theta = acos(z.z/r);
|
|
|
|
float 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);
|
|
|
|
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, float pow, int threads, const char path[], bool save) {
|
|
|
|
float cam_position = 1.15;
|
|
|
|
int steps = 2000;
|
|
|
|
int iters = 1000;
|
|
|
|
float 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_shared(*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 argc, char *argv[])
|
|
|
|
{
|
|
|
|
int threads = get_nprocs();
|
|
|
|
struct timer bench;
|
|
|
|
int size = 1080;
|
|
|
|
|
|
|
|
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", true);
|
|
|
|
timer_end(&bench);
|
|
|
|
timer_print(bench);
|
|
|
|
|
|
|
|
sleep(2);
|
|
|
|
|
|
|
|
bench.name = "1080px render without saving";
|
|
|
|
timer_start(&bench);
|
|
|
|
run_bench(1080, 3.0, threads, "", false);
|
|
|
|
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", true);
|
|
|
|
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", true);
|
|
|
|
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, "", false);
|
|
|
|
timer_end(&bench);
|
|
|
|
timer_print(bench);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|