Add --threads option
This commit is contained in:
+82
-50
@@ -482,9 +482,21 @@ bool intersect_object(Ray r, Object o, float *t, Vector3 *normal)
|
||||
return false;
|
||||
}
|
||||
|
||||
_Thread_local uint64_t wyhash64_x = 0;
|
||||
|
||||
uint64_t wyhash64(void) {
|
||||
wyhash64_x += 0x60bee2bee120fc15;
|
||||
__uint128_t tmp;
|
||||
tmp = (__uint128_t) wyhash64_x * 0xa3b195354a39b70d;
|
||||
uint64_t m1 = (tmp >> 64) ^ tmp;
|
||||
tmp = (__uint128_t)m1 * 0x1b03738712fad5c9;
|
||||
uint64_t m2 = (tmp >> 64) ^ tmp;
|
||||
return m2;
|
||||
}
|
||||
|
||||
float random_float(void)
|
||||
{
|
||||
return (float) rand() / RAND_MAX;
|
||||
return (float) wyhash64() / UINT64_MAX;
|
||||
}
|
||||
|
||||
Vector3 random_vector(void)
|
||||
@@ -597,9 +609,14 @@ Vector3 pixel(float x, float y, float aspect_ratio)
|
||||
Ray in_ray = ray_through_screen_at(x, y, aspect_ratio);
|
||||
assert(!isnanv(in_ray.direction));
|
||||
|
||||
//Vector3 sky_color = {0.6, 0.7, 0.9};
|
||||
//Vector3 sky_color = {0, 0, 0};
|
||||
//Vector3 sky_color = {1, 1, 1};
|
||||
// Choose a light source
|
||||
int light_index = -1;
|
||||
for (int i = 0; i < num_objects; i++) {
|
||||
if (objects[i].material.emission_power > 0) {
|
||||
light_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 contrib = {1, 1, 1};
|
||||
Vector3 result = {0, 0, 0};
|
||||
@@ -609,43 +626,41 @@ Vector3 pixel(float x, float y, float aspect_ratio)
|
||||
|
||||
HitInfo hit = trace_ray(in_ray);
|
||||
if (hit.object == -1) {
|
||||
//Vector3 sky_color = {0.6, 0.7, 0.9};
|
||||
//Vector3 sky_color = {0, 0, 0};
|
||||
//Vector3 sky_color = {1, 1, 1};
|
||||
Vector3 sky_color = sample_cubemap(&skybox, normalize(in_ray.direction));
|
||||
result = combine(result, mulv(sky_color, contrib), 1, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
Vector3 sampled_light_color = {0, 0, 0};
|
||||
for (int j = 0; j < num_objects; j++) {
|
||||
if (objects[j].material.emission_power == 0 || j == hit.object)
|
||||
continue;
|
||||
Vector3 dir_to_light_source = combine(origin_of(objects[j]), hit.point, 1, -1);
|
||||
int samples = 5;
|
||||
if (light_index != -1) {
|
||||
Vector3 dir_to_light_source = combine(origin_of(objects[light_index]), hit.point, 1, -1);
|
||||
int max_samples = 3;
|
||||
int num_samples = 0;
|
||||
float spread = 0.5;
|
||||
for (int k = 0; k < samples; k++) {
|
||||
for (int k = 0; k < max_samples; k++) {
|
||||
// Add some noise based on roughness
|
||||
Vector3 rand_dir = random_direction();
|
||||
if (dotv(rand_dir, hit.normal) < 0)
|
||||
rand_dir = scale(rand_dir, -1);
|
||||
Vector3 sample_dir = normalize(combine(rand_dir, dir_to_light_source, spread, 1));
|
||||
Ray sample_ray = { combine(hit.point, sample_dir, 1, 0.001), sample_dir };
|
||||
HitInfo hit2 = trace_ray(sample_ray);
|
||||
if (hit2.object != -1)
|
||||
sampled_light_color = combine(sampled_light_color, objects[hit2.object].material.emission_color, 1, objects[hit2.object].material.emission_power);
|
||||
if (dotv(rand_dir, hit.normal) > 0) {
|
||||
Vector3 sample_dir = normalize(combine(rand_dir, dir_to_light_source, spread, 1));
|
||||
Ray sample_ray = { combine(hit.point, sample_dir, 1, 0.001), sample_dir };
|
||||
HitInfo hit2 = trace_ray(sample_ray);
|
||||
if (hit2.object != -1)
|
||||
sampled_light_color = combine(sampled_light_color, objects[hit2.object].material.emission_color, 1, objects[hit2.object].material.emission_power);
|
||||
num_samples++;
|
||||
}
|
||||
}
|
||||
sampled_light_color = scale(sampled_light_color, 1.0f / samples);
|
||||
break;
|
||||
if (num_samples > 0)
|
||||
sampled_light_color = scale(sampled_light_color, 1.0f / num_samples);
|
||||
}
|
||||
|
||||
Material material = objects[hit.object].material;
|
||||
|
||||
Vector3 v = scale(in_ray.direction, -1);
|
||||
//Vector3 l = out_dir;
|
||||
Vector3 n = hit.normal;
|
||||
//Vector3 h = normalize(combine(v, l, 1, 1));
|
||||
//float NoH = clamp(dotv(n, h), 0, 1);
|
||||
//float LoH = clamp(dotv(l, h), 0, 1);
|
||||
float NoV = clamp(dotv(n, v), 0, 1);
|
||||
//float NoL = clamp(dotv(n, l), 0, 1);
|
||||
|
||||
Vector3 f0_dielectric = vec_from_scalar(0.16 * material.reflectance * material.reflectance);
|
||||
Vector3 f0_metal = material.albedo;
|
||||
@@ -686,7 +701,9 @@ Vector3 pixel(float x, float y, float aspect_ratio)
|
||||
return result;
|
||||
}
|
||||
|
||||
#define NUM_COLUMNS 16
|
||||
int num_columns = 1;
|
||||
int init_scale = 2;
|
||||
#define MAX_COLUMNS 32
|
||||
|
||||
bool stop_workers = false;
|
||||
_Atomic uint32_t accum_generation = 0;
|
||||
@@ -695,9 +712,9 @@ Vector3 *frame = NULL;
|
||||
int frame_w = 0;
|
||||
int frame_h = 0;
|
||||
unsigned int frame_texture;
|
||||
float accum_counts[NUM_COLUMNS] = {0};
|
||||
float accum_counts[MAX_COLUMNS] = {0};
|
||||
os_mutex_t frame_mutex;
|
||||
os_condvar_t accum_conds[NUM_COLUMNS];
|
||||
os_condvar_t accum_conds[MAX_COLUMNS];
|
||||
|
||||
float render_to_column(Vector3 *data, int scale_, int column_w, int column_i, int frame_w, int frame_h, uint64_t cached_generation)
|
||||
{
|
||||
@@ -749,7 +766,6 @@ os_threadreturn worker(void *arg)
|
||||
int cached_frame_h;
|
||||
uint64_t cached_generation;
|
||||
|
||||
int init_scale = 16;
|
||||
int scale_ = init_scale;
|
||||
|
||||
os_mutex_lock(&frame_mutex);
|
||||
@@ -758,7 +774,7 @@ os_threadreturn worker(void *arg)
|
||||
|
||||
if (column_data == NULL || cached_generation != atomic_load(&accum_generation))
|
||||
resize = true;
|
||||
column_w = frame_w / NUM_COLUMNS;
|
||||
column_w = frame_w / num_columns;
|
||||
cached_frame_w = frame_w;
|
||||
cached_frame_h = frame_h;
|
||||
cached_generation = atomic_load(&accum_generation);
|
||||
@@ -801,7 +817,7 @@ os_threadreturn worker(void *arg)
|
||||
void invalidate_accumulation(void)
|
||||
{
|
||||
os_mutex_lock(&frame_mutex);
|
||||
for (int i = 0; i < NUM_COLUMNS; i++)
|
||||
for (int i = 0; i < num_columns; i++)
|
||||
accum_counts[i] = 0;
|
||||
atomic_fetch_add(&accum_generation, 1);
|
||||
memset(accum, 0, sizeof(Vector3) * frame_w * frame_h);
|
||||
@@ -827,7 +843,7 @@ void update_frame_texture(void)
|
||||
accum = malloc(sizeof(Vector3) * frame_w * frame_h);
|
||||
if (!accum) { printf("OUT OF MEMORY\n"); abort(); }
|
||||
|
||||
for (int i = 0; i < NUM_COLUMNS; i++)
|
||||
for (int i = 0; i < num_columns; i++)
|
||||
accum_counts[i] = 0;
|
||||
|
||||
memset(accum, 0, sizeof(Vector3) * frame_w * frame_h);
|
||||
@@ -836,9 +852,9 @@ void update_frame_texture(void)
|
||||
atomic_fetch_add(&accum_generation, 1);
|
||||
}
|
||||
|
||||
int column_w = frame_w / NUM_COLUMNS;
|
||||
int column_w = frame_w / num_columns;
|
||||
|
||||
for (int i = 0; i < NUM_COLUMNS; i++) {
|
||||
for (int i = 0; i < num_columns; i++) {
|
||||
while (accum_counts[i] < 0.0001)
|
||||
os_condvar_wait(&accum_conds[i], &frame_mutex, -1);
|
||||
}
|
||||
@@ -862,8 +878,33 @@ void update_frame_texture(void)
|
||||
os_mutex_unlock(&frame_mutex);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
num_columns = -1;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "--threads")) {
|
||||
i++;
|
||||
if (i == argc) {
|
||||
fprintf(stderr, "Error: --threads option is missing the count\n");
|
||||
return -1;
|
||||
}
|
||||
num_columns = atoi(argv[i]);
|
||||
if (num_columns == 0) {
|
||||
fprintf(stderr, "Error: Invalid count for --threads\n");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Warning: Ignoring option %s\n", argv[i]);
|
||||
}
|
||||
}
|
||||
if (num_columns < 0) {
|
||||
fprintf(stderr, "Error: Missing --threads <N> option\n");
|
||||
return -1;
|
||||
}
|
||||
if (num_columns > MAX_COLUMNS)
|
||||
num_columns = MAX_COLUMNS;
|
||||
init_scale = 8;
|
||||
|
||||
#if 0
|
||||
|
||||
add_object(sphere(
|
||||
@@ -1147,12 +1188,12 @@ int main(void)
|
||||
|
||||
os_mutex_create(&frame_mutex);
|
||||
|
||||
os_thread workers[16];
|
||||
os_thread workers[MAX_COLUMNS];
|
||||
|
||||
for (int i = 0; i < NUM_COLUMNS; i++)
|
||||
for (int i = 0; i < num_columns; i++)
|
||||
os_condvar_create(&accum_conds[i]);
|
||||
|
||||
for (int i = 0; i < NUM_COLUMNS; i++)
|
||||
for (int i = 0; i < num_columns; i++)
|
||||
os_thread_create(&workers[i], (void*) i, worker);
|
||||
|
||||
unsigned int screen_program = compile_shader("assets/screen.vs", "assets/screen.fs");
|
||||
@@ -1191,15 +1232,13 @@ int main(void)
|
||||
glBindTexture(GL_TEXTURE_2D, frame_texture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
while (!glfwWindowShouldClose(window)) {
|
||||
|
||||
double startTime = glfwGetTime();
|
||||
|
||||
glfwGetWindowSize(window, &screen_w, &screen_h);
|
||||
|
||||
float speed = 0.5;
|
||||
@@ -1226,22 +1265,15 @@ int main(void)
|
||||
|
||||
glfwSwapBuffers(window);
|
||||
glfwPollEvents();
|
||||
|
||||
double fps = 30;
|
||||
double elapsedTime = glfwGetTime() - startTime;
|
||||
double remaining = 1.0f/fps - elapsedTime;
|
||||
printf("remain = %f ms\n", remaining * 1000);
|
||||
if (remaining > 0)
|
||||
sleep_ms(remaining * 1000);
|
||||
}
|
||||
|
||||
os_mutex_lock(&frame_mutex);
|
||||
stop_workers = true;
|
||||
os_mutex_unlock(&frame_mutex);
|
||||
for (int i = 0; i < NUM_COLUMNS; i++)
|
||||
for (int i = 0; i < num_columns; i++)
|
||||
os_thread_join(workers[i]);
|
||||
|
||||
for (int i = 0; i < NUM_COLUMNS; i++)
|
||||
for (int i = 0; i < num_columns; i++)
|
||||
os_condvar_delete(&accum_conds[i]);
|
||||
|
||||
free_cubemap(&skybox);
|
||||
|
||||
Reference in New Issue
Block a user