Skip to content

Commit

Permalink
lib+blender: Update top-level BVH in interactive mode
Browse files Browse the repository at this point in the history
It updates fairly quickly, the BVH swap is now guarded by both the tile
mutex *and* a rwlock on the bvh itself. I'm not sure why, but doing it
any other way made it far slower.
  • Loading branch information
vkoskiv committed Jun 29, 2024
1 parent 9e5eab5 commit 10d965d
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 18 deletions.
58 changes: 58 additions & 0 deletions src/common/platform/thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,61 @@ int thread_cond_broadcast(struct cr_cond *cond) {
return pthread_cond_broadcast(&cond->cond);
#endif
}

int thread_rwlock_init(struct cr_rwlock *lock) {
if (!lock) return -1;
#ifdef WINDOWS
InitializeSRWLock(&lock->lock);
lock->exclusive = false;
return 0;
#else
return pthread_rwlock_init(&lock->lock, NULL);
#endif
}

int thread_rwlock_destroy(struct cr_rwlock *lock) {
if (!lock) return -1;
#ifdef WINDOWS
(void)lock;
return 0;
#else
return pthread_rwlock_destroy(&lock->lock);
#endif
}

int thread_rwlock_rdlock(struct cr_rwlock *lock) {
if (!lock) return -1;
#ifdef WINDOWS
AcquireSRWLockShared(&lock->lock);
return 0;
#else
return pthread_rwlock_rdlock(&lock->lock);
#endif
}

int thread_rwlock_wrlock(struct cr_rwlock *lock) {
if (!lock) return -1;
#ifdef WINDOWS
AcquireSRWLockExclusive(&lock->lock);
lock->exclusive = true;
return 0;
#else
return pthread_rwlock_wrlock(&lock->lock);
#endif
}

int thread_rwlock_unlock(struct cr_rwlock *lock) {
if (!lock) return -1;
#ifdef WINDOWS
if (lock->exclusive) {
lock->exclusive = false;
ReleaseSRWLockExclusive(&lock->lock);
} else {
ReleaseSRWLockShared(&lock->lock);
}
return 0;
#else
return pthread_rwlock_unlock(&lock->lock);
#endif
}

17 changes: 17 additions & 0 deletions src/common/platform/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

#pragma once

#include "../../includes.h"

#ifdef WINDOWS
#include <stdbool.h>
#include <Windows.h>
Expand Down Expand Up @@ -42,6 +44,15 @@ struct cr_cond {
#endif
};

struct cr_rwlock {
#ifdef WINDOWS
SRWLock lock;
bool exclusive;
#else
pthread_rwlock_t lock;
#endif
};

typedef struct cr_thread cr_thread;
dyn_array_def(cr_thread)

Expand All @@ -68,3 +79,9 @@ int thread_cond_timed_wait(struct cr_cond *cond, struct cr_mutex *mutex, const s
int thread_cond_signal(struct cr_cond *cond);

int thread_cond_broadcast(struct cr_cond *cond);

int thread_rwlock_init(struct cr_rwlock *lock);
int thread_rwlock_destroy(struct cr_rwlock *lock);
int thread_rwlock_rdlock(struct cr_rwlock *lock);
int thread_rwlock_wrlock(struct cr_rwlock *lock);
int thread_rwlock_unlock(struct cr_rwlock *lock);
9 changes: 4 additions & 5 deletions src/lib/accelerators/bvh.c
Original file line number Diff line number Diff line change
Expand Up @@ -683,11 +683,10 @@ bool traverse_top_level_bvh(
}

void destroy_bvh(struct bvh *bvh) {
if (bvh) {
if (bvh->nodes) free(bvh->nodes);
if (bvh->prim_indices) free(bvh->prim_indices);
free(bvh);
}
if (!bvh) return;
if (bvh->nodes) free(bvh->nodes);
if (bvh->prim_indices) free(bvh->prim_indices);
free(bvh);
}

void bvh_build_task(void *arg) {
Expand Down
4 changes: 3 additions & 1 deletion src/lib/api/c-ray.c
Original file line number Diff line number Diff line change
Expand Up @@ -351,11 +351,12 @@ void cr_instance_set_transform(struct cr_scene *s_ext, cr_instance instance, flo
if ((size_t)instance > scene->instances.count - 1) return;
struct instance *i = &scene->instances.items[instance];
struct matrix4x4 mtx = mtx_convert(row_major);
if (memcmp(&i->composite, &mtx, sizeof(mtx)) == 0) return;
i->composite = (struct transform){
.A = mtx,
.Ainv = mat_invert(mtx)
};
scene->instances_dirty = true;
scene->top_level_dirty = true;
}

void cr_instance_transform(struct cr_scene *s_ext, cr_instance instance, float row_major[4][4]) {
Expand Down Expand Up @@ -836,6 +837,7 @@ void cr_renderer_restart_interactive(struct cr_renderer *ext) {
// FIXME: What about network renderers?
r->state.workers.items[i].totalSamples = 0;
}
update_toplevel_bvh(r->scene);
mutex_release(r->state.current_set->tile_mutex);
}

Expand Down
4 changes: 4 additions & 0 deletions src/lib/datatypes/scene.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ void scene_destroy(struct world *scene) {
camera_arr_free(&scene->cameras);
scene->meshes.elem_free = mesh_free;
mesh_arr_free(&scene->meshes);

thread_rwlock_wrlock(&scene->bvh_lock);
destroy_bvh(scene->topLevel);
thread_rwlock_unlock(&scene->bvh_lock);

destroyHashtable(scene->storage.node_table);
destroyBlocks(scene->storage.node_pool);

Expand Down
4 changes: 3 additions & 1 deletion src/lib/datatypes/scene.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

#pragma once

#include <stddef.h>
#include "../datatypes/mesh.h"
#include "../../common/platform/thread.h"
#include "../renderer/instance.h"
#include "camera.h"
#include "../../common/texture.h"
Expand Down Expand Up @@ -38,7 +38,9 @@ struct world {
bool instances_dirty; // Recompute top-level BVH?
// Top-level bounding volume hierarchy,
// contains all 3D assets in the scene.
struct cr_rwlock bvh_lock;
struct bvh *topLevel; // FIXME: Move to state?
bool top_level_dirty;
struct sphere_arr spheres;
struct camera_arr cameras;
struct node_storage storage; // FIXME: Move to state?
Expand Down
1 change: 1 addition & 0 deletions src/lib/renderer/pathtrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "sky.h"
#include "../renderer/instance.h"
#include "../nodes/shaders/background.h"
#include "../../common/platform/thread.h"

static inline struct hitRecord getClosestIsect(struct lightRay *incidentRay, const struct world *scene, sampler *sampler) {
//TODO: Consider passing in last instance idx + polygon to detect self-intersections?
Expand Down
32 changes: 21 additions & 11 deletions src/lib/renderer/renderer.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,21 @@ void renderer_start_interactive(struct renderer *r) {
});
}

void update_toplevel_bvh(struct world *s) {
if (!s->top_level_dirty) return;
logr(info, "%s top-level BVH\n", s->topLevel ? "Updating" : "Computing");
struct bvh *new = build_top_level_bvh(s->instances);
//!//!//!//!//!//!//!//!//!//!//!//!
thread_rwlock_wrlock(&s->bvh_lock);
struct bvh *old = s->topLevel;
s->topLevel = new;
thread_rwlock_unlock(&s->bvh_lock);
//!//!//!//!//!//!//!//!//!//!//!//!
destroy_bvh(old);
logr(info, "BVH update done\n");
s->top_level_dirty = false;
}

// TODO: Clean this up, it's ugly.
void renderer_render(struct renderer *r) {
//Check for CTRL-C
Expand Down Expand Up @@ -171,17 +186,8 @@ void renderer_render(struct renderer *r) {
// Compute BVH acceleration structures for all meshes in the scene
compute_accels(r->scene->meshes);

// And then compute a single top-level BVH that contains all the objects
if (r->scene->instances_dirty) {
logr(info, "%s top-level BVH: ", r->scene->topLevel ? "Updating" : "Computing");
if (r->scene->topLevel) destroy_bvh(r->scene->topLevel);
struct timeval bvh_timer = {0};
timer_start(&bvh_timer);
r->scene->topLevel = build_top_level_bvh(r->scene->instances);
printSmartTime(timer_get_ms(bvh_timer));
logr(plain, "\n");
r->scene->instances_dirty = false;
}
// And compute an initial top-level BVH.
update_toplevel_bvh(r->scene);

print_stats(r->scene);

Expand Down Expand Up @@ -335,7 +341,9 @@ void *render_thread_interactive(void *arg) {
initSampler(sampler, SAMPLING_STRATEGY, r->state.finishedPasses, r->prefs.sampleCount, pixIdx);

struct color output = textureGetPixel(*buf, x, y, false);
thread_rwlock_rdlock(&r->scene->bvh_lock);
struct color sample = path_trace(cam_get_ray(cam, x, y, sampler), r->scene, r->prefs.bounces, sampler);
thread_rwlock_unlock(&r->scene->bvh_lock);

nan_clamp(&sample, &output);

Expand Down Expand Up @@ -410,7 +418,9 @@ void *render_thread(void *arg) {
initSampler(sampler, SAMPLING_STRATEGY, samples - 1, r->prefs.sampleCount, pixIdx);

struct color output = textureGetPixel(*buf, x, y, false);
thread_rwlock_rdlock(&r->scene->bvh_lock);
struct color sample = path_trace(cam_get_ray(cam, x, y, sampler), r->scene, r->prefs.bounces, sampler);
thread_rwlock_unlock(&r->scene->bvh_lock);

// Clamp out fireflies - This is probably not a good way to do that.
nan_clamp(&sample, &output);
Expand Down
3 changes: 3 additions & 0 deletions src/lib/renderer/renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,7 @@ void renderer_render(struct renderer *r);
void renderer_start_interactive(struct renderer *r);
void renderer_destroy(struct renderer *r);

// Exposed for now, so API calls can synchronously ensure the BVH is up to date
void update_toplevel_bvh(struct world *s);

struct prefs default_prefs(void); // TODO: Remove

0 comments on commit 10d965d

Please sign in to comment.