Add low pass filter

This commit is contained in:
2024-11-10 23:03:38 +01:00
parent 9cb3b83b9b
commit 058f9f8a3e
+338 -181
View File
@@ -39,6 +39,13 @@ typedef struct {
int column_i; int column_i;
} WorkerConfig; } WorkerConfig;
typedef struct {
float depth;
Vector3 color;
Vector3 normal;
float roughness;
} PixelInfo;
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
/// GLOBAL VARIABLES /// /// GLOBAL VARIABLES ///
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@@ -53,21 +60,12 @@ int num_columns;
Scene scene; Scene scene;
Cubemap skybox; Cubemap skybox;
// Any time the accumulation buffer is reset or int color_buffer_frames = 0;
// resized, this is incremented. Vector3 *color_buffer;
_Atomic uint32_t accum_generation = 0; float *depth_buffer;
Vector3 *normal_buffer;
// This is the "accumulation buffer". Workers evaluate Vector3 *filter_buffer;
// pixel colors in parallel and sum their results in here. float *roughness_buffer;
// When the main thread needs to draw a new frame it takes
// these values and divides them by the frame count, averaging
// the results of multiple frames.
Vector3 *accum = NULL;
// This is the "frame buffer". It's only accessed by the
// main buffer to store the averaged values of the accumulation
// buffer before sending them to the GPU.
Vector3 *frame = NULL;
// Size of the accumulation and frame buffers // Size of the accumulation and frame buffers
int frame_w = 0; int frame_w = 0;
@@ -76,21 +74,20 @@ int frame_h = 0;
// This guards the critical section around the accumulation buffer. // This guards the critical section around the accumulation buffer.
os_mutex_t frame_mutex; os_mutex_t frame_mutex;
// One condition variable per column. Any time new information int completed = 0;
// is added to the accumulation buffer the condition of the os_condvar_t start_work;
// associated column is signaled os_condvar_t completed_work;
os_condvar_t accum_conds[MAX_COLUMNS];
// Counters that indicate how much information each column
// is storing. An integer value of N means N full frames have
// been accumulated. Lower resolution frames contribute lower
// values (half resolution weighs 0.25).
float accum_counts[MAX_COLUMNS];
uint64_t loop_cycles = 0; uint64_t loop_cycles = 0;
uint64_t loop_count = 0; uint64_t loop_count = 0;
uint64_t frame_cycles = 0;
uint64_t frame_count = 0; uint64_t global_frame_index = 0;
uint64_t global_cycle_pixel_sum = 0;
uint64_t global_pixel_count = 0;
uint64_t smooth_index = 0;
uint64_t smooth_limit = 0;
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
/// FUNCTION PROTOTYPES /// /// FUNCTION PROTOTYPES ///
@@ -103,9 +100,9 @@ bool quitting(void);
void screenshot(void); void screenshot(void);
void parse_arguments_or_exit(int argc, char **argv, int *num_columns, char **scene_file); void parse_arguments_or_exit(int argc, char **argv, int *num_columns, char **scene_file);
Vector3 pixel(float x, float y, float aspect_ratio); PixelInfo pixel(float x, float y, float aspect_ratio);
void update_frame(void); void update_frame(void);
void invalidate_accumulation(void); void invalidate_accumulation(void);
os_threadreturn worker(void *arg); os_threadreturn worker(void *arg);
@@ -113,16 +110,16 @@ os_threadreturn worker(void *arg);
/// IMPLEMENTATION /// /// IMPLEMENTATION ///
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// Resets the current frame and accumulation buffers and tells
// every worker to drop what they are doing and start again.
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++) memset(color_buffer, 0, sizeof(Vector3) * frame_w * frame_h);
accum_counts[i] = 0; memset(depth_buffer, 0, sizeof(float) * frame_w * frame_h);
atomic_fetch_add(&accum_generation, 1); memset(normal_buffer, 0, sizeof(Vector3) * frame_w * frame_h);
memset(accum, 0, sizeof(Vector3) * frame_w * frame_h); memset(roughness_buffer, 0, sizeof(float) * frame_w * frame_h);
memset(frame, 0, sizeof(Vector3) * frame_w * frame_h); color_buffer_frames = 0;
smooth_index = 0;
smooth_limit = 0;
os_mutex_unlock(&frame_mutex); os_mutex_unlock(&frame_mutex);
} }
@@ -143,13 +140,8 @@ static uint64_t wyhash64(void) {
return m2; return m2;
} }
static _Thread_local uint64_t local_pixel_cycles; PixelInfo pixel_inner(Ray in_ray)
static _Thread_local uint64_t local_pixel_count;
Vector3 pixel_inner(Ray in_ray)
{ {
uint64_t start_time = __rdtsc();
// Find a light source. This is kind of lazy as we should // Find a light source. This is kind of lazy as we should
// sample every light source in the scene. // sample every light source in the scene.
float light_sample_weight = 0.05; float light_sample_weight = 0.05;
@@ -178,6 +170,12 @@ Vector3 pixel_inner(Ray in_ray)
// Maximum number of bounces of the ray // Maximum number of bounces of the ray
int bounces = 5; int bounces = 5;
PixelInfo info;
info.depth = 1000000;
info.color = (Vector3) {0, 0, 0};
info.normal = (Vector3) {-in_ray.direction.x, -in_ray.direction.y, -in_ray.direction.z};
info.roughness = 0;
for (int i = 0; i < bounces; i++) { for (int i = 0; i < bounces; i++) {
// Find the next collision // Find the next collision
@@ -197,6 +195,12 @@ Vector3 pixel_inner(Ray in_ray)
Material material = scene.objects[hit.object].material; Material material = scene.objects[hit.object].material;
if (i == 0) {
info.depth = hit.distance;
info.normal = hit.normal;
info.roughness = material.roughness;
}
uint64_t rand_bucket_0 = wyhash64(); uint64_t rand_bucket_0 = wyhash64();
Vector3 v = in_ray.direction; Vector3 v = in_ray.direction;
@@ -332,19 +336,11 @@ Vector3 pixel_inner(Ray in_ray)
in_ray = out_ray; in_ray = out_ray;
} }
/* info.color = result;
// Saturate the result so it's a valid color return info;
result.x = clamp(result.x, 0, 1);
result.y = clamp(result.y, 0, 1);
result.z = clamp(result.z, 0, 1);
*/
local_pixel_cycles += __rdtsc() - start_time;
local_pixel_count++;
return result;
} }
Vector3 pixel(float x, float y, float aspect_ratio) PixelInfo pixel(float x, float y, float aspect_ratio)
{ {
assert(!isnan(aspect_ratio)); assert(!isnan(aspect_ratio));
@@ -356,11 +352,11 @@ Vector3 pixel(float x, float y, float aspect_ratio)
os_threadreturn worker(void *arg) os_threadreturn worker(void *arg)
{ {
// How many information is contained in the column buffer
float column_data_weight = 0;
// The actual pixels // The actual pixels
Vector3 *column_data = NULL; Vector3 *local_color_buffer = NULL;
float *local_depth_buffer = NULL;
Vector3 *local_normal_buffer = NULL;
float *local_roughness_buffer = NULL;
// The screen is divided in "num_columns" columns // The screen is divided in "num_columns" columns
int column_i = (int) arg; int column_i = (int) arg;
@@ -372,40 +368,56 @@ os_threadreturn worker(void *arg)
int cached_frame_w; int cached_frame_w;
int cached_frame_h; int cached_frame_h;
// Generation counter of the frame buffer when the worker uint64_t local_frame_index = 0;
// started producing a new frame. If the camera moves in the
// or something else causing the frame buffer to be reset, this
// will let the worker know the information needs to be thrown
// away.
uint64_t cached_generation;
os_mutex_lock(&frame_mutex); os_mutex_lock(&frame_mutex);
while (!quitting()) { for (;;) {
while (local_frame_index == global_frame_index && !quitting())
os_condvar_wait(&start_work, &frame_mutex, -1);
local_frame_index = global_frame_index;
if (quitting()) {
completed++;
os_condvar_signal(&completed_work);
break;
}
// Cache data and check if we need to resize the column buffer // Cache data and check if we need to resize the column buffer
bool resize = false; bool resize = false;
if (column_data == NULL || cached_generation != atomic_load(&accum_generation)) if (local_color_buffer == NULL)
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);
os_mutex_unlock(&frame_mutex); os_mutex_unlock(&frame_mutex);
// We need to resize // We need to resize
if (resize) { if (resize) {
free(column_data);
column_data = malloc(sizeof(Vector3) * column_w * cached_frame_h); free(local_color_buffer);
if (!column_data) abort(); local_color_buffer = malloc(sizeof(Vector3) * column_w * cached_frame_h);
if (!local_color_buffer) abort();
free(local_depth_buffer);
local_depth_buffer = malloc(sizeof(float) * column_w * cached_frame_h);
if (!local_depth_buffer) abort();
free(local_normal_buffer);
local_normal_buffer = malloc(sizeof(Vector3) * column_w * cached_frame_h);
if (!local_normal_buffer) abort();
free(local_roughness_buffer);
local_roughness_buffer = malloc(sizeof(float) * column_w * cached_frame_h);
if (!local_roughness_buffer) abort();
} }
int column_x = column_w * column_i; int column_x = column_w * column_i;
float aspect_ratio = (float) frame_w / frame_h; float aspect_ratio = (float) frame_w / frame_h;
local_pixel_cycles = 0; uint64_t local_cycle_pixel_sum = 0;
local_pixel_count = 0; uint64_t local_pixel_count = 0;
uint64_t frame_start = __rdtsc();
// Iterate over each low resolution pixel // Iterate over each low resolution pixel
for (int j = 0; j < frame_h; j++) { for (int j = 0; j < frame_h; j++) {
@@ -416,85 +428,41 @@ os_threadreturn worker(void *arg)
u = 1 - u; u = 1 - u;
v = 1 - v; v = 1 - v;
Vector3 color = pixel(u, v, aspect_ratio); uint64_t start_time = __rdtsc();
PixelInfo info = pixel(u, v, aspect_ratio);
local_cycle_pixel_sum += __rdtsc() - start_time;
local_pixel_count++;
column_data[j * column_w + i] = color; local_color_buffer[j * column_w + i] = info.color;
local_depth_buffer[j * column_w + i] = info.depth;
local_normal_buffer[j * column_w + i] = info.normal;
local_roughness_buffer[j * column_w + i] = info.roughness;
} }
if (cached_generation != atomic_load(&accum_generation)) break;
} }
uint64_t frame_delta = __rdtsc() - frame_start;
/*
for (int j = 1; j < frame_h-2; j++)
for (int i = 1; i < column_w-2; i++) {
data[j * column_w + i].x
= data[(j - 1) * column_w + (i - 1)].x
+ data[(j - 1) * column_w + (i + 0)].x
+ data[(j - 1) * column_w + (i + 1)].x
+ data[(j + 0) * column_w + (i - 1)].x
+ data[(j + 0) * column_w + (i + 0)].x
+ data[(j + 0) * column_w + (i + 1)].x
+ data[(j + 1) * column_w + (i - 1)].x
+ data[(j + 1) * column_w + (i + 0)].x
+ data[(j + 1) * column_w + (i + 1)].x;
data[j * column_w + i].x /= 9;
data[j * column_w + i].y
= data[(j - 1) * column_w + (i - 1)].y
+ data[(j - 1) * column_w + (i + 0)].y
+ data[(j - 1) * column_w + (i + 1)].y
+ data[(j + 0) * column_w + (i - 1)].y
+ data[(j + 0) * column_w + (i + 0)].y
+ data[(j + 0) * column_w + (i + 1)].y
+ data[(j + 1) * column_w + (i - 1)].y
+ data[(j + 1) * column_w + (i + 0)].y
+ data[(j + 1) * column_w + (i + 1)].y;
data[j * column_w + i].y /= 9;
data[j * column_w + i].z
= data[(j - 1) * column_w + (i - 1)].z
+ data[(j - 1) * column_w + (i + 0)].z
+ data[(j - 1) * column_w + (i + 1)].z
+ data[(j + 0) * column_w + (i - 1)].z
+ data[(j + 0) * column_w + (i + 0)].z
+ data[(j + 0) * column_w + (i + 1)].z
+ data[(j + 1) * column_w + (i - 1)].z
+ data[(j + 1) * column_w + (i + 0)].z
+ data[(j + 1) * column_w + (i + 1)].z;
data[j * column_w + i].z /= 9;
}
*/
// Now we try publishing the changes // Now we try publishing the changes
os_mutex_lock(&frame_mutex); os_mutex_lock(&frame_mutex);
loop_cycles += local_pixel_cycles; global_cycle_pixel_sum += local_cycle_pixel_sum;
loop_count += local_pixel_count; global_pixel_count += local_pixel_count;
frame_cycles += frame_delta; for (int j = 0; j < frame_h; j++)
frame_count++; for (int i = 0; i < column_w; i++) {
if (cached_generation == atomic_load(&accum_generation)) { int src_index = j * column_w + i;
// Frame didn't change its size while we were evaluating the column int dst_index = j * frame_w + (i + column_x);
// This loop basically copies the pixel colors from the column buffer to color_buffer[dst_index].x = color_buffer[dst_index].x * color_buffer_frames / (color_buffer_frames + 1) + local_color_buffer[src_index].x / (color_buffer_frames + 1);
// the frame buffer. color_buffer[dst_index].y = color_buffer[dst_index].y * color_buffer_frames / (color_buffer_frames + 1) + local_color_buffer[src_index].y / (color_buffer_frames + 1);
for (int j = 0; j < frame_h; j++) color_buffer[dst_index].z = color_buffer[dst_index].z * color_buffer_frames / (color_buffer_frames + 1) + local_color_buffer[src_index].z / (color_buffer_frames + 1);
for (int i = 0; i < column_w; i++) {
int column_x = column_w * column_i;
int src_index = j * column_w + i;
int dst_index = j * frame_w + (i + column_x);
assert(src_index >= 0 && src_index < column_w * cached_frame_h);
assert(dst_index >= 0 && dst_index < cached_frame_w * cached_frame_h);
accum[dst_index] = combine(accum[dst_index], column_data[src_index], 1, 1.0f);
}
accum_counts[column_i]++;
// Let the main thread know there are new pixels depth_buffer[dst_index] = local_depth_buffer[src_index];
os_condvar_signal(&accum_conds[column_i]); normal_buffer[dst_index] = local_normal_buffer[src_index];
roughness_buffer[dst_index] = local_roughness_buffer[src_index];
}
} completed++;
os_condvar_signal(&completed_work);
} }
os_mutex_unlock(&frame_mutex); os_mutex_unlock(&frame_mutex);
} }
@@ -504,28 +472,46 @@ void realloc_frame_buffer(void)
frame_w = get_screen_w(); frame_w = get_screen_w();
frame_h = get_screen_h(); frame_h = get_screen_h();
if (frame) free(frame); free(color_buffer);
if (accum) free(accum); color_buffer = malloc(sizeof(Vector3) * frame_w * frame_h);
if (!color_buffer) {
frame = malloc(sizeof(Vector3) * frame_w * frame_h);
if (!frame) {
printf("OUT OF MEMORY\n"); printf("OUT OF MEMORY\n");
abort(); abort();
} }
accum = malloc(sizeof(Vector3) * frame_w * frame_h); free(depth_buffer);
if (!accum) { depth_buffer = malloc(sizeof(float) * frame_w * frame_h);
if (!depth_buffer) {
printf("OUT OF MEMORY\n"); printf("OUT OF MEMORY\n");
abort(); abort();
} }
for (int i = 0; i < num_columns; i++) free(normal_buffer);
accum_counts[i] = 0; normal_buffer = malloc(sizeof(Vector3) * frame_w * frame_h);
if (!normal_buffer) {
printf("OUT OF MEMORY\n");
abort();
}
memset(accum, 0, sizeof(Vector3) * frame_w * frame_h); free(roughness_buffer);
memset(frame, 0, sizeof(Vector3) * frame_w * frame_h); roughness_buffer = malloc(sizeof(float) * frame_w * frame_h);
if (!roughness_buffer) {
printf("OUT OF MEMORY\n");
abort();
}
free(filter_buffer);
filter_buffer = malloc(sizeof(Vector3) * frame_w * frame_h);
if (!filter_buffer) {
printf("OUT OF MEMORY\n");
abort();
}
memset(color_buffer, 0, sizeof(Vector3) * frame_w * frame_h);
memset(depth_buffer, 0, sizeof(float) * frame_w * frame_h);
memset(normal_buffer, 0, sizeof(Vector3) * frame_w * frame_h);
memset(roughness_buffer, 0, sizeof(float) * frame_w * frame_h);
atomic_fetch_add(&accum_generation, 1);
} }
bool frame_buffer_size_doesnt_match_window(void) bool frame_buffer_size_doesnt_match_window(void)
@@ -533,8 +519,152 @@ bool frame_buffer_size_doesnt_match_window(void)
return frame_w != get_screen_w() || frame_h != get_screen_h(); return frame_w != get_screen_w() || frame_h != get_screen_h();
} }
static int compare_vector_luminosity(const void *a, const void *b)
{
Vector3 u = *(Vector3*) a;
Vector3 v = *(Vector3*) b;
float x = avgv(u);
float y = avgv(v);
if (x < y)
return 1;
return -1;
}
void median_filter()
{
for (int j = 0; j < frame_h; j++)
for (int i = 0; i < frame_w; i++) {
int center_pixel_location = j * frame_w + i;
Vector3 central_color = color_buffer[center_pixel_location];
bool center_roughness = roughness_buffer[center_pixel_location];
/*
if (center_roughness < 0.8) {
filter_buffer[center_pixel_location] = color_buffer[center_pixel_location];
continue;
}
*/
#define WINDOW_SIZE 3
Vector3 samples[WINDOW_SIZE*WINDOW_SIZE];
int num_samples = 0;
for (int u = 0; u < WINDOW_SIZE; u++)
for (int v = 0; v < WINDOW_SIZE; v++) {
int g = j + u - WINDOW_SIZE / 2;
int t = i + v - WINDOW_SIZE / 2;
if (g < 0 || t < 0 || t >= frame_w || g >= frame_h)
continue;
int neighbor_pixel_location = g * frame_w + t;
if (absf(depth_buffer[center_pixel_location] - depth_buffer[neighbor_pixel_location]) > 1)
continue;
bool neighbor_roughness = roughness_buffer[neighbor_pixel_location];
if (absf(neighbor_roughness - center_roughness) > 0.2)
continue;
samples[num_samples++] = color_buffer[neighbor_pixel_location];
}
qsort(samples, num_samples, sizeof(Vector3), compare_vector_luminosity);
filter_buffer[center_pixel_location] = samples[num_samples/2];
/*
float error = (absf(central_color.x - result.x) + absf(central_color.y - result.y) + absf(central_color.z - result.z)) / 3;
if (error > 0.05)
filter_buffer[center_pixel_location] = result;
else
filter_buffer[center_pixel_location] = color_buffer[center_pixel_location];
*/
}
//memcpy(color_buffer, filter_buffer, sizeof(Vector3) * frame_w * frame_h);
}
void smooth_filter()
{
for (int j = 0; j < frame_h; j++)
for (int i = 0; i < frame_w; i++) {
Vector3 samples = {0, 0, 0};
int num_samples = 0;
float weight_sum = 0;
int center_pixel_location = j * frame_w + i;
Vector3 central_color = color_buffer[center_pixel_location];
bool center_roughness = roughness_buffer[center_pixel_location];
/*
if (center_roughness < 0.8) {
filter_buffer[center_pixel_location] = color_buffer[center_pixel_location];
continue;
}
*/
#define WINDOW_SIZE 3
for (int u = 0; u < WINDOW_SIZE; u++)
for (int v = 0; v < WINDOW_SIZE; v++) {
int g = j + u - WINDOW_SIZE / 2;
int t = i + v - WINDOW_SIZE / 2;
if (g < 0 || t < 0 || t >= frame_w || g >= frame_h)
continue;
int neighbor_pixel_location = g * frame_w + t;
if (absf(depth_buffer[center_pixel_location] - depth_buffer[neighbor_pixel_location]) > 1)
continue;
bool neighbor_roughness = roughness_buffer[neighbor_pixel_location];
if (absf(neighbor_roughness - center_roughness) > 0.2)
continue;
Vector3 center_normal = normal_buffer[center_pixel_location];
Vector3 neighbor_normal = normal_buffer[neighbor_pixel_location];
float simil = dotv(center_normal, neighbor_normal);
if (simil < 0.9)
continue;
float weight;
if (t == i && g == j)
weight = 1 - center_roughness;
else
weight = center_roughness;
weight += 0.1;
samples.x += weight * color_buffer[neighbor_pixel_location].x;
samples.y += weight * color_buffer[neighbor_pixel_location].y;
samples.z += weight * color_buffer[neighbor_pixel_location].z;
weight_sum += weight;
}
Vector3 result;
result.x = samples.x / weight_sum;
result.y = samples.y / weight_sum;
result.z = samples.z / weight_sum;
filter_buffer[center_pixel_location] = result;
/*
float error = (absf(central_color.x - result.x) + absf(central_color.y - result.y) + absf(central_color.z - result.z)) / 3;
if (error > 0.05)
filter_buffer[center_pixel_location] = result;
else
filter_buffer[center_pixel_location] = color_buffer[center_pixel_location];
*/
}
memcpy(color_buffer, filter_buffer, sizeof(Vector3) * frame_w * frame_h);
}
uint64_t start_time_ns;
uint64_t start_time_cycles;
void update_frame(void) void update_frame(void)
{ {
uint64_t frame_start = __rdtsc();
os_mutex_lock(&frame_mutex); os_mutex_lock(&frame_mutex);
if (frame_buffer_size_doesnt_match_window()) if (frame_buffer_size_doesnt_match_window())
@@ -542,32 +672,54 @@ void update_frame(void)
int column_w = frame_w / num_columns; int column_w = frame_w / num_columns;
// Wait for the workers to produce a frame completed = 0;
// (each worker produces a column) global_frame_index++;
for (int i = 0; i < num_columns; i++) { for (int i = 0; i < num_columns; i++)
while (accum_counts[i] < 0.0001) os_condvar_signal(&start_work);
os_condvar_wait(&accum_conds[i], &frame_mutex, -1);
while (completed < num_columns)
os_condvar_wait(&completed_work, &frame_mutex, -1);
color_buffer_frames++;
bool smooth = false;
if (smooth_index == smooth_limit) {
smooth = true;
smooth_index = 0;
smooth_limit++;
printf("smoothing!\n");
}
smooth_index++;
if (smooth) {
smooth_filter();
for (int i = 0; i < frame_w * frame_h; i++) {
filter_buffer[i].x = clamp(filter_buffer[i].x, 0, 1);
filter_buffer[i].y = clamp(filter_buffer[i].y, 0, 1);
filter_buffer[i].z = clamp(filter_buffer[i].z, 0, 1);
}
} else {
for (int i = 0; i < frame_w * frame_h; i++) {
filter_buffer[i].x = clamp(color_buffer[i].x, 0, 1);
filter_buffer[i].y = clamp(color_buffer[i].y, 0, 1);
filter_buffer[i].z = clamp(color_buffer[i].z, 0, 1);
}
} }
// Copy pixels from the accumulation buffer to the frame buffer move_frame_to_the_gpu(frame_w, frame_h, filter_buffer);
for (int j = 0; j < frame_h; j++)
for (int i = 0; i < frame_w; i++) {
float u = (float) i / (frame_w - 1); uint64_t cycles_per_pixel = global_cycle_pixel_sum / global_pixel_count;
float v = (float) j / (frame_h - 1);
u = 1 - u;
v = 1 - v;
int pixel_index = j * frame_w + i;
frame[pixel_index] = scalev(accum[pixel_index], 1.0f / accum_counts[i / column_w]);
}
move_frame_to_the_gpu(frame_w, frame_h, frame);
printf("pixel -> %lu cycles\n", loop_cycles / loop_count);
printf("frame -> %lu cycles\n", frame_cycles / frame_count);
os_mutex_unlock(&frame_mutex); os_mutex_unlock(&frame_mutex);
uint64_t cycles_per_frame = __rdtsc() - frame_start;
uint64_t current_time_cycles = __rdtsc();
uint64_t current_time_ns = get_relative_time_ns();
double cy2ns = (double) (current_time_ns - start_time_ns) / (current_time_cycles - start_time_cycles);
printf("pixel -> %llu cycles (%f ns)\n", cycles_per_pixel, cycles_per_pixel * cy2ns);
printf("frame -> %llu cycles (%f ns)\n", cycles_per_frame, cycles_per_frame * cy2ns);
} }
int main(int argc, char **argv) int main(int argc, char **argv)
@@ -625,6 +777,9 @@ int main(int argc, char **argv)
fprintf(stderr, "Workers started\n"); fprintf(stderr, "Workers started\n");
start_time_ns = get_relative_time_ns();
start_time_cycles = __rdtsc();
for (bool exit = false; !exit; ) { for (bool exit = false; !exit; ) {
for (;;) { for (;;) {
@@ -760,9 +915,9 @@ void screenshot(void)
fprintf(stderr, "Couldn't take screenshot (out of memory)\n"); fprintf(stderr, "Couldn't take screenshot (out of memory)\n");
} }
for (int i = 0; i < frame_w * frame_h; i++) { for (int i = 0; i < frame_w * frame_h; i++) {
converted[i * 3 + 0] = frame[i].x * 255; converted[i * 3 + 0] = filter_buffer[i].x * 255;
converted[i * 3 + 1] = frame[i].y * 255; converted[i * 3 + 1] = filter_buffer[i].y * 255;
converted[i * 3 + 2] = frame[i].z * 255; converted[i * 3 + 2] = filter_buffer[i].z * 255;
} }
stbi_flip_vertically_on_write(1); stbi_flip_vertically_on_write(1);
@@ -794,8 +949,8 @@ void start_workers(void)
os_mutex_create(&frame_mutex); os_mutex_create(&frame_mutex);
for (int i = 0; i < num_columns; i++) os_condvar_create(&start_work);
os_condvar_create(&accum_conds[i]); os_condvar_create(&completed_work);
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);
@@ -805,10 +960,12 @@ void stop_workers(void)
{ {
os_mutex_lock(&frame_mutex); os_mutex_lock(&frame_mutex);
workers_should_stop = true; workers_should_stop = true;
for (int i = 0; i < num_columns; i++)
os_condvar_signal(&start_work);
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++) os_condvar_delete(&start_work);
os_condvar_delete(&accum_conds[i]); os_condvar_delete(&completed_work);
} }