Cycles: multithreaded export of geometry
This improves performance in scene synchronization when there are many mesh, hair and volume objects. Sync time speedups in benchmarks: barbershop 5.2x bmw 1.3x fishycat 1.5x koro 1.0x sponza 3.0x victor 1.4x wdas_cloud 0.9x Implementation by Nicolas Lelong, and Jagannadhan Ravi (AMD). Differential Revision: https://developer.blender.org/D9258
This commit is contained in:
parent
b5803c0a24
commit
bb49aa0d69
Notes:
blender-bot
2023-02-14 04:40:22 +01:00
Referenced by issue #83939, Blender randomly stops responding under Linux.
|
@ -25,6 +25,7 @@
|
|||
#include "blender/blender_util.h"
|
||||
|
||||
#include "util/util_foreach.h"
|
||||
#include "util/util_task.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
|
@ -45,7 +46,8 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
|
|||
BL::Object &b_ob,
|
||||
BL::Object &b_ob_instance,
|
||||
bool object_updated,
|
||||
bool use_particle_hair)
|
||||
bool use_particle_hair,
|
||||
TaskPool *task_pool)
|
||||
{
|
||||
/* Test if we can instance or if the object is modified. */
|
||||
BL::ID b_ob_data = b_ob.data();
|
||||
|
@ -77,8 +79,15 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
|
|||
used_shaders.push_back(default_shader);
|
||||
}
|
||||
|
||||
/* Test if we need to sync. */
|
||||
/* Ensure we only sync instanced geometry once. */
|
||||
Geometry *geom = geometry_map.find(key);
|
||||
if (geom) {
|
||||
if (geometry_synced.find(geom) != geometry_synced.end()) {
|
||||
return geom;
|
||||
}
|
||||
}
|
||||
|
||||
/* Test if we need to sync. */
|
||||
bool sync = true;
|
||||
if (geom == NULL) {
|
||||
/* Add new geometry if it did not exist yet. */
|
||||
|
@ -125,28 +134,36 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
|
|||
}
|
||||
}
|
||||
|
||||
/* Ensure we only sync instanced geometry once. */
|
||||
if (geometry_synced.find(geom) != geometry_synced.end()) {
|
||||
return geom;
|
||||
}
|
||||
|
||||
progress.set_sync_status("Synchronizing object", b_ob.name());
|
||||
|
||||
geometry_synced.insert(geom);
|
||||
|
||||
geom->name = ustring(b_ob_data.name().c_str());
|
||||
|
||||
if (geom_type == Geometry::HAIR) {
|
||||
Hair *hair = static_cast<Hair *>(geom);
|
||||
sync_hair(b_depsgraph, b_ob, hair, used_shaders);
|
||||
}
|
||||
else if (geom_type == Geometry::VOLUME) {
|
||||
Volume *volume = static_cast<Volume *>(geom);
|
||||
sync_volume(b_ob, volume, used_shaders);
|
||||
auto sync_func = [=]() mutable {
|
||||
if (progress.get_cancel())
|
||||
return;
|
||||
|
||||
progress.set_sync_status("Synchronizing object", b_ob.name());
|
||||
|
||||
if (geom_type == Geometry::HAIR) {
|
||||
Hair *hair = static_cast<Hair *>(geom);
|
||||
sync_hair(b_depsgraph, b_ob, hair, used_shaders);
|
||||
}
|
||||
else if (geom_type == Geometry::VOLUME) {
|
||||
Volume *volume = static_cast<Volume *>(geom);
|
||||
sync_volume(b_ob, volume, used_shaders);
|
||||
}
|
||||
else {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
sync_mesh(b_depsgraph, b_ob, mesh, used_shaders);
|
||||
}
|
||||
};
|
||||
|
||||
/* Defer the actual geometry sync to the task_pool for multithreading */
|
||||
if (task_pool) {
|
||||
task_pool->push(sync_func);
|
||||
}
|
||||
else {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
sync_mesh(b_depsgraph, b_ob, mesh, used_shaders);
|
||||
sync_func();
|
||||
}
|
||||
|
||||
return geom;
|
||||
|
@ -156,7 +173,8 @@ void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph,
|
|||
BL::Object &b_ob,
|
||||
Object *object,
|
||||
float motion_time,
|
||||
bool use_particle_hair)
|
||||
bool use_particle_hair,
|
||||
TaskPool *task_pool)
|
||||
{
|
||||
/* Ensure we only sync instanced geometry once. */
|
||||
Geometry *geom = object->geometry;
|
||||
|
@ -177,16 +195,29 @@ void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph,
|
|||
return;
|
||||
}
|
||||
|
||||
if (b_ob.type() == BL::Object::type_HAIR || use_particle_hair) {
|
||||
Hair *hair = static_cast<Hair *>(geom);
|
||||
sync_hair_motion(b_depsgraph, b_ob, hair, motion_step);
|
||||
}
|
||||
else if (b_ob.type() == BL::Object::type_VOLUME || object_fluid_gas_domain_find(b_ob)) {
|
||||
/* No volume motion blur support yet. */
|
||||
auto sync_func = [=]() mutable {
|
||||
if (progress.get_cancel())
|
||||
return;
|
||||
|
||||
if (b_ob.type() == BL::Object::type_HAIR || use_particle_hair) {
|
||||
Hair *hair = static_cast<Hair *>(geom);
|
||||
sync_hair_motion(b_depsgraph, b_ob, hair, motion_step);
|
||||
}
|
||||
else if (b_ob.type() == BL::Object::type_VOLUME || object_fluid_gas_domain_find(b_ob)) {
|
||||
/* No volume motion blur support yet. */
|
||||
}
|
||||
else {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
sync_mesh_motion(b_depsgraph, b_ob, mesh, motion_step);
|
||||
}
|
||||
};
|
||||
|
||||
/* Defer the actual geometry sync to the task_pool for multithreading */
|
||||
if (task_pool) {
|
||||
task_pool->push(sync_func);
|
||||
}
|
||||
else {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
sync_mesh_motion(b_depsgraph, b_ob, mesh, motion_step);
|
||||
sync_func();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "util/util_foreach.h"
|
||||
#include "util/util_hash.h"
|
||||
#include "util/util_logging.h"
|
||||
#include "util/util_task.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
|
@ -103,7 +104,8 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
|||
bool use_particle_hair,
|
||||
bool show_lights,
|
||||
BlenderObjectCulling &culling,
|
||||
bool *use_portal)
|
||||
bool *use_portal,
|
||||
TaskPool *geom_task_pool)
|
||||
{
|
||||
const bool is_instance = b_instance.is_instance();
|
||||
BL::Object b_ob = b_instance.object();
|
||||
|
@ -181,6 +183,10 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* Use task pool only for non-instances, since sync_dupli_particle accesses
|
||||
* geometry. This restriction should be removed for better performance. */
|
||||
TaskPool *object_geom_task_pool = (is_instance) ? NULL : geom_task_pool;
|
||||
|
||||
/* key to lookup object */
|
||||
ObjectKey key(b_parent, persistent_id, b_ob_instance, use_particle_hair);
|
||||
Object *object;
|
||||
|
@ -198,7 +204,12 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
|||
|
||||
/* mesh deformation */
|
||||
if (object->geometry)
|
||||
sync_geometry_motion(b_depsgraph, b_ob, object, motion_time, use_particle_hair);
|
||||
sync_geometry_motion(b_depsgraph,
|
||||
b_ob_instance,
|
||||
object,
|
||||
motion_time,
|
||||
use_particle_hair,
|
||||
object_geom_task_pool);
|
||||
}
|
||||
|
||||
return object;
|
||||
|
@ -211,8 +222,15 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
|||
object_updated = true;
|
||||
|
||||
/* mesh sync */
|
||||
object->geometry = sync_geometry(
|
||||
b_depsgraph, b_ob, b_ob_instance, object_updated, use_particle_hair);
|
||||
/* b_ob is owned by the iterator and will go out of scope at the end of the block.
|
||||
* b_ob_instance is the original object and will remain valid for deferred geometry
|
||||
* sync. */
|
||||
object->geometry = sync_geometry(b_depsgraph,
|
||||
b_ob_instance,
|
||||
b_ob_instance,
|
||||
object_updated,
|
||||
use_particle_hair,
|
||||
object_geom_task_pool);
|
||||
|
||||
/* special case not tracked by object update flags */
|
||||
|
||||
|
@ -331,6 +349,9 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
|
|||
BL::SpaceView3D &b_v3d,
|
||||
float motion_time)
|
||||
{
|
||||
/* Task pool for multithreaded geometry sync. */
|
||||
TaskPool geom_task_pool;
|
||||
|
||||
/* layer data */
|
||||
bool motion = motion_time != 0.0f;
|
||||
|
||||
|
@ -355,8 +376,8 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
|
|||
const bool show_lights = BlenderViewportParameters(b_v3d).use_scene_lights;
|
||||
|
||||
BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval();
|
||||
|
||||
BL::Depsgraph::object_instances_iterator b_instance_iter;
|
||||
|
||||
for (b_depsgraph.object_instances.begin(b_instance_iter);
|
||||
b_instance_iter != b_depsgraph.object_instances.end() && !cancel;
|
||||
++b_instance_iter) {
|
||||
|
@ -381,7 +402,8 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
|
|||
false,
|
||||
show_lights,
|
||||
culling,
|
||||
&use_portal);
|
||||
&use_portal,
|
||||
&geom_task_pool);
|
||||
}
|
||||
|
||||
/* Particle hair as separate object. */
|
||||
|
@ -393,12 +415,15 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
|
|||
true,
|
||||
show_lights,
|
||||
culling,
|
||||
&use_portal);
|
||||
&use_portal,
|
||||
&geom_task_pool);
|
||||
}
|
||||
|
||||
cancel = progress.get_cancel();
|
||||
}
|
||||
|
||||
geom_task_pool.wait_work();
|
||||
|
||||
progress.set_sync_status("");
|
||||
|
||||
if (!cancel && !motion) {
|
||||
|
|
|
@ -50,6 +50,7 @@ class ViewLayer;
|
|||
class Shader;
|
||||
class ShaderGraph;
|
||||
class ShaderNode;
|
||||
class TaskPool;
|
||||
|
||||
class BlenderSync {
|
||||
public:
|
||||
|
@ -145,7 +146,8 @@ class BlenderSync {
|
|||
bool use_particle_hair,
|
||||
bool show_lights,
|
||||
BlenderObjectCulling &culling,
|
||||
bool *use_portal);
|
||||
bool *use_portal,
|
||||
TaskPool *geom_task_pool);
|
||||
|
||||
/* Volume */
|
||||
void sync_volume(BL::Object &b_ob, Volume *volume, const vector<Shader *> &used_shaders);
|
||||
|
@ -177,12 +179,15 @@ class BlenderSync {
|
|||
BL::Object &b_ob,
|
||||
BL::Object &b_ob_instance,
|
||||
bool object_updated,
|
||||
bool use_particle_hair);
|
||||
bool use_particle_hair,
|
||||
TaskPool *task_pool);
|
||||
|
||||
void sync_geometry_motion(BL::Depsgraph &b_depsgraph,
|
||||
BL::Object &b_ob,
|
||||
Object *object,
|
||||
float motion_time,
|
||||
bool use_particle_hair);
|
||||
bool use_particle_hair,
|
||||
TaskPool *task_pool);
|
||||
|
||||
/* Light */
|
||||
void sync_light(BL::Object &b_parent,
|
||||
|
|
Loading…
Reference in New Issue