Add --threads option
This commit is contained in:
+77
-45
@@ -482,9 +482,21 @@ bool intersect_object(Ray r, Object o, float *t, Vector3 *normal)
|
|||||||
return false;
|
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)
|
float random_float(void)
|
||||||
{
|
{
|
||||||
return (float) rand() / RAND_MAX;
|
return (float) wyhash64() / UINT64_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 random_vector(void)
|
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);
|
Ray in_ray = ray_through_screen_at(x, y, aspect_ratio);
|
||||||
assert(!isnanv(in_ray.direction));
|
assert(!isnanv(in_ray.direction));
|
||||||
|
|
||||||
//Vector3 sky_color = {0.6, 0.7, 0.9};
|
// Choose a light source
|
||||||
//Vector3 sky_color = {0, 0, 0};
|
int light_index = -1;
|
||||||
//Vector3 sky_color = {1, 1, 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 contrib = {1, 1, 1};
|
||||||
Vector3 result = {0, 0, 0};
|
Vector3 result = {0, 0, 0};
|
||||||
@@ -609,43 +626,41 @@ Vector3 pixel(float x, float y, float aspect_ratio)
|
|||||||
|
|
||||||
HitInfo hit = trace_ray(in_ray);
|
HitInfo hit = trace_ray(in_ray);
|
||||||
if (hit.object == -1) {
|
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));
|
Vector3 sky_color = sample_cubemap(&skybox, normalize(in_ray.direction));
|
||||||
result = combine(result, mulv(sky_color, contrib), 1, 1);
|
result = combine(result, mulv(sky_color, contrib), 1, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 sampled_light_color = {0, 0, 0};
|
Vector3 sampled_light_color = {0, 0, 0};
|
||||||
for (int j = 0; j < num_objects; j++) {
|
if (light_index != -1) {
|
||||||
if (objects[j].material.emission_power == 0 || j == hit.object)
|
Vector3 dir_to_light_source = combine(origin_of(objects[light_index]), hit.point, 1, -1);
|
||||||
continue;
|
int max_samples = 3;
|
||||||
Vector3 dir_to_light_source = combine(origin_of(objects[j]), hit.point, 1, -1);
|
int num_samples = 0;
|
||||||
int samples = 5;
|
|
||||||
float spread = 0.5;
|
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
|
// Add some noise based on roughness
|
||||||
Vector3 rand_dir = random_direction();
|
Vector3 rand_dir = random_direction();
|
||||||
if (dotv(rand_dir, hit.normal) < 0)
|
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));
|
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 };
|
Ray sample_ray = { combine(hit.point, sample_dir, 1, 0.001), sample_dir };
|
||||||
HitInfo hit2 = trace_ray(sample_ray);
|
HitInfo hit2 = trace_ray(sample_ray);
|
||||||
if (hit2.object != -1)
|
if (hit2.object != -1)
|
||||||
sampled_light_color = combine(sampled_light_color, objects[hit2.object].material.emission_color, 1, objects[hit2.object].material.emission_power);
|
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;
|
Material material = objects[hit.object].material;
|
||||||
|
|
||||||
Vector3 v = scale(in_ray.direction, -1);
|
Vector3 v = scale(in_ray.direction, -1);
|
||||||
//Vector3 l = out_dir;
|
|
||||||
Vector3 n = hit.normal;
|
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 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_dielectric = vec_from_scalar(0.16 * material.reflectance * material.reflectance);
|
||||||
Vector3 f0_metal = material.albedo;
|
Vector3 f0_metal = material.albedo;
|
||||||
@@ -686,7 +701,9 @@ Vector3 pixel(float x, float y, float aspect_ratio)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define NUM_COLUMNS 16
|
int num_columns = 1;
|
||||||
|
int init_scale = 2;
|
||||||
|
#define MAX_COLUMNS 32
|
||||||
|
|
||||||
bool stop_workers = false;
|
bool stop_workers = false;
|
||||||
_Atomic uint32_t accum_generation = 0;
|
_Atomic uint32_t accum_generation = 0;
|
||||||
@@ -695,9 +712,9 @@ Vector3 *frame = NULL;
|
|||||||
int frame_w = 0;
|
int frame_w = 0;
|
||||||
int frame_h = 0;
|
int frame_h = 0;
|
||||||
unsigned int frame_texture;
|
unsigned int frame_texture;
|
||||||
float accum_counts[NUM_COLUMNS] = {0};
|
float accum_counts[MAX_COLUMNS] = {0};
|
||||||
os_mutex_t frame_mutex;
|
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)
|
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;
|
int cached_frame_h;
|
||||||
uint64_t cached_generation;
|
uint64_t cached_generation;
|
||||||
|
|
||||||
int init_scale = 16;
|
|
||||||
int scale_ = init_scale;
|
int scale_ = init_scale;
|
||||||
|
|
||||||
os_mutex_lock(&frame_mutex);
|
os_mutex_lock(&frame_mutex);
|
||||||
@@ -758,7 +774,7 @@ os_threadreturn worker(void *arg)
|
|||||||
|
|
||||||
if (column_data == NULL || cached_generation != atomic_load(&accum_generation))
|
if (column_data == NULL || cached_generation != atomic_load(&accum_generation))
|
||||||
resize = true;
|
resize = true;
|
||||||
column_w = frame_w / NUM_COLUMNS;
|
column_w = frame_w / num_columns;
|
||||||
cached_frame_w = frame_w;
|
cached_frame_w = frame_w;
|
||||||
cached_frame_h = frame_h;
|
cached_frame_h = frame_h;
|
||||||
cached_generation = atomic_load(&accum_generation);
|
cached_generation = atomic_load(&accum_generation);
|
||||||
@@ -801,7 +817,7 @@ os_threadreturn worker(void *arg)
|
|||||||
void invalidate_accumulation(void)
|
void invalidate_accumulation(void)
|
||||||
{
|
{
|
||||||
os_mutex_lock(&frame_mutex);
|
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;
|
accum_counts[i] = 0;
|
||||||
atomic_fetch_add(&accum_generation, 1);
|
atomic_fetch_add(&accum_generation, 1);
|
||||||
memset(accum, 0, sizeof(Vector3) * frame_w * frame_h);
|
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);
|
accum = malloc(sizeof(Vector3) * frame_w * frame_h);
|
||||||
if (!accum) { printf("OUT OF MEMORY\n"); abort(); }
|
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;
|
accum_counts[i] = 0;
|
||||||
|
|
||||||
memset(accum, 0, sizeof(Vector3) * frame_w * frame_h);
|
memset(accum, 0, sizeof(Vector3) * frame_w * frame_h);
|
||||||
@@ -836,9 +852,9 @@ void update_frame_texture(void)
|
|||||||
atomic_fetch_add(&accum_generation, 1);
|
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)
|
while (accum_counts[i] < 0.0001)
|
||||||
os_condvar_wait(&accum_conds[i], &frame_mutex, -1);
|
os_condvar_wait(&accum_conds[i], &frame_mutex, -1);
|
||||||
}
|
}
|
||||||
@@ -862,8 +878,33 @@ void update_frame_texture(void)
|
|||||||
os_mutex_unlock(&frame_mutex);
|
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
|
#if 0
|
||||||
|
|
||||||
add_object(sphere(
|
add_object(sphere(
|
||||||
@@ -1147,12 +1188,12 @@ int main(void)
|
|||||||
|
|
||||||
os_mutex_create(&frame_mutex);
|
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]);
|
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);
|
os_thread_create(&workers[i], (void*) i, worker);
|
||||||
|
|
||||||
unsigned int screen_program = compile_shader("assets/screen.vs", "assets/screen.fs");
|
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);
|
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_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 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_MIN_FILTER, GL_LINEAR);
|
||||||
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_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_MIN_FILTER, GL_NEAREST);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
|
||||||
while (!glfwWindowShouldClose(window)) {
|
while (!glfwWindowShouldClose(window)) {
|
||||||
|
|
||||||
double startTime = glfwGetTime();
|
|
||||||
|
|
||||||
glfwGetWindowSize(window, &screen_w, &screen_h);
|
glfwGetWindowSize(window, &screen_w, &screen_h);
|
||||||
|
|
||||||
float speed = 0.5;
|
float speed = 0.5;
|
||||||
@@ -1226,22 +1265,15 @@ int main(void)
|
|||||||
|
|
||||||
glfwSwapBuffers(window);
|
glfwSwapBuffers(window);
|
||||||
glfwPollEvents();
|
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);
|
os_mutex_lock(&frame_mutex);
|
||||||
stop_workers = true;
|
stop_workers = true;
|
||||||
os_mutex_unlock(&frame_mutex);
|
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]);
|
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]);
|
os_condvar_delete(&accum_conds[i]);
|
||||||
|
|
||||||
free_cubemap(&skybox);
|
free_cubemap(&skybox);
|
||||||
|
|||||||
Reference in New Issue
Block a user