Skip to content

Commit

Permalink
lib: Compute BVHs asynchronously
Browse files Browse the repository at this point in the history
A new cr_mesh_finalize() API function starts the BVH build task while
other meshes are still being loaded to reduce initialization time.
  • Loading branch information
vkoskiv committed Jul 2, 2024
1 parent fb3157c commit a3e61ea
Show file tree
Hide file tree
Showing 10 changed files with 56 additions and 40 deletions.
1 change: 1 addition & 0 deletions bindings/blender_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ def sync_scene(self, depsgraph):
facebuf = (c_ray.cr_face * len(faces))(*faces)
cr_mesh.bind_faces(bytearray(facebuf), len(faces))
cr_mesh.bind_vertex_buf(me)
cr_mesh.finalize()

# Set background shader
bl_nodetree = bpy.data.worlds[0].node_tree
Expand Down
2 changes: 2 additions & 0 deletions bindings/c_ray.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,8 @@ def bind_vertex_buf(self, me):
_lib.mesh_bind_vertex_buf(self.scene_ptr, self.cr_idx, self.v, self.vn, self.n, self.nn, self.t, self.tn)
def bind_faces(self, faces, face_count):
_lib.mesh_bind_faces(self.scene_ptr, self.cr_idx, faces, face_count)
def finalize(self):
_lib.mesh_finalize(self.scene_ptr, self.cr_idx)
def instance_new(self):
self.instances.append(instance(self.scene_ptr, self, 0))
return self.instances[-1]
Expand Down
14 changes: 14 additions & 0 deletions bindings/cray_wrap.c
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,19 @@ static PyObject *py_cr_mesh_bind_faces(PyObject *self, PyObject *args) {
Py_RETURN_NONE;
}

static PyObject *py_cr_mesh_finalize(PyObject *self, PyObject *args) {
(void)self; (void)args;
PyObject *s_ext;
cr_mesh mesh;
if (!PyArg_ParseTuple(args, "Ol", &s_ext, &mesh)) {
return NULL;
}

struct cr_scene *s = PyCapsule_GetPointer(s_ext, "cray.cr_scene");
cr_mesh_finalize(s, mesh);
Py_RETURN_NONE;
}

static PyObject *py_cr_scene_mesh_new(PyObject *self, PyObject *args) {
(void)self; (void)args;
PyObject *s_ext;
Expand Down Expand Up @@ -732,6 +745,7 @@ static PyMethodDef cray_methods[] = {
{ "scene_add_sphere", py_cr_scene_add_sphere, METH_VARARGS, "" },
{ "mesh_bind_vertex_buf", py_cr_mesh_bind_vertex_buf, METH_VARARGS, "" },
{ "mesh_bind_faces", py_cr_mesh_bind_faces, METH_VARARGS, "" },
{ "mesh_finalize", py_cr_mesh_finalize, METH_VARARGS, "" },
{ "scene_mesh_new", py_cr_scene_mesh_new, METH_VARARGS, "" },
{ "scene_get_mesh", py_cr_scene_get_mesh, METH_VARARGS, "" },
{ "camera_new", py_cr_camera_new, METH_VARARGS, "" },
Expand Down
1 change: 1 addition & 0 deletions include/c-ray/c-ray.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ CR_EXPORT cr_mesh cr_scene_get_mesh(struct cr_scene *s_ext, const char *name);

CR_EXPORT void cr_mesh_bind_vertex_buf(struct cr_scene *s_ext, cr_mesh mesh, struct cr_vertex_buf_param buf);
CR_EXPORT void cr_mesh_bind_faces(struct cr_scene *s_ext, cr_mesh mesh, struct cr_face *faces, size_t face_count);
CR_EXPORT void cr_mesh_finalize(struct cr_scene *s_ext, cr_mesh mesh);

// -- Camera --
// FIXME: Use cr_vector
Expand Down
32 changes: 0 additions & 32 deletions src/lib/accelerators/bvh.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@
#include "../datatypes/poly.h"
#include "../renderer/instance.h"
#include "../../common/vector.h"
#include "../../common/platform/thread.h"
#include "../../common/platform/thread_pool.h"
#include "../../common/platform/capabilities.h"
#include "../../common/platform/signal.h"
#include "../../common/timer.h"

Expand Down Expand Up @@ -689,32 +686,3 @@ void destroy_bvh(struct bvh *bvh) {
free(bvh);
}

void bvh_build_task(void *arg) {
block_signals();
struct mesh *mesh = (struct mesh *)arg;
struct timeval timer = { 0 };
timer_start(&timer);
mesh->bvh = build_mesh_bvh(mesh);
if (mesh->bvh) {
logr(debug, "Built BVH for %s, took %lums\n", mesh->name, timer_get_ms(timer));
} else {
logr(debug, "BVH build FAILED for %s\n", mesh->name);
}
}

// FIXME: Add pthread_cancel() support
void compute_accels(struct mesh_arr meshes) {
struct cr_thread_pool *pool = thread_pool_create(sys_get_cores());
logr(info, "Updating %zu BVHs: ", meshes.count);
struct timeval timer = { 0 };
timer_start(&timer);
for (size_t i = 0; i < meshes.count; ++i) {
if (!meshes.items[i].bvh) thread_pool_enqueue(pool, bvh_build_task, &meshes.items[i]);
}
thread_pool_wait(pool);

printSmartTime(timer_get_ms(timer));
logr(plain, "\n");
thread_pool_destroy(pool);
}

2 changes: 0 additions & 2 deletions src/lib/accelerators/bvh.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,3 @@ bool traverse_bottom_level_bvh(

/// Frees the memory allocated by the given BVH
void destroy_bvh(struct bvh *);

void compute_accels(struct mesh_arr meshes);
26 changes: 26 additions & 0 deletions src/lib/api/c-ray.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "../../common/gitsha1.h"
#include "../../common/fileio.h"
#include "../../common/platform/terminal.h"
#include "../../common/platform/signal.h"
#include "../../common/assert.h"
#include "../../common/texture.h"
#include "../../common/string.h"
Expand All @@ -29,6 +30,8 @@
#include "../../common/json_loader.h"
#include "../protocol/protocol.h"
#include "../../common/node_parse.h"
#include "../../common/platform/thread_pool.h"
#include "../accelerators/bvh.h"

#ifdef CRAY_DEBUG_ENABLED
#define DEBUG "D"
Expand Down Expand Up @@ -254,6 +257,20 @@ cr_sphere cr_scene_add_sphere(struct cr_scene *s_ext, float radius) {
return sphere_arr_add(&scene->spheres, (struct sphere){ .radius = radius });
}

void bvh_build_task(void *arg) {
block_signals();
struct mesh *mesh = (struct mesh *)arg;
if (mesh->bvh) destroy_bvh(mesh->bvh);
struct timeval timer = { 0 };
timer_start(&timer);
mesh->bvh = build_mesh_bvh(mesh);
if (mesh->bvh) {
logr(debug, "Built BVH for %s, took %lums\n", mesh->name, timer_get_ms(timer));
} else {
logr(debug, "BVH build FAILED for %s\n", mesh->name);
}
}

void cr_mesh_bind_vertex_buf(struct cr_scene *s_ext, cr_mesh mesh, struct cr_vertex_buf_param buf) {
if (!s_ext) return;
struct world *scene = (struct world *)s_ext;
Expand Down Expand Up @@ -290,6 +307,14 @@ void cr_mesh_bind_faces(struct cr_scene *s_ext, cr_mesh mesh, struct cr_face *fa
}
}

void cr_mesh_finalize(struct cr_scene *s_ext, cr_mesh mesh) {
if (!s_ext) return;
struct world *scene = (struct world *)s_ext;
if ((size_t)mesh > scene->meshes.count - 1) return;
struct mesh *m = &scene->meshes.items[mesh];
thread_pool_enqueue(scene->bvh_builder, bvh_build_task, m);
}

cr_mesh cr_scene_mesh_new(struct cr_scene *s_ext, const char *name) {
if (!s_ext) return -1;
struct world *scene = (struct world *)s_ext;
Expand Down Expand Up @@ -844,6 +869,7 @@ void cr_renderer_restart_interactive(struct cr_renderer *ext) {
r->state.workers.items[i].totalSamples = 0;
}
update_toplevel_bvh(r->scene);
thread_pool_wait(r->scene->bvh_builder);
mutex_release(r->state.current_set->tile_mutex);
}

Expand Down
2 changes: 2 additions & 0 deletions src/lib/datatypes/scene.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ struct world {
struct cr_rwlock bvh_lock;
struct bvh *topLevel; // FIXME: Move to state?
bool top_level_dirty;
struct cr_thread_pool *bvh_builder;

struct sphere_arr spheres;
struct camera_arr cameras;
struct node_storage storage; // FIXME: Move to state?
Expand Down
6 changes: 3 additions & 3 deletions src/lib/protocol/worker.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "../../common/texture.h"
#include "../../common/platform/mutex.h"
#include "../../common/platform/thread.h"
#include "../../common/platform/thread_pool.h"
#include "../../common/networking.h"
#include "../../common/string.h"
#include "../../common/gitsha1.h"
Expand Down Expand Up @@ -231,9 +232,8 @@ static cJSON *startRender(int connectionSocket, size_t thread_limit) {
struct tile_set set = tile_quantize(selected_cam.width, selected_cam.height, r->prefs.tileWidth, r->prefs.tileHeight, r->prefs.tileOrder);

logr(info, "%u x %u tiles\n", r->prefs.tileWidth, r->prefs.tileHeight);
// Do some pre-render preparations
// Compute BVH acceleration structures for all meshes in the scene
compute_accels(r->scene->meshes);
// Ensure BVHs are up to date
thread_pool_wait(r->scene->bvh_builder);

// And then compute a single top-level BVH that contains all the objects
logr(info, "Computing top-level BVH: ");
Expand Down
10 changes: 7 additions & 3 deletions src/lib/renderer/renderer.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "../../common/timer.h"
#include "../../common/texture.h"
#include "../../common/platform/thread.h"
#include "../../common/platform/thread_pool.h"
#include "../../common/platform/mutex.h"
#include "../../common/platform/capabilities.h"
#include "../../common/platform/signal.h"
Expand Down Expand Up @@ -175,9 +176,10 @@ void renderer_render(struct renderer *r) {
inst->bbuf = &r->scene->shader_buffers.items[inst->bbuf_idx];
}

// Do some pre-render preparations
// Compute BVH acceleration structures for all meshes in the scene
compute_accels(r->scene->meshes);
// Ensure BVHs are up to date
logr(debug, "Waiting for BVH thread pool\n");
thread_pool_wait(r->scene->bvh_builder);
logr(debug, "Continuing\n");

// And compute an initial top-level BVH.
update_toplevel_bvh(r->scene);
Expand Down Expand Up @@ -479,11 +481,13 @@ struct renderer *renderer_new(void) {
r->scene->asset_path = stringCopy("./");
r->scene->storage.node_pool = newBlock(NULL, 1024);
r->scene->storage.node_table = newHashtable(compareNodes, &r->scene->storage.node_pool);
r->scene->bvh_builder = thread_pool_create(sys_get_cores());
return r;
}

void renderer_destroy(struct renderer *r) {
if (!r) return;
thread_pool_destroy(r->scene->bvh_builder);
scene_destroy(r->scene);
worker_arr_free(&r->state.workers);
render_client_arr_free(&r->state.clients);
Expand Down

0 comments on commit a3e61ea

Please sign in to comment.