diff options
author | Kévin Dietrich <kevin.dietrich@mailoo.org> | 2021-01-22 17:01:26 +0300 |
---|---|---|
committer | Kévin Dietrich <kevin.dietrich@mailoo.org> | 2021-01-22 18:08:25 +0300 |
commit | bbe6d44928235cd4a5cfbeaf1a1de78ed861bb92 (patch) | |
tree | c3a8653dfdf38029caebfd9978ea4644535bae3d /intern/cycles | |
parent | 131a758b6f88a2be816e9351d216bcfb9c965c4b (diff) |
Cycles: optimize device updates
This optimizes device updates (during user edits or frame changes in
the viewport) by avoiding unnecessary computations. To achieve this,
we use a combination of the sockets' update flags as well as some new
flags passed to the various managers when tagging for an update to tell
exactly what the tagging is for (e.g. shader was modified, object was
removed, etc.).
Besides avoiding recomputations, we also avoid resending to the devices
unmodified data arrays, thus reducing bandwidth usage. For OptiX and
Embree, BVH packing was also multithreaded.
The performance improvements may vary depending on the used device (CPU
or GPU), and the content of the scene. Simple scenes (e.g. with no adaptive
subdivision or volumes) rendered using OptiX will benefit from this work
the most.
On average, for a variety of animated scenes, this gives a 3x speedup.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79174
Differential Revision: https://developer.blender.org/D9555
Diffstat (limited to 'intern/cycles')
40 files changed, 1084 insertions, 338 deletions
diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp index 964241e9904..1764b5b635d 100644 --- a/intern/cycles/blender/blender_curves.cpp +++ b/intern/cycles/blender/blender_curves.cpp @@ -855,10 +855,7 @@ void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Hair *ha hair->set_value(socket, new_hair, socket); } - hair->attributes.clear(); - foreach (Attribute &attr, new_hair.attributes.attributes) { - hair->attributes.attributes.push_back(std::move(attr)); - } + hair->attributes.update(std::move(new_hair.attributes)); /* tag update */ diff --git a/intern/cycles/blender/blender_geometry.cpp b/intern/cycles/blender/blender_geometry.cpp index bd2f0731030..99df8b7b1c9 100644 --- a/intern/cycles/blender/blender_geometry.cpp +++ b/intern/cycles/blender/blender_geometry.cpp @@ -124,7 +124,7 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph, foreach (Node *node, geom->get_used_shaders()) { Shader *shader = static_cast<Shader *>(node); - if (shader->need_update_geometry) { + if (shader->need_update_geometry()) { attribute_recalc = true; } } diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index 3420025f472..b334da38372 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -1075,15 +1075,8 @@ void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *me mesh->set_value(socket, new_mesh, socket); } - mesh->attributes.clear(); - foreach (Attribute &attr, new_mesh.attributes.attributes) { - mesh->attributes.attributes.push_back(std::move(attr)); - } - - mesh->subd_attributes.clear(); - foreach (Attribute &attr, new_mesh.subd_attributes.attributes) { - mesh->subd_attributes.attributes.push_back(std::move(attr)); - } + mesh->attributes.update(std::move(new_mesh.attributes)); + mesh->subd_attributes.update(std::move(new_mesh.subd_attributes)); mesh->set_num_subd_faces(new_mesh.get_num_subd_faces()); diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 5261fbcee07..8daaaea6978 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -243,9 +243,6 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, /* holdout */ object->set_use_holdout(use_holdout); - if (object->use_holdout_is_modified()) { - scene->object_manager->tag_update(scene); - } object->set_visibility(visibility); diff --git a/intern/cycles/blender/blender_particles.cpp b/intern/cycles/blender/blender_particles.cpp index ca221b229b4..d5dd7215c47 100644 --- a/intern/cycles/blender/blender_particles.cpp +++ b/intern/cycles/blender/blender_particles.cpp @@ -57,7 +57,7 @@ bool BlenderSync::sync_dupli_particle(BL::Object &b_ob, /* no update needed? */ if (!need_update && !object->get_geometry()->is_modified() && - !scene->object_manager->need_update) + !scene->object_manager->need_update()) return true; /* first time used in this sync loop? clear and tag update */ @@ -85,7 +85,7 @@ bool BlenderSync::sync_dupli_particle(BL::Object &b_ob, object->set_particle_index(psys->particles.size() - 1); if (object->particle_index_is_modified()) - scene->object_manager->tag_update(scene); + scene->object_manager->tag_update(scene, ObjectManager::PARTICLE_MODIFIED); /* return that this object has particle data */ return true; diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index 8566d0e7ed5..2ec76be4ee8 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -552,7 +552,6 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_) int seed = scene->integrator->get_seed(); seed += hash_uint2(seed, hash_uint2(view_index * 0xdeadbeef, 0)); scene->integrator->set_seed(seed); - scene->integrator->tag_update(scene); } /* Update number of samples per layer. */ @@ -1116,10 +1115,6 @@ void BlenderSession::update_resumable_tile_manager(int num_samples) scene->integrator->set_start_sample(rounded_range_start_sample); - if (scene->integrator->is_modified()) { - scene->integrator->tag_update(scene); - } - session->tile_manager.range_start_sample = rounded_range_start_sample; session->tile_manager.range_num_samples = rounded_range_num_samples; } diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index ac86cf3345c..f3f46a1b108 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -1497,7 +1497,6 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, shader->set_graph(graph); shader->tag_update(scene); - background->tag_update(scene); } PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); @@ -1517,8 +1516,7 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, viewport_parameters.custom_viewport_parameters()); background->set_use_ao(background->get_use_ao() && view_layer.use_background_ao); - if (background->is_modified()) - background->tag_update(scene); + background->tag_update(scene); } /* Sync Lights */ diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index e27daa2488d..6b2039e7e21 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -302,11 +302,6 @@ void BlenderSync::sync_integrator() integrator->set_sample_clamp_direct(get_float(cscene, "sample_clamp_direct")); integrator->set_sample_clamp_indirect(get_float(cscene, "sample_clamp_indirect")); if (!preview) { - if (integrator->get_motion_blur() != r.use_motion_blur()) { - scene->object_manager->tag_update(scene); - scene->camera->tag_modified(); - } - integrator->set_motion_blur(r.use_motion_blur()); } @@ -375,8 +370,8 @@ void BlenderSync::sync_integrator() integrator->set_ao_bounces(0); } - if (integrator->is_modified()) - integrator->tag_update(scene); + /* UPDATE_NONE as we don't want to tag the integrator as modified, just tag dependent things */ + integrator->tag_update(scene, Integrator::UPDATE_NONE); } /* Film */ @@ -729,7 +724,7 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, scene->film->set_pass_alpha_threshold(b_view_layer.pass_alpha_threshold()); scene->film->tag_passes_update(scene, passes); - scene->integrator->tag_update(scene); + scene->integrator->tag_update(scene, Integrator::UPDATE_ALL); return passes; } diff --git a/intern/cycles/device/device_memory.h b/intern/cycles/device/device_memory.h index 00b2aa864aa..1f63a152458 100644 --- a/intern/cycles/device/device_memory.h +++ b/intern/cycles/device/device_memory.h @@ -259,6 +259,8 @@ class device_memory { device_ptr original_device_ptr; size_t original_device_size; Device *original_device; + bool need_realloc_; + bool modified; }; /* Device Only Memory @@ -329,6 +331,8 @@ template<typename T> class device_vector : public device_memory { { data_type = device_type_traits<T>::data_type; data_elements = device_type_traits<T>::num_elements; + modified = true; + need_realloc_ = true; assert(data_elements > 0); } @@ -347,6 +351,7 @@ template<typename T> class device_vector : public device_memory { device_free(); host_free(); host_pointer = host_alloc(sizeof(T) * new_size); + modified = true; assert(device_pointer == 0); } @@ -400,6 +405,19 @@ template<typename T> class device_vector : public device_memory { assert(device_pointer == 0); } + void give_data(array<T> &to) + { + device_free(); + + to.set_data((T *)host_pointer, data_size); + data_size = 0; + data_width = 0; + data_height = 0; + data_depth = 0; + host_pointer = 0; + assert(device_pointer == 0); + } + /* Free device and host memory. */ void free() { @@ -411,10 +429,40 @@ template<typename T> class device_vector : public device_memory { data_height = 0; data_depth = 0; host_pointer = 0; + modified = true; + need_realloc_ = true; assert(device_pointer == 0); } - size_t size() + void free_if_need_realloc(bool force_free) + { + if (need_realloc_ || force_free) { + free(); + } + } + + bool is_modified() const + { + return modified; + } + + bool need_realloc() + { + return need_realloc_; + } + + void tag_modified() + { + modified = true; + } + + void tag_realloc() + { + need_realloc_ = true; + tag_modified(); + } + + size_t size() const { return data_size; } @@ -432,7 +480,24 @@ template<typename T> class device_vector : public device_memory { void copy_to_device() { - device_copy_to(); + if (data_size != 0) { + device_copy_to(); + } + } + + void copy_to_device_if_modified() + { + if (!modified) { + return; + } + + copy_to_device(); + } + + void clear_modified() + { + modified = false; + need_realloc_ = false; } void copy_from_device() diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp index b478aae9ae2..6a3fbb7772f 100644 --- a/intern/cycles/render/attribute.cpp +++ b/intern/cycles/render/attribute.cpp @@ -28,7 +28,7 @@ CCL_NAMESPACE_BEGIN Attribute::Attribute( ustring name, TypeDesc type, AttributeElement element, Geometry *geom, AttributePrimitive prim) - : name(name), std(ATTR_STD_NONE), type(type), element(element), flags(0) + : name(name), std(ATTR_STD_NONE), type(type), element(element), flags(0), modified(true) { /* string and matrix not supported! */ assert(type == TypeDesc::TypeFloat || type == TypeDesc::TypeColor || @@ -82,6 +82,8 @@ void Attribute::add(const float &f) for (size_t i = 0; i < size; i++) buffer.push_back(data[i]); + + modified = true; } void Attribute::add(const uchar4 &f) @@ -93,6 +95,8 @@ void Attribute::add(const uchar4 &f) for (size_t i = 0; i < size; i++) buffer.push_back(data[i]); + + modified = true; } void Attribute::add(const float2 &f) @@ -104,6 +108,8 @@ void Attribute::add(const float2 &f) for (size_t i = 0; i < size; i++) buffer.push_back(data[i]); + + modified = true; } void Attribute::add(const float3 &f) @@ -115,6 +121,8 @@ void Attribute::add(const float3 &f) for (size_t i = 0; i < size; i++) buffer.push_back(data[i]); + + modified = true; } void Attribute::add(const Transform &f) @@ -126,6 +134,8 @@ void Attribute::add(const Transform &f) for (size_t i = 0; i < size; i++) buffer.push_back(data[i]); + + modified = true; } void Attribute::add(const char *data) @@ -134,6 +144,26 @@ void Attribute::add(const char *data) for (size_t i = 0; i < size; i++) buffer.push_back(data[i]); + + modified = true; +} + +void Attribute::set_data_from(Attribute &&other) +{ + assert(other.std == std); + assert(other.type == type); + assert(other.element == element); + + this->flags = other.flags; + + if (this->buffer.size() != other.buffer.size()) { + this->buffer = std::move(other.buffer); + modified = true; + } + else if (memcmp(this->data(), other.data(), other.buffer.size()) != 0) { + this->buffer = std::move(other.buffer); + modified = true; + } } size_t Attribute::data_sizeof() const @@ -627,6 +657,49 @@ void AttributeSet::clear(bool preserve_voxel_data) } } +void AttributeSet::update(AttributeSet &&new_attributes) +{ + /* add or update old_attributes based on the new_attributes */ + foreach (Attribute &attr, new_attributes.attributes) { + Attribute *nattr = nullptr; + + if (attr.std != ATTR_STD_NONE) { + nattr = add(attr.std, attr.name); + } + else { + nattr = add(attr.name, attr.type, attr.element); + } + + nattr->set_data_from(std::move(attr)); + } + + /* remove any attributes not on new_attributes */ + list<Attribute>::iterator it; + for (it = attributes.begin(); it != attributes.end();) { + if (it->std != ATTR_STD_NONE) { + if (new_attributes.find(it->std) == nullptr) { + attributes.erase(it++); + continue; + } + } + else if (it->name != "") { + if (new_attributes.find(it->name) == nullptr) { + attributes.erase(it++); + continue; + } + } + + it++; + } +} + +void AttributeSet::clear_modified() +{ + foreach (Attribute &attr, attributes) { + attr.modified = false; + } +} + /* AttributeRequest */ AttributeRequest::AttributeRequest(ustring name_) diff --git a/intern/cycles/render/attribute.h b/intern/cycles/render/attribute.h index 9990a1325a7..f9997d3c422 100644 --- a/intern/cycles/render/attribute.h +++ b/intern/cycles/render/attribute.h @@ -54,6 +54,8 @@ class Attribute { AttributeElement element; uint flags; /* enum AttributeFlag */ + bool modified; + Attribute(ustring name, TypeDesc type, AttributeElement element, @@ -159,6 +161,8 @@ class Attribute { void add(const Transform &tfm); void add(const char *data); + void set_data_from(Attribute &&other); + static bool same_storage(TypeDesc a, TypeDesc b); static const char *standard_name(AttributeStandard std); static AttributeStandard name_standard(const char *name); @@ -194,6 +198,12 @@ class AttributeSet { void resize(bool reserve_only = false); void clear(bool preserve_voxel_data = false); + + /* Update the attributes in this AttributeSet with the ones from the new set, + * and remove any attribute not found on the new set from this. */ + void update(AttributeSet &&new_attributes); + + void clear_modified(); }; /* AttributeRequest diff --git a/intern/cycles/render/background.cpp b/intern/cycles/render/background.cpp index 7bdcb1578c3..1303f894912 100644 --- a/intern/cycles/render/background.cpp +++ b/intern/cycles/render/background.cpp @@ -130,8 +130,9 @@ void Background::device_free(Device * /*device*/, DeviceScene * /*dscene*/) void Background::tag_update(Scene *scene) { - scene->integrator->tag_update(scene); - tag_modified(); + if (ao_factor_is_modified() || use_ao_is_modified()) { + scene->integrator->tag_update(scene, Integrator::BACKGROUND_AO_MODIFIED); + } } Shader *Background::get_shader(const Scene *scene) diff --git a/intern/cycles/render/bake.cpp b/intern/cycles/render/bake.cpp index 439ebdedb8e..317a3937cab 100644 --- a/intern/cycles/render/bake.cpp +++ b/intern/cycles/render/bake.cpp @@ -78,7 +78,7 @@ BakeManager::BakeManager() type = SHADER_EVAL_BAKE; pass_filter = 0; - need_update = true; + need_update_ = true; } BakeManager::~BakeManager() @@ -114,9 +114,9 @@ void BakeManager::set(Scene *scene, /* create device and update scene */ scene->film->tag_modified(); - scene->integrator->tag_update(scene); + scene->integrator->tag_update(scene, Integrator::UPDATE_ALL); - need_update = true; + need_update_ = true; } void BakeManager::device_update(Device * /*device*/, @@ -124,7 +124,7 @@ void BakeManager::device_update(Device * /*device*/, Scene *scene, Progress & /* progress */) { - if (!need_update) + if (!need_update()) return; scoped_callback_timer timer([scene](double time) { @@ -152,11 +152,21 @@ void BakeManager::device_update(Device * /*device*/, object_index++; } - need_update = false; + need_update_ = false; } void BakeManager::device_free(Device * /*device*/, DeviceScene * /*dscene*/) { } +void BakeManager::tag_update() +{ + need_update_ = true; +} + +bool BakeManager::need_update() const +{ + return need_update_; +} + CCL_NAMESPACE_END diff --git a/intern/cycles/render/bake.h b/intern/cycles/render/bake.h index 93e664c2ab1..655b9b1cf7e 100644 --- a/intern/cycles/render/bake.h +++ b/intern/cycles/render/bake.h @@ -36,9 +36,12 @@ class BakeManager { void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress); void device_free(Device *device, DeviceScene *dscene); - bool need_update; + void tag_update(); + + bool need_update() const; private: + bool need_update_; ShaderEvalType type; int pass_filter; std::string object_name; diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp index 5c3778f6ae5..9b7657802d6 100644 --- a/intern/cycles/render/film.cpp +++ b/intern/cycles/render/film.cpp @@ -688,16 +688,16 @@ void Film::device_free(Device * /*device*/, DeviceScene * /*dscene*/, Scene *sce void Film::tag_passes_update(Scene *scene, const vector<Pass> &passes_, bool update_passes) { if (Pass::contains(scene->passes, PASS_UV) != Pass::contains(passes_, PASS_UV)) { - scene->geometry_manager->tag_update(scene); + scene->geometry_manager->tag_update(scene, GeometryManager::UV_PASS_NEEDED); foreach (Shader *shader, scene->shaders) - shader->need_update_geometry = true; + shader->need_update_uvs = true; } else if (Pass::contains(scene->passes, PASS_MOTION) != Pass::contains(passes_, PASS_MOTION)) { - scene->geometry_manager->tag_update(scene); + scene->geometry_manager->tag_update(scene, GeometryManager::MOTION_PASS_NEEDED); } else if (Pass::contains(scene->passes, PASS_AO) != Pass::contains(passes_, PASS_AO)) { - scene->integrator->tag_update(scene); + scene->integrator->tag_update(scene, Integrator::AO_PASS_MODIFIED); } if (update_passes) { diff --git a/intern/cycles/render/geometry.cpp b/intern/cycles/render/geometry.cpp index 6fc217f2d76..38e84cfa8f3 100644 --- a/intern/cycles/render/geometry.cpp +++ b/intern/cycles/render/geometry.cpp @@ -240,7 +240,6 @@ void Geometry::compute_bvh( } } - clear_modified(); need_update_rebuild = false; } @@ -262,22 +261,21 @@ bool Geometry::has_voxel_attributes() const void Geometry::tag_update(Scene *scene, bool rebuild) { - tag_modified(); - if (rebuild) { need_update_rebuild = true; - scene->light_manager->need_update = true; + scene->light_manager->tag_update(scene, LightManager::MESH_NEED_REBUILD); } else { foreach (Node *node, used_shaders) { Shader *shader = static_cast<Shader *>(node); - if (shader->has_surface_emission) - scene->light_manager->need_update = true; + if (shader->has_surface_emission) { + scene->light_manager->tag_update(scene, LightManager::EMISSIVE_MESH_MODIFIED); + break; + } } } - scene->geometry_manager->need_update = true; - scene->object_manager->need_update = true; + scene->geometry_manager->tag_update(scene, GeometryManager::GEOMETRY_MODIFIED); } void Geometry::tag_bvh_update(bool rebuild) @@ -293,7 +291,7 @@ void Geometry::tag_bvh_update(bool rebuild) GeometryManager::GeometryManager() { - need_update = true; + update_flags = UPDATE_ALL; need_flags_update = true; } @@ -494,6 +492,10 @@ void GeometryManager::update_svm_attributes(Device *, if (attr_map_size == 0) return; + if (!dscene->attributes_map.need_realloc()) { + return; + } + /* create attribute map */ uint4 *attr_map = dscene->attributes_map.alloc(attr_map_size); memset(attr_map, 0, dscene->attributes_map.size() * sizeof(uint)); @@ -602,8 +604,10 @@ void GeometryManager::update_attribute_element_offset(Geometry *geom, offset = attr_uchar4_offset; assert(attr_uchar4.size() >= offset + size); - for (size_t k = 0; k < size; k++) { - attr_uchar4[offset + k] = data[k]; + if (mattr->modified) { + for (size_t k = 0; k < size; k++) { + attr_uchar4[offset + k] = data[k]; + } } attr_uchar4_offset += size; } @@ -612,8 +616,10 @@ void GeometryManager::update_attribute_element_offset(Geometry *geom, offset = attr_float_offset; assert(attr_float.size() >= offset + size); - for (size_t k = 0; k < size; k++) { - attr_float[offset + k] = data[k]; + if (mattr->modified) { + for (size_t k = 0; k < size; k++) { + attr_float[offset + k] = data[k]; + } } attr_float_offset += size; } @@ -622,8 +628,10 @@ void GeometryManager::update_attribute_element_offset(Geometry *geom, offset = attr_float2_offset; assert(attr_float2.size() >= offset + size); - for (size_t k = 0; k < size; k++) { - attr_float2[offset + k] = data[k]; + if (mattr->modified) { + for (size_t k = 0; k < size; k++) { + attr_float2[offset + k] = data[k]; + } } attr_float2_offset += size; } @@ -632,8 +640,10 @@ void GeometryManager::update_attribute_element_offset(Geometry *geom, offset = attr_float3_offset; assert(attr_float3.size() >= offset + size * 3); - for (size_t k = 0; k < size * 3; k++) { - attr_float3[offset + k] = (&tfm->x)[k]; + if (mattr->modified) { + for (size_t k = 0; k < size * 3; k++) { + attr_float3[offset + k] = (&tfm->x)[k]; + } } attr_float3_offset += size * 3; } @@ -642,8 +652,10 @@ void GeometryManager::update_attribute_element_offset(Geometry *geom, offset = attr_float3_offset; assert(attr_float3.size() >= offset + size); - for (size_t k = 0; k < size; k++) { - attr_float3[offset + k] = data[k]; + if (mattr->modified) { + for (size_t k = 0; k < size; k++) { + attr_float3[offset + k] = data[k]; + } } attr_float3_offset += size; } @@ -808,6 +820,11 @@ void GeometryManager::device_update_attributes(Device *device, dscene->attributes_float3.alloc(attr_float3_size); dscene->attributes_uchar4.alloc(attr_uchar4_size); + const bool copy_all_data = dscene->attributes_float.need_realloc() || + dscene->attributes_float2.need_realloc() || + dscene->attributes_float3.need_realloc() || + dscene->attributes_uchar4.need_realloc(); + size_t attr_float_offset = 0; size_t attr_float2_offset = 0; size_t attr_float3_offset = 0; @@ -822,6 +839,12 @@ void GeometryManager::device_update_attributes(Device *device, * they actually refer to the same mesh attributes, optimize */ foreach (AttributeRequest &req, attributes.requests) { Attribute *attr = geom->attributes.find(req); + + if (attr) { + /* force a copy if we need to reallocate all the data */ + attr->modified |= copy_all_data; + } + update_attribute_element_offset(geom, dscene->attributes_float, attr_float_offset, @@ -840,6 +863,11 @@ void GeometryManager::device_update_attributes(Device *device, Mesh *mesh = static_cast<Mesh *>(geom); Attribute *subd_attr = mesh->subd_attributes.find(req); + if (subd_attr) { + /* force a copy if we need to reallocate all the data */ + subd_attr->modified |= copy_all_data; + } + update_attribute_element_offset(mesh, dscene->attributes_float, attr_float_offset, @@ -903,18 +931,10 @@ void GeometryManager::device_update_attributes(Device *device, /* copy to device */ progress.set_status("Updating Mesh", "Copying Attributes to device"); - if (dscene->attributes_float.size()) { - dscene->attributes_float.copy_to_device(); - } - if (dscene->attributes_float2.size()) { - dscene->attributes_float2.copy_to_device(); - } - if (dscene->attributes_float3.size()) { - dscene->attributes_float3.copy_to_device(); - } - if (dscene->attributes_uchar4.size()) { - dscene->attributes_uchar4.copy_to_device(); - } + dscene->attributes_float.copy_to_device(); + dscene->attributes_float2.copy_to_device(); + dscene->attributes_float3.copy_to_device(); + dscene->attributes_uchar4.copy_to_device(); if (progress.get_cancel()) return; @@ -1066,17 +1086,34 @@ void GeometryManager::device_update_mesh( uint *tri_patch = dscene->tri_patch.alloc(tri_size); float2 *tri_patch_uv = dscene->tri_patch_uv.alloc(vert_size); + const bool copy_all_data = dscene->tri_shader.need_realloc() || + dscene->tri_vindex.need_realloc() || + dscene->tri_vnormal.need_realloc() || + dscene->tri_patch.need_realloc() || + dscene->tri_patch_uv.need_realloc(); + foreach (Geometry *geom, scene->geometry) { if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) { Mesh *mesh = static_cast<Mesh *>(geom); - mesh->pack_shaders(scene, &tri_shader[mesh->prim_offset]); - mesh->pack_normals(&vnormal[mesh->vert_offset]); - mesh->pack_verts(tri_prim_index, - &tri_vindex[mesh->prim_offset], - &tri_patch[mesh->prim_offset], - &tri_patch_uv[mesh->vert_offset], - mesh->vert_offset, - mesh->prim_offset); + + if (mesh->shader_is_modified() || mesh->smooth_is_modified() || + mesh->triangles_is_modified() || copy_all_data) { + mesh->pack_shaders(scene, &tri_shader[mesh->prim_offset]); + } + + if (mesh->verts_is_modified() || copy_all_data) { + mesh->pack_normals(&vnormal[mesh->vert_offset]); + } + + if (mesh->triangles_is_modified() || mesh->vert_patch_uv_is_modified() || copy_all_data) { + mesh->pack_verts(tri_prim_index, + &tri_vindex[mesh->prim_offset], + &tri_patch[mesh->prim_offset], + &tri_patch_uv[mesh->vert_offset], + mesh->vert_offset, + mesh->prim_offset); + } + if (progress.get_cancel()) return; } @@ -1085,11 +1122,11 @@ void GeometryManager::device_update_mesh( /* vertex coordinates */ progress.set_status("Updating Mesh", "Copying Mesh to device"); - dscene->tri_shader.copy_to_device(); - dscene->tri_vnormal.copy_to_device(); - dscene->tri_vindex.copy_to_device(); - dscene->tri_patch.copy_to_device(); - dscene->tri_patch_uv.copy_to_device(); + dscene->tri_shader.copy_to_device_if_modified(); + dscene->tri_vnormal.copy_to_device_if_modified(); + dscene->tri_vindex.copy_to_device_if_modified(); + dscene->tri_patch.copy_to_device_if_modified(); + dscene->tri_patch_uv.copy_to_device_if_modified(); } if (curve_size != 0) { @@ -1098,9 +1135,21 @@ void GeometryManager::device_update_mesh( float4 *curve_keys = dscene->curve_keys.alloc(curve_key_size); float4 *curves = dscene->curves.alloc(curve_size); + const bool copy_all_data = dscene->curve_keys.need_realloc() || dscene->curves.need_realloc(); + foreach (Geometry *geom, scene->geometry) { if (geom->is_hair()) { Hair *hair = static_cast<Hair *>(geom); + + bool curve_keys_co_modified = hair->curve_radius_is_modified() || + hair->curve_keys_is_modified(); + bool curve_data_modified = hair->curve_shader_is_modified() || + hair->curve_first_key_is_modified(); + + if (!curve_keys_co_modified && !curve_data_modified && !copy_all_data) { + continue; + } + hair->pack_curves(scene, &curve_keys[hair->curvekey_offset], &curves[hair->prim_offset], @@ -1110,11 +1159,11 @@ void GeometryManager::device_update_mesh( } } - dscene->curve_keys.copy_to_device(); - dscene->curves.copy_to_device(); + dscene->curve_keys.copy_to_device_if_modified(); + dscene->curves.copy_to_device_if_modified(); } - if (patch_size != 0) { + if (patch_size != 0 && dscene->patches.need_realloc()) { progress.set_status("Updating Mesh", "Copying Patches to device"); uint *patch_data = dscene->patches.alloc(patch_size); @@ -1180,16 +1229,25 @@ void GeometryManager::device_update_bvh(Device *device, VLOG(1) << "Using " << bvh_layout_name(bparams.bvh_layout) << " layout."; - delete scene->bvh; - BVH *bvh = scene->bvh = BVH::create(bparams, scene->geometry, scene->objects, device); - device->build_bvh(bvh, progress, false); + const bool can_refit = scene->bvh != nullptr && + (bparams.bvh_layout == BVHLayout::BVH_LAYOUT_OPTIX); + const bool pack_all = scene->bvh == nullptr; + + BVH *bvh = scene->bvh; + if (!scene->bvh) { + bvh = scene->bvh = BVH::create(bparams, scene->geometry, scene->objects, device); + } + + device->build_bvh(bvh, progress, can_refit); if (progress.get_cancel()) { return; } + const bool has_bvh2_layout = (bparams.bvh_layout == BVH_LAYOUT_BVH2); + PackedBVH pack; - if (bparams.bvh_layout == BVH_LAYOUT_BVH2) { + if (has_bvh2_layout) { pack = std::move(static_cast<BVH2 *>(bvh)->pack); } else { @@ -1210,12 +1268,22 @@ void GeometryManager::device_update_bvh(Device *device, } pack.root_index = -1; - pack.prim_tri_index.reserve(num_prims); - pack.prim_tri_verts.reserve(num_tri_verts); - pack.prim_type.reserve(num_prims); - pack.prim_index.reserve(num_prims); - pack.prim_object.reserve(num_prims); - pack.prim_visibility.reserve(num_prims); + + if (!pack_all) { + /* if we do not need to recreate the BVH, then only the vertices are updated, so we can + * safely retake the memory */ + dscene->prim_tri_verts.give_data(pack.prim_tri_verts); + } + else { + /* it is not stricly necessary to skip those resizes we if do not have to repack, as the OS + * will not allocate pages if we do not touch them, however it does help catching bugs */ + pack.prim_tri_index.resize(num_prims); + pack.prim_tri_verts.resize(num_tri_verts); + pack.prim_type.resize(num_prims); + pack.prim_index.resize(num_prims); + pack.prim_object.resize(num_prims); + pack.prim_visibility.resize(num_prims); + } // Merge visibility flags of all objects and find object index for non-instanced geometry unordered_map<const Geometry *, pair<int, uint>> geometry_to_object_info; @@ -1229,17 +1297,27 @@ void GeometryManager::device_update_bvh(Device *device, } } + TaskPool pool; // Iterate over scene mesh list instead of objects, since 'optix_prim_offset' was calculated // based on that list, which may be ordered differently from the object list. foreach (Geometry *geom, scene->geometry) { + if (!pack_all && !geom->is_modified()) { + continue; + } + const pair<int, uint> &info = geometry_to_object_info[geom]; - geom->pack_primitives(pack, info.first, info.second); + pool.push(function_bind( + &Geometry::pack_primitives, geom, &pack, info.first, info.second, pack_all)); } + pool.wait_work(); } /* copy to device */ progress.set_status("Updating Scene BVH", "Copying BVH to device"); + /* When using BVH2, we always have to copy/update the data as its layout is dependent on the + * BVH's leaf nodes which may be different when the objects or vertices move. */ + if (pack.nodes.size()) { dscene->bvh_nodes.steal_data(pack.nodes); dscene->bvh_nodes.copy_to_device(); @@ -1252,7 +1330,7 @@ void GeometryManager::device_update_bvh(Device *device, dscene->object_node.steal_data(pack.object_node); dscene->object_node.copy_to_device(); } - if (pack.prim_tri_index.size()) { + if (pack.prim_tri_index.size() && (dscene->prim_tri_index.need_realloc() || has_bvh2_layout)) { dscene->prim_tri_index.steal_data(pack.prim_tri_index); dscene->prim_tri_index.copy_to_device(); } @@ -1260,23 +1338,23 @@ void GeometryManager::device_update_bvh(Device *device, dscene->prim_tri_verts.steal_data(pack.prim_tri_verts); dscene->prim_tri_verts.copy_to_device(); } - if (pack.prim_type.size()) { + if (pack.prim_type.size() && (dscene->prim_type.need_realloc() || has_bvh2_layout)) { dscene->prim_type.steal_data(pack.prim_type); dscene->prim_type.copy_to_device(); } - if (pack.prim_visibility.size()) { + if (pack.prim_visibility.size() && (dscene->prim_visibility.need_realloc() || has_bvh2_layout)) { dscene->prim_visibility.steal_data(pack.prim_visibility); dscene->prim_visibility.copy_to_device(); } - if (pack.prim_index.size()) { + if (pack.prim_index.size() && (dscene->prim_index.need_realloc() || has_bvh2_layout)) { dscene->prim_index.steal_data(pack.prim_index); dscene->prim_index.copy_to_device(); } - if (pack.prim_object.size()) { + if (pack.prim_object.size() && (dscene->prim_object.need_realloc() || has_bvh2_layout)) { dscene->prim_object.steal_data(pack.prim_object); dscene->prim_object.copy_to_device(); } - if (pack.prim_time.size()) { + if (pack.prim_time.size() && (dscene->prim_time.need_realloc() || has_bvh2_layout)) { dscene->prim_time.steal_data(pack.prim_time); dscene->prim_time.copy_to_device(); } @@ -1289,12 +1367,65 @@ void GeometryManager::device_update_bvh(Device *device, dscene->data.bvh.scene = NULL; } +/* Set of flags used to help determining what data has been modified or needs reallocation, so we + * can decide which device data to free or update. */ +enum { + DEVICE_CURVE_DATA_MODIFIED = (1 << 0), + DEVICE_MESH_DATA_MODIFIED = (1 << 1), + + ATTR_FLOAT_MODIFIED = (1 << 2), + ATTR_FLOAT2_MODIFIED = (1 << 3), + ATTR_FLOAT3_MODIFIED = (1 << 4), + ATTR_UCHAR4_MODIFIED = (1 << 5), + + CURVE_DATA_NEED_REALLOC = (1 << 6), + MESH_DATA_NEED_REALLOC = (1 << 7), + + ATTR_FLOAT_NEEDS_REALLOC = (1 << 8), + ATTR_FLOAT2_NEEDS_REALLOC = (1 << 9), + ATTR_FLOAT3_NEEDS_REALLOC = (1 << 10), + ATTR_UCHAR4_NEEDS_REALLOC = (1 << 11), + + ATTRS_NEED_REALLOC = (ATTR_FLOAT_NEEDS_REALLOC | ATTR_FLOAT2_NEEDS_REALLOC | + ATTR_FLOAT3_NEEDS_REALLOC | ATTR_UCHAR4_NEEDS_REALLOC), + DEVICE_MESH_DATA_NEEDS_REALLOC = (CURVE_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC), + DEVICE_CURVE_DATA_NEEDS_REALLOC = (MESH_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC), +}; + +static void update_device_flags_attribute(uint32_t &device_update_flags, + const AttributeSet &attributes) +{ + foreach (const Attribute &attr, attributes.attributes) { + if (!attr.modified) { + continue; + } + + if (attr.element == ATTR_ELEMENT_CORNER) { + device_update_flags |= ATTR_UCHAR4_MODIFIED; + } + else if (attr.type == TypeDesc::TypeFloat) { + device_update_flags |= ATTR_FLOAT_MODIFIED; + } + else if (attr.type == TypeFloat2) { + device_update_flags |= ATTR_FLOAT2_MODIFIED; + } + else if (attr.type == TypeDesc::TypeMatrix) { + device_update_flags |= ATTR_FLOAT3_MODIFIED; + } + else if (attr.element != ATTR_ELEMENT_VOXEL) { + device_update_flags |= ATTR_FLOAT3_MODIFIED; + } + } +} + void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Progress &progress) { - if (!need_update && !need_flags_update) { + if (!need_update() && !need_flags_update) { return; } + uint32_t device_update_flags = 0; + scoped_callback_timer timer([scene](double time) { if (scene->update_stats) { scene->update_stats->geometry.times.add_entry({"device_update_preprocess", time}); @@ -1314,9 +1445,54 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro if (shader->has_volume) { geom->has_volume = true; } + if (shader->has_surface_bssrdf) { geom->has_surface_bssrdf = true; } + + if (shader->need_update_uvs) { + device_update_flags |= ATTR_FLOAT2_NEEDS_REALLOC; + + /* Attributes might need to be tesselated if added. */ + if (geom->is_mesh()) { + Mesh *mesh = static_cast<Mesh *>(geom); + if (mesh->need_tesselation()) { + mesh->tag_modified(); + } + } + } + + if (shader->need_update_attribute) { + device_update_flags |= ATTRS_NEED_REALLOC; + + /* Attributes might need to be tesselated if added. */ + if (geom->is_mesh()) { + Mesh *mesh = static_cast<Mesh *>(geom); + if (mesh->need_tesselation()) { + mesh->tag_modified(); + } + } + } + + if (shader->need_update_displacement) { + /* tag displacement related sockets as modified */ + if (geom->is_mesh()) { + Mesh *mesh = static_cast<Mesh *>(geom); + mesh->tag_verts_modified(); + mesh->tag_subd_dicing_rate_modified(); + mesh->tag_subd_max_level_modified(); + mesh->tag_subd_objecttoworld_modified(); + + device_update_flags |= ATTRS_NEED_REALLOC; + } + } + } + + /* only check for modified attributes if we do not need to reallocate them already */ + if ((device_update_flags & ATTRS_NEED_REALLOC) == 0) { + update_device_flags_attribute(device_update_flags, geom->attributes); + /* don't check for subd_attributes, as if they were modified, we would need to reallocate + * anyway */ } /* Re-create volume mesh if we will rebuild or refit the BVH. Note we @@ -1332,13 +1508,118 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro Volume *volume = static_cast<Volume *>(geom); create_volume_mesh(volume, progress); + + /* always reallocate when we have a volume, as we need to rebuild the BVH */ + device_update_flags |= DEVICE_MESH_DATA_NEEDS_REALLOC; } if (geom->is_hair()) { /* Set curve shape, still a global scene setting for now. */ Hair *hair = static_cast<Hair *>(geom); hair->curve_shape = scene->params.hair_shape; + + if (hair->need_update_rebuild) { + device_update_flags |= DEVICE_CURVE_DATA_NEEDS_REALLOC; + } + else if (hair->is_modified()) { + device_update_flags |= DEVICE_CURVE_DATA_MODIFIED; + } } + + if (geom->is_mesh()) { + Mesh *mesh = static_cast<Mesh *>(geom); + + if (mesh->need_update_rebuild) { + device_update_flags |= DEVICE_MESH_DATA_NEEDS_REALLOC; + } + else if (mesh->verts_is_modified()) { + device_update_flags |= DEVICE_MESH_DATA_MODIFIED; + } + } + } + + if (update_flags & (MESH_ADDED | MESH_REMOVED)) { + device_update_flags |= DEVICE_MESH_DATA_NEEDS_REALLOC; + } + + if (update_flags & (HAIR_ADDED | HAIR_REMOVED)) { + device_update_flags |= DEVICE_CURVE_DATA_NEEDS_REALLOC; + } + + /* tag the device arrays for reallocation or modification */ + DeviceScene *dscene = &scene->dscene; + + if (device_update_flags & (DEVICE_MESH_DATA_NEEDS_REALLOC | DEVICE_CURVE_DATA_NEEDS_REALLOC)) { + delete scene->bvh; + scene->bvh = nullptr; + + dscene->bvh_nodes.tag_realloc(); + dscene->bvh_leaf_nodes.tag_realloc(); + dscene->object_node.tag_realloc(); + dscene->prim_tri_verts.tag_realloc(); + dscene->prim_tri_index.tag_realloc(); + dscene->prim_type.tag_realloc(); + dscene->prim_visibility.tag_realloc(); + dscene->prim_index.tag_realloc(); + dscene->prim_object.tag_realloc(); + dscene->prim_time.tag_realloc(); + + if (device_update_flags & DEVICE_MESH_DATA_NEEDS_REALLOC) { + dscene->tri_vnormal.tag_realloc(); + dscene->tri_vindex.tag_realloc(); + dscene->tri_patch.tag_realloc(); + dscene->tri_vnormal.tag_realloc(); + dscene->tri_patch_uv.tag_realloc(); + dscene->patches.tag_realloc(); + } + + if (device_update_flags & DEVICE_CURVE_DATA_NEEDS_REALLOC) { + dscene->curves.tag_realloc(); + dscene->curve_keys.tag_realloc(); + } + } + + if (device_update_flags & ATTR_FLOAT_NEEDS_REALLOC) { + dscene->attributes_map.tag_realloc(); + dscene->attributes_float.tag_realloc(); + } + else if (device_update_flags & ATTR_FLOAT_MODIFIED) { + dscene->attributes_float.tag_modified(); + } + + if (device_update_flags & ATTR_FLOAT2_NEEDS_REALLOC) { + dscene->attributes_map.tag_realloc(); + dscene->attributes_float2.tag_realloc(); + } + else if (device_update_flags & ATTR_FLOAT_MODIFIED) { + dscene->attributes_float.tag_modified(); + } + + if (device_update_flags & ATTR_FLOAT3_NEEDS_REALLOC) { + dscene->attributes_map.tag_realloc(); + dscene->attributes_float3.tag_realloc(); + } + else if (device_update_flags & ATTR_FLOAT_MODIFIED) { + dscene->attributes_float.tag_modified(); + } + + if (device_update_flags & ATTR_UCHAR4_NEEDS_REALLOC) { + dscene->attributes_map.tag_realloc(); + dscene->attributes_uchar4.tag_realloc(); + } + else if (device_update_flags & ATTR_UCHAR4_MODIFIED) { + dscene->attributes_uchar4.tag_modified(); + } + + if (device_update_flags & DEVICE_MESH_DATA_MODIFIED) { + /* if anything else than vertices are modified, we would need to reallocate, so this is the + * only array that can be updated */ + dscene->tri_vnormal.tag_modified(); + } + + if (device_update_flags & DEVICE_CURVE_DATA_MODIFIED) { + dscene->curve_keys.tag_modified(); + dscene->curves.tag_modified(); } need_flags_update = false; @@ -1423,7 +1704,7 @@ void GeometryManager::device_update(Device *device, Scene *scene, Progress &progress) { - if (!need_update) + if (!need_update()) return; VLOG(1) << "Total " << scene->geometry.size() << " meshes."; @@ -1439,12 +1720,6 @@ void GeometryManager::device_update(Device *device, }); foreach (Geometry *geom, scene->geometry) { - foreach (Node *node, geom->get_used_shaders()) { - Shader *shader = static_cast<Shader *>(node); - if (shader->need_update_geometry) - geom->tag_modified(); - } - if (geom->is_modified() && (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME)) { Mesh *mesh = static_cast<Mesh *>(geom); @@ -1541,7 +1816,7 @@ void GeometryManager::device_update(Device *device, } /* Device update. */ - device_free(device, dscene); + device_free(device, dscene, false); const BVHLayout bvh_layout = BVHParams::best_bvh_layout(scene->params.bvh_layout, device->get_bvh_layout_mask()); @@ -1614,7 +1889,7 @@ void GeometryManager::device_update(Device *device, {"device_update (displacement: attributes)", time}); } }); - device_free(device, dscene); + device_free(device, dscene, false); device_update_attributes(device, dscene, scene, progress); if (progress.get_cancel()) { @@ -1622,6 +1897,9 @@ void GeometryManager::device_update(Device *device, } } + /* update the bvh even when there is no geometry so the kernel bvh data is still valid, + * especially when removing all of the objects during interactive renders */ + bool need_update_scene_bvh = (scene->bvh == nullptr); { scoped_callback_timer timer([scene](double time) { if (scene->update_stats) { @@ -1633,6 +1911,7 @@ void GeometryManager::device_update(Device *device, size_t i = 0; foreach (Geometry *geom, scene->geometry) { if (geom->is_modified()) { + need_update_scene_bvh = true; pool.push(function_bind( &Geometry::compute_bvh, geom, device, dscene, &scene->params, &progress, i, num_bvh)); if (geom->need_build_bvh(bvh_layout)) { @@ -1647,7 +1926,9 @@ void GeometryManager::device_update(Device *device, } foreach (Shader *shader, scene->shaders) { - shader->need_update_geometry = false; + shader->need_update_uvs = false; + shader->need_update_attribute = false; + shader->need_update_displacement = false; } Scene::MotionType need_motion = scene->need_motion(); @@ -1670,7 +1951,7 @@ void GeometryManager::device_update(Device *device, return; } - { + if (need_update_scene_bvh) { scoped_callback_timer timer([scene](double time) { if (scene->update_stats) { scene->update_stats->geometry.times.add_entry({"device_update (build scene BVH)", time}); @@ -1695,8 +1976,6 @@ void GeometryManager::device_update(Device *device, } } - need_update = false; - if (true_displacement_used) { /* Re-tag flags for update, so they're re-evaluated * for meshes with correct bounding boxes. @@ -1706,33 +1985,71 @@ void GeometryManager::device_update(Device *device, */ scene->object_manager->need_flags_update = old_need_object_flags_update; } + + /* unset flags */ + + foreach (Geometry *geom, scene->geometry) { + geom->clear_modified(); + geom->attributes.clear_modified(); + + if (geom->is_mesh()) { + Mesh *mesh = static_cast<Mesh *>(geom); + mesh->subd_attributes.clear_modified(); + } + } + + update_flags = UPDATE_NONE; + + dscene->bvh_nodes.clear_modified(); + dscene->bvh_leaf_nodes.clear_modified(); + dscene->object_node.clear_modified(); + dscene->prim_tri_verts.clear_modified(); + dscene->prim_tri_index.clear_modified(); + dscene->prim_type.clear_modified(); + dscene->prim_visibility.clear_modified(); + dscene->prim_index.clear_modified(); + dscene->prim_object.clear_modified(); + dscene->prim_time.clear_modified(); + dscene->tri_shader.clear_modified(); + dscene->tri_vindex.clear_modified(); + dscene->tri_patch.clear_modified(); + dscene->tri_vnormal.clear_modified(); + dscene->tri_patch_uv.clear_modified(); + dscene->curves.clear_modified(); + dscene->curve_keys.clear_modified(); + dscene->patches.clear_modified(); + dscene->attributes_map.clear_modified(); + dscene->attributes_float.clear_modified(); + dscene->attributes_float2.clear_modified(); + dscene->attributes_float3.clear_modified(); + dscene->attributes_uchar4.clear_modified(); } -void GeometryManager::device_free(Device *device, DeviceScene *dscene) +void GeometryManager::device_free(Device *device, DeviceScene *dscene, bool force_free) { - dscene->bvh_nodes.free(); - dscene->bvh_leaf_nodes.free(); - dscene->object_node.free(); - dscene->prim_tri_verts.free(); - dscene->prim_tri_index.free(); - dscene->prim_type.free(); - dscene->prim_visibility.free(); - dscene->prim_index.free(); - dscene->prim_object.free(); - dscene->prim_time.free(); - dscene->tri_shader.free(); - dscene->tri_vnormal.free(); - dscene->tri_vindex.free(); - dscene->tri_patch.free(); - dscene->tri_patch_uv.free(); - dscene->curves.free(); - dscene->curve_keys.free(); - dscene->patches.free(); - dscene->attributes_map.free(); - dscene->attributes_float.free(); - dscene->attributes_float2.free(); - dscene->attributes_float3.free(); - dscene->attributes_uchar4.free(); + dscene->bvh_nodes.free_if_need_realloc(force_free); + dscene->bvh_leaf_nodes.free_if_need_realloc(force_free); + dscene->object_node.free_if_need_realloc(force_free); + dscene->prim_tri_verts.free_if_need_realloc(force_free); + dscene->prim_tri_index.free_if_need_realloc(force_free); + dscene->prim_type.free_if_need_realloc(force_free); + dscene->prim_visibility.free_if_need_realloc(force_free); + dscene->prim_index.free_if_need_realloc(force_free); + dscene->prim_object.free_if_need_realloc(force_free); + dscene->prim_time.free_if_need_realloc(force_free); + dscene->tri_shader.free_if_need_realloc(force_free); + dscene->tri_vnormal.free_if_need_realloc(force_free); + dscene->tri_vindex.free_if_need_realloc(force_free); + dscene->tri_patch.free_if_need_realloc(force_free); + dscene->tri_patch_uv.free_if_need_realloc(force_free); + dscene->curves.free_if_need_realloc(force_free); + dscene->curve_keys.free_if_need_realloc(force_free); + dscene->patches.free_if_need_realloc(force_free); + dscene->attributes_map.free_if_need_realloc(force_free); + dscene->attributes_float.free_if_need_realloc(force_free); + dscene->attributes_float2.free_if_need_realloc(force_free); + dscene->attributes_float3.free_if_need_realloc(force_free); + dscene->attributes_uchar4.free_if_need_realloc(force_free); /* Signal for shaders like displacement not to do ray tracing. */ dscene->data.bvh.bvh_layout = BVH_LAYOUT_NONE; @@ -1750,10 +2067,19 @@ void GeometryManager::device_free(Device *device, DeviceScene *dscene) #endif } -void GeometryManager::tag_update(Scene *scene) +void GeometryManager::tag_update(Scene *scene, uint32_t flag) +{ + update_flags |= flag; + + /* do not tag the object manager for an update if it is the one who tagged us */ + if ((flag & OBJECT_MANAGER) == 0) { + scene->object_manager->tag_update(scene, ObjectManager::GEOMETRY_MANAGER); + } +} + +bool GeometryManager::need_update() const { - need_update = true; - scene->object_manager->need_update = true; + return update_flags != UPDATE_NONE; } void GeometryManager::collect_statistics(const Scene *scene, RenderStats *stats) diff --git a/intern/cycles/render/geometry.h b/intern/cycles/render/geometry.h index b124e950ad2..88388f31a9b 100644 --- a/intern/cycles/render/geometry.h +++ b/intern/cycles/render/geometry.h @@ -125,7 +125,7 @@ class Geometry : public Node { int n, int total); - virtual void pack_primitives(PackedBVH &pack, int object, uint visibility) = 0; + virtual void pack_primitives(PackedBVH *pack, int object, uint visibility, bool pack_all) = 0; /* Check whether the geometry should have own BVH built separately. Briefly, * own BVH is needed for geometry, if: @@ -155,6 +155,11 @@ class Geometry : public Node { return geometry_type == HAIR; } + bool is_volume() const + { + return geometry_type == VOLUME; + } + /* Updates */ void tag_update(Scene *scene, bool rebuild); @@ -164,9 +169,32 @@ class Geometry : public Node { /* Geometry Manager */ class GeometryManager { + uint32_t update_flags; + public: + enum : uint32_t { + UV_PASS_NEEDED = (1 << 0), + MOTION_PASS_NEEDED = (1 << 1), + GEOMETRY_MODIFIED = (1 << 2), + OBJECT_MANAGER = (1 << 3), + MESH_ADDED = (1 << 4), + MESH_REMOVED = (1 << 5), + HAIR_ADDED = (1 << 6), + HAIR_REMOVED = (1 << 7), + + SHADER_ATTRIBUTE_MODIFIED = (1 << 8), + SHADER_DISPLACEMENT_MODIFIED = (1 << 9), + + GEOMETRY_ADDED = MESH_ADDED | HAIR_ADDED, + GEOMETRY_REMOVED = MESH_REMOVED | HAIR_REMOVED, + + /* tag everything in the manager for an update */ + UPDATE_ALL = ~0u, + + UPDATE_NONE = 0u, + }; + /* Update Flags */ - bool need_update; bool need_flags_update; /* Constructor/Destructor */ @@ -176,10 +204,12 @@ class GeometryManager { /* Device Updates */ void device_update_preprocess(Device *device, Scene *scene, Progress &progress); void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress); - void device_free(Device *device, DeviceScene *dscene); + void device_free(Device *device, DeviceScene *dscene, bool force_free); /* Updates */ - void tag_update(Scene *scene); + void tag_update(Scene *scene, uint32_t flag); + + bool need_update() const; /* Statistics */ void collect_statistics(const Scene *scene, RenderStats *stats); diff --git a/intern/cycles/render/hair.cpp b/intern/cycles/render/hair.cpp index 896e798b6f9..e94cad6b32e 100644 --- a/intern/cycles/render/hair.cpp +++ b/intern/cycles/render/hair.cpp @@ -494,33 +494,38 @@ void Hair::pack_curves(Scene *scene, } } -void Hair::pack_primitives(PackedBVH &pack, int object, uint visibility) +void Hair::pack_primitives(PackedBVH *pack, int object, uint visibility, bool pack_all) { if (curve_first_key.empty()) return; - const size_t num_prims = num_segments(); - pack.prim_tri_index.reserve(pack.prim_tri_index.size() + num_prims); - pack.prim_type.reserve(pack.prim_type.size() + num_prims); - pack.prim_visibility.reserve(pack.prim_visibility.size() + num_prims); - pack.prim_index.reserve(pack.prim_index.size() + num_prims); - pack.prim_object.reserve(pack.prim_object.size() + num_prims); - // 'pack.prim_time' is unused by Embree and OptiX + /* If the BVH does not have to be recreated, we can bail out. */ + if (!pack_all) { + return; + } + + unsigned int *prim_tri_index = &pack->prim_tri_index[optix_prim_offset]; + int *prim_type = &pack->prim_type[optix_prim_offset]; + unsigned int *prim_visibility = &pack->prim_visibility[optix_prim_offset]; + int *prim_index = &pack->prim_index[optix_prim_offset]; + int *prim_object = &pack->prim_object[optix_prim_offset]; + // 'pack->prim_time' is unused by Embree and OptiX uint type = has_motion_blur() ? ((curve_shape == CURVE_RIBBON) ? PRIMITIVE_MOTION_CURVE_RIBBON : PRIMITIVE_MOTION_CURVE_THICK) : ((curve_shape == CURVE_RIBBON) ? PRIMITIVE_CURVE_RIBBON : PRIMITIVE_CURVE_THICK); + size_t index = 0; for (size_t j = 0; j < num_curves(); ++j) { Curve curve = get_curve(j); - for (size_t k = 0; k < curve.num_segments(); ++k) { - pack.prim_tri_index.push_back_reserved(-1); - pack.prim_type.push_back_reserved(PRIMITIVE_PACK_SEGMENT(type, k)); - pack.prim_visibility.push_back_reserved(visibility); + for (size_t k = 0; k < curve.num_segments(); ++k, ++index) { + prim_tri_index[index] = -1; + prim_type[index] = PRIMITIVE_PACK_SEGMENT(type, k); + prim_visibility[index] = visibility; // Each curve segment points back to its curve index - pack.prim_index.push_back_reserved(j + prim_offset); - pack.prim_object.push_back_reserved(object); + prim_index[index] = j + prim_offset; + prim_object[index] = object; } } } diff --git a/intern/cycles/render/hair.h b/intern/cycles/render/hair.h index c7be08d679c..4b949f984e5 100644 --- a/intern/cycles/render/hair.h +++ b/intern/cycles/render/hair.h @@ -146,7 +146,7 @@ class Hair : public Geometry { /* BVH */ void pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset); - void pack_primitives(PackedBVH &pack, int object, uint visibility) override; + void pack_primitives(PackedBVH *pack, int object, uint visibility, bool pack_all) override; }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index 30858c4f68b..a09a680f93f 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -298,7 +298,7 @@ bool ImageLoader::is_vdb_loader() const ImageManager::ImageManager(const DeviceInfo &info) { - need_update = true; + need_update_ = true; osl_texture_system = NULL; animation_frame = 0; @@ -451,7 +451,7 @@ int ImageManager::add_image_slot(ImageLoader *loader, images[slot] = img; - need_update = true; + need_update_ = true; return slot; } @@ -478,7 +478,7 @@ void ImageManager::remove_image_user(int slot) * the reasons for this is that on shader changes we add and remove nodes * that use them, but we do not want to reload the image all the time. */ if (image->users == 0) - need_update = true; + need_update_ = true; } static bool image_associate_alpha(ImageManager::Image *img) @@ -810,7 +810,7 @@ void ImageManager::device_free_image(Device *, int slot) void ImageManager::device_update(Device *device, Scene *scene, Progress &progress) { - if (!need_update) { + if (!need_update()) { return; } @@ -834,7 +834,7 @@ void ImageManager::device_update(Device *device, Scene *scene, Progress &progres pool.wait_work(); - need_update = false; + need_update_ = false; } void ImageManager::device_update_slot(Device *device, Scene *scene, int slot, Progress *progress) @@ -854,7 +854,7 @@ void ImageManager::device_load_builtin(Device *device, Scene *scene, Progress &p { /* Load only builtin images, Blender needs this to load evaluated * scene data from depsgraph before it is freed. */ - if (!need_update) { + if (!need_update()) { return; } @@ -896,4 +896,14 @@ void ImageManager::collect_statistics(RenderStats *stats) } } +void ImageManager::tag_update() +{ + need_update_ = true; +} + +bool ImageManager::need_update() const +{ + return need_update_; +} + CCL_NAMESPACE_END diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index 6ac1db9ed63..c802521db56 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -189,7 +189,9 @@ class ImageManager { void collect_statistics(RenderStats *stats); - bool need_update; + void tag_update(); + + bool need_update() const; struct Image { ImageParams params; @@ -209,6 +211,7 @@ class ImageManager { }; private: + bool need_update_; bool has_half_images; thread_mutex device_mutex; diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp index e5b9e6bfabf..c97a6549653 100644 --- a/intern/cycles/render/integrator.cpp +++ b/intern/cycles/render/integrator.cpp @@ -17,9 +17,11 @@ #include "render/integrator.h" #include "device/device.h" #include "render/background.h" +#include "render/camera.h" #include "render/film.h" #include "render/jitter.h" #include "render/light.h" +#include "render/object.h" #include "render/scene.h" #include "render/shader.h" #include "render/sobol.h" @@ -113,6 +115,10 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene } }); + if (sampling_pattern_is_modified()) { + dscene->sample_pattern_lut.tag_realloc(); + } + device_free(device, dscene); KernelIntegrator *kintegrator = &dscene->data.integrator; @@ -242,45 +248,63 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene int dimensions = PRNG_BASE_NUM + max_samples * PRNG_BOUNCE_NUM; dimensions = min(dimensions, SOBOL_MAX_DIMENSIONS); - if (sampling_pattern == SAMPLING_PATTERN_SOBOL) { - uint *directions = dscene->sample_pattern_lut.alloc(SOBOL_BITS * dimensions); + if (sampling_pattern_is_modified()) { + if (sampling_pattern == SAMPLING_PATTERN_SOBOL) { + uint *directions = dscene->sample_pattern_lut.alloc(SOBOL_BITS * dimensions); - sobol_generate_direction_vectors((uint(*)[SOBOL_BITS])directions, dimensions); + sobol_generate_direction_vectors((uint(*)[SOBOL_BITS])directions, dimensions); - dscene->sample_pattern_lut.copy_to_device(); - } - else { - constexpr int sequence_size = NUM_PMJ_SAMPLES; - constexpr int num_sequences = NUM_PMJ_PATTERNS; - float2 *directions = (float2 *)dscene->sample_pattern_lut.alloc(sequence_size * num_sequences * - 2); - TaskPool pool; - for (int j = 0; j < num_sequences; ++j) { - float2 *sequence = directions + j * sequence_size; - pool.push( - function_bind(&progressive_multi_jitter_02_generate_2D, sequence, sequence_size, j)); + dscene->sample_pattern_lut.copy_to_device(); + } + else { + constexpr int sequence_size = NUM_PMJ_SAMPLES; + constexpr int num_sequences = NUM_PMJ_PATTERNS; + float2 *directions = (float2 *)dscene->sample_pattern_lut.alloc(sequence_size * + num_sequences * 2); + TaskPool pool; + for (int j = 0; j < num_sequences; ++j) { + float2 *sequence = directions + j * sequence_size; + pool.push( + function_bind(&progressive_multi_jitter_02_generate_2D, sequence, sequence_size, j)); + } + pool.wait_work(); + dscene->sample_pattern_lut.copy_to_device(); } - pool.wait_work(); - dscene->sample_pattern_lut.copy_to_device(); } clear_modified(); } -void Integrator::device_free(Device *, DeviceScene *dscene) +void Integrator::device_free(Device *, DeviceScene *dscene, bool force_free) { - dscene->sample_pattern_lut.free(); + dscene->sample_pattern_lut.free_if_need_realloc(force_free); } -void Integrator::tag_update(Scene *scene) +void Integrator::tag_update(Scene *scene, uint32_t flag) { - foreach (Shader *shader, scene->shaders) { - if (shader->has_integrator_dependency) { - scene->shader_manager->need_update = true; - break; + if (flag & UPDATE_ALL) { + tag_modified(); + } + + if (flag & (AO_PASS_MODIFIED | BACKGROUND_AO_MODIFIED)) { + /* tag only the ao_bounces socket as modified so we avoid updating sample_pattern_lut + * unnecessarily */ + tag_ao_bounces_modified(); + } + + if (filter_glossy_is_modified()) { + foreach (Shader *shader, scene->shaders) { + if (shader->has_integrator_dependency) { + scene->shader_manager->tag_update(scene, ShaderManager::INTEGRATOR_MODIFIED); + break; + } } } - tag_modified(); + + if (motion_blur_is_modified()) { + scene->object_manager->tag_update(scene, ObjectManager::MOTION_BLUR_MODIFIED); + scene->camera->tag_modified(); + } } CCL_NAMESPACE_END diff --git a/intern/cycles/render/integrator.h b/intern/cycles/render/integrator.h index 9fe46ad591c..57dcaf95360 100644 --- a/intern/cycles/render/integrator.h +++ b/intern/cycles/render/integrator.h @@ -89,13 +89,23 @@ class Integrator : public Node { NODE_SOCKET_API(SamplingPattern, sampling_pattern) + enum : uint32_t { + AO_PASS_MODIFIED = (1 << 0), + BACKGROUND_AO_MODIFIED = (1 << 1), + + /* tag everything in the manager for an update */ + UPDATE_ALL = ~0u, + + UPDATE_NONE = 0u, + }; + Integrator(); ~Integrator(); void device_update(Device *device, DeviceScene *dscene, Scene *scene); - void device_free(Device *device, DeviceScene *dscene); + void device_free(Device *device, DeviceScene *dscene, bool force_free = false); - void tag_update(Scene *scene); + void tag_update(Scene *scene, uint32_t flag); }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp index 2bde3242b26..6e9dea564c2 100644 --- a/intern/cycles/render/light.cpp +++ b/intern/cycles/render/light.cpp @@ -162,7 +162,9 @@ Light::Light() : Node(node_type) void Light::tag_update(Scene *scene) { - scene->light_manager->need_update = is_modified(); + if (is_modified()) { + scene->light_manager->tag_update(scene, LightManager::LIGHT_MODIFIED); + } } bool Light::has_contribution(Scene *scene) @@ -183,7 +185,7 @@ bool Light::has_contribution(Scene *scene) LightManager::LightManager() { - need_update = true; + update_flags = UPDATE_ALL; need_update_background = true; use_light_visibility = false; last_background_enabled = false; @@ -962,7 +964,7 @@ void LightManager::device_update(Device *device, Scene *scene, Progress &progress) { - if (!need_update) + if (!need_update()) return; scoped_callback_timer timer([scene](double time) { @@ -1000,7 +1002,7 @@ void LightManager::device_update(Device *device, scene->film->set_use_light_visibility(use_light_visibility); - need_update = false; + update_flags = UPDATE_NONE; need_update_background = false; } @@ -1015,9 +1017,14 @@ void LightManager::device_free(Device *, DeviceScene *dscene, const bool free_ba dscene->ies_lights.free(); } -void LightManager::tag_update(Scene * /*scene*/) +void LightManager::tag_update(Scene * /*scene*/, uint32_t flag) +{ + update_flags |= flag; +} + +bool LightManager::need_update() const { - need_update = true; + return update_flags != UPDATE_NONE; } int LightManager::add_ies_from_file(const string &filename) @@ -1063,7 +1070,7 @@ int LightManager::add_ies(const string &content) ies_slots[slot]->users = 1; ies_slots[slot]->hash = hash; - need_update = true; + update_flags = UPDATE_ALL; need_update_background = true; return slot; @@ -1082,8 +1089,10 @@ void LightManager::remove_ies(int slot) ies_slots[slot]->users--; /* If the slot has no more users, update the device to remove it. */ - need_update |= (ies_slots[slot]->users == 0); - need_update_background |= need_update; + if (ies_slots[slot]->users == 0) { + update_flags |= UPDATE_ALL; + need_update_background = true; + } } void LightManager::device_update_ies(DeviceScene *dscene) diff --git a/intern/cycles/render/light.h b/intern/cycles/render/light.h index e590e13b489..39014b5d667 100644 --- a/intern/cycles/render/light.h +++ b/intern/cycles/render/light.h @@ -91,8 +91,23 @@ class Light : public Node { class LightManager { public: + enum : uint32_t { + MESH_NEED_REBUILD = (1 << 0), + EMISSIVE_MESH_MODIFIED = (1 << 1), + LIGHT_MODIFIED = (1 << 2), + LIGHT_ADDED = (1 << 3), + LIGHT_REMOVED = (1 << 4), + OBJECT_MANAGER = (1 << 5), + SHADER_COMPILED = (1 << 6), + SHADER_MODIFIED = (1 << 7), + + /* tag everything in the manager for an update */ + UPDATE_ALL = ~0u, + + UPDATE_NONE = 0u, + }; + bool use_light_visibility; - bool need_update; /* Need to update background (including multiple importance map) */ bool need_update_background; @@ -108,7 +123,9 @@ class LightManager { void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress); void device_free(Device *device, DeviceScene *dscene, const bool free_background = true); - void tag_update(Scene *scene); + void tag_update(Scene *scene, uint32_t flag); + + bool need_update() const; /* Check whether there is a background light. */ bool has_background_light(Scene *scene); @@ -145,6 +162,8 @@ class LightManager { bool last_background_enabled; int last_background_resolution; + + uint32_t update_flags; }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index a0afdd3b841..5f62da8f18b 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -805,34 +805,42 @@ void Mesh::pack_patches(uint *patch_data, uint vert_offset, uint face_offset, ui } } -void Mesh::pack_primitives(PackedBVH &pack, int object, uint visibility) +void Mesh::pack_primitives(ccl::PackedBVH *pack, int object, uint visibility, bool pack_all) { if (triangles.empty()) return; const size_t num_prims = num_triangles(); - pack.prim_tri_index.reserve(pack.prim_tri_index.size() + num_prims); - pack.prim_tri_verts.reserve(pack.prim_tri_verts.size() + num_prims * 3); - pack.prim_type.reserve(pack.prim_type.size() + num_prims); - pack.prim_visibility.reserve(pack.prim_visibility.size() + num_prims); - pack.prim_index.reserve(pack.prim_index.size() + num_prims); - pack.prim_object.reserve(pack.prim_object.size() + num_prims); - // 'pack.prim_time' is unused by Embree and OptiX + + /* Use prim_offset for indexing as it is computed per geometry type, and prim_tri_verts does not + * contain data for Hair geometries. */ + float4 *prim_tri_verts = &pack->prim_tri_verts[prim_offset * 3]; + // 'pack->prim_time' is unused by Embree and OptiX uint type = has_motion_blur() ? PRIMITIVE_MOTION_TRIANGLE : PRIMITIVE_TRIANGLE; - for (size_t k = 0; k < num_prims; ++k) { - pack.prim_tri_index.push_back_reserved(pack.prim_tri_verts.size()); + if (pack_all) { + /* Use optix_prim_offset for indexing as those arrays also contain data for Hair geometries. */ + unsigned int *prim_tri_index = &pack->prim_tri_index[optix_prim_offset]; + int *prim_type = &pack->prim_type[optix_prim_offset]; + unsigned int *prim_visibility = &pack->prim_visibility[optix_prim_offset]; + int *prim_index = &pack->prim_index[optix_prim_offset]; + int *prim_object = &pack->prim_object[optix_prim_offset]; + + for (size_t k = 0; k < num_prims; ++k) { + prim_tri_index[k] = (prim_offset + k) * 3; + prim_type[k] = type; + prim_index[k] = prim_offset + k; + prim_object[k] = object; + prim_visibility[k] = visibility; + } + } + for (size_t k = 0; k < num_prims; ++k) { const Mesh::Triangle t = get_triangle(k); - pack.prim_tri_verts.push_back_reserved(float3_to_float4(verts[t.v[0]])); - pack.prim_tri_verts.push_back_reserved(float3_to_float4(verts[t.v[1]])); - pack.prim_tri_verts.push_back_reserved(float3_to_float4(verts[t.v[2]])); - - pack.prim_type.push_back_reserved(type); - pack.prim_visibility.push_back_reserved(visibility); - pack.prim_index.push_back_reserved(k + prim_offset); - pack.prim_object.push_back_reserved(object); + prim_tri_verts[k * 3] = float3_to_float4(verts[t.v[0]]); + prim_tri_verts[k * 3 + 1] = float3_to_float4(verts[t.v[1]]); + prim_tri_verts[k * 3 + 2] = float3_to_float4(verts[t.v[2]]); } } diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h index b0a16fdfd8f..2b0ff92ab62 100644 --- a/intern/cycles/render/mesh.h +++ b/intern/cycles/render/mesh.h @@ -232,7 +232,7 @@ class Mesh : public Geometry { size_t tri_offset); void pack_patches(uint *patch_data, uint vert_offset, uint face_offset, uint corner_offset); - void pack_primitives(PackedBVH &pack, int object, uint visibility) override; + void pack_primitives(PackedBVH *pack, int object, uint visibility, bool pack_all) override; void tessellate(DiagSplit *split); diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index 406982e3ef9..0f16a4fc12c 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -153,6 +153,10 @@ void Object::update_motion() void Object::compute_bounds(bool motion_blur) { + if (!is_modified() && !geometry->is_modified()) { + return; + } + BoundBox mbounds = geometry->bounds; if (motion_blur && use_motion()) { @@ -205,20 +209,39 @@ void Object::apply_transform(bool apply_to_motion) void Object::tag_update(Scene *scene) { + uint32_t flag = ObjectManager::UPDATE_NONE; + + if (is_modified()) { + flag |= ObjectManager::OBJECT_MODIFIED; + + if (use_holdout_is_modified()) { + flag |= ObjectManager::HOLDOUT_MODIFIED; + } + } + if (geometry) { - if (geometry->transform_applied) - geometry->tag_modified(); + if (tfm_is_modified()) { + /* tag the geometry as modified so the BVH is updated, but do not tag everything as modified + */ + if (geometry->is_mesh() || geometry->is_volume()) { + Mesh *mesh = static_cast<Mesh *>(geometry); + mesh->tag_verts_modified(); + } + else if (geometry->is_hair()) { + Hair *hair = static_cast<Hair *>(geometry); + hair->tag_curve_keys_modified(); + } + } foreach (Node *node, geometry->get_used_shaders()) { Shader *shader = static_cast<Shader *>(node); if (shader->get_use_mis() && shader->has_surface_emission) - scene->light_manager->need_update = true; + scene->light_manager->tag_update(scene, LightManager::EMISSIVE_MESH_MODIFIED); } } scene->camera->need_flags_update = true; - scene->geometry_manager->need_update = true; - scene->object_manager->need_update = true; + scene->object_manager->tag_update(scene, flag); } bool Object::use_motion() const @@ -361,7 +384,7 @@ int Object::get_device_index() const ObjectManager::ObjectManager() { - need_update = true; + update_flags = UPDATE_ALL; need_flags_update = true; } @@ -382,7 +405,9 @@ static float object_volume_density(const Transform &tfm, Geometry *geom) return 1.0f; } -void ObjectManager::device_update_object_transform(UpdateObjectTransformState *state, Object *ob) +void ObjectManager::device_update_object_transform(UpdateObjectTransformState *state, + Object *ob, + bool update_all) { KernelObject &kobject = state->objects[ob->index]; Transform *object_motion_pass = state->object_motion_pass; @@ -456,8 +481,11 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s kobject.motion_offset = state->motion_offset[ob->index]; /* Decompose transforms for interpolation. */ - DecomposedTransform *decomp = state->object_motion + kobject.motion_offset; - transform_motion_decompose(decomp, ob->motion.data(), ob->motion.size()); + if (ob->tfm_is_modified() || update_all) { + DecomposedTransform *decomp = state->object_motion + kobject.motion_offset; + transform_motion_decompose(decomp, ob->motion.data(), ob->motion.size()); + } + flag |= SD_OBJECT_MOTION; state->have_motion = true; } @@ -480,10 +508,14 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s 0; kobject.patch_map_offset = 0; kobject.attribute_map_offset = 0; - uint32_t hash_name = util_murmur_hash3(ob->name.c_str(), ob->name.length(), 0); - uint32_t hash_asset = util_murmur_hash3(ob->asset_name.c_str(), ob->asset_name.length(), 0); - kobject.cryptomatte_object = util_hash_to_float(hash_name); - kobject.cryptomatte_asset = util_hash_to_float(hash_asset); + + if (ob->asset_name_is_modified() || update_all) { + uint32_t hash_name = util_murmur_hash3(ob->name.c_str(), ob->name.length(), 0); + uint32_t hash_asset = util_murmur_hash3(ob->asset_name.c_str(), ob->asset_name.length(), 0); + kobject.cryptomatte_object = util_hash_to_float(hash_name); + kobject.cryptomatte_asset = util_hash_to_float(hash_asset); + } + kobject.shadow_terminator_offset = 1.0f / (1.0f - 0.5f * ob->shadow_terminator_offset); /* Object flag. */ @@ -544,6 +576,9 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene, numparticles += psys->particles.size(); } + /* as all the arrays are the same size, checking only dscene.objects is sufficient */ + const bool update_all = dscene->objects.need_realloc(); + /* Parallel object update, with grain size to avoid too much threading overhead * for individual objects. */ static const int OBJECTS_PER_TASK = 32; @@ -551,7 +586,7 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene, [&](const blocked_range<size_t> &r) { for (size_t i = r.begin(); i != r.end(); i++) { Object *ob = state.scene->objects[i]; - device_update_object_transform(&state, ob); + device_update_object_transform(&state, ob, update_all); } }); @@ -559,7 +594,7 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene, return; } - dscene->objects.copy_to_device(); + dscene->objects.copy_to_device_if_modified(); if (state.need_motion == Scene::MOTION_PASS) { dscene->object_motion_pass.copy_to_device(); } @@ -569,6 +604,10 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene, dscene->data.bvh.have_motion = state.have_motion; dscene->data.bvh.have_curves = state.have_curves; + + dscene->objects.clear_modified(); + dscene->object_motion_pass.clear_modified(); + dscene->object_motion.clear_modified(); } void ObjectManager::device_update(Device *device, @@ -576,12 +615,28 @@ void ObjectManager::device_update(Device *device, Scene *scene, Progress &progress) { - if (!need_update) + if (!need_update()) return; + if (update_flags & (OBJECT_ADDED | OBJECT_REMOVED)) { + dscene->objects.tag_realloc(); + dscene->object_motion_pass.tag_realloc(); + dscene->object_motion.tag_realloc(); + dscene->object_flag.tag_realloc(); + dscene->object_volume_step.tag_realloc(); + } + + if (update_flags & HOLDOUT_MODIFIED) { + dscene->object_flag.tag_modified(); + } + + if (update_flags & PARTICLE_MODIFIED) { + dscene->objects.tag_modified(); + } + VLOG(1) << "Total " << scene->objects.size() << " objects."; - device_free(device, dscene); + device_free(device, dscene, false); if (scene->objects.size() == 0) return; @@ -597,6 +652,16 @@ void ObjectManager::device_update(Device *device, int index = 0; foreach (Object *object, scene->objects) { object->index = index++; + + /* this is a bit too broad, however a bigger refactor might be needed to properly separate + * update each type of data (transform, flags, etc.) */ + if (object->is_modified()) { + dscene->objects.tag_modified(); + dscene->object_motion_pass.tag_modified(); + dscene->object_motion.tag_modified(); + dscene->object_flag.tag_modified(); + dscene->object_volume_step.tag_modified(); + } } } @@ -638,7 +703,7 @@ void ObjectManager::device_update(Device *device, void ObjectManager::device_update_flags( Device *, DeviceScene *dscene, Scene *scene, Progress & /*progress*/, bool bounds_valid) { - if (!need_update && !need_flags_update) + if (!need_update() && !need_flags_update) return; scoped_callback_timer timer([scene](double time) { @@ -647,7 +712,7 @@ void ObjectManager::device_update_flags( } }); - need_update = false; + update_flags = UPDATE_NONE; need_flags_update = false; if (scene->objects.size() == 0) @@ -717,6 +782,9 @@ void ObjectManager::device_update_flags( /* Copy object flag. */ dscene->object_flag.copy_to_device(); dscene->object_volume_step.copy_to_device(); + + dscene->object_flag.clear_modified(); + dscene->object_volume_step.clear_modified(); } void ObjectManager::device_update_mesh_offsets(Device *, DeviceScene *dscene, Scene *scene) @@ -764,13 +832,13 @@ void ObjectManager::device_update_mesh_offsets(Device *, DeviceScene *dscene, Sc } } -void ObjectManager::device_free(Device *, DeviceScene *dscene) +void ObjectManager::device_free(Device *, DeviceScene *dscene, bool force_free) { - dscene->objects.free(); - dscene->object_motion_pass.free(); - dscene->object_motion.free(); - dscene->object_flag.free(); - dscene->object_volume_step.free(); + dscene->objects.free_if_need_realloc(force_free); + dscene->object_motion_pass.free_if_need_realloc(force_free); + dscene->object_motion.free_if_need_realloc(force_free); + dscene->object_flag.free_if_need_realloc(force_free); + dscene->object_volume_step.free_if_need_realloc(force_free); } void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress &progress) @@ -841,11 +909,21 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, P } } -void ObjectManager::tag_update(Scene *scene) +void ObjectManager::tag_update(Scene *scene, uint32_t flag) +{ + update_flags |= flag; + + /* avoid infinite loops if the geometry manager tagged us for an update */ + if ((flag & GEOMETRY_MANAGER) == 0) { + scene->geometry_manager->tag_update(scene, GeometryManager::OBJECT_MANAGER); + } + + scene->light_manager->tag_update(scene, LightManager::OBJECT_MANAGER); +} + +bool ObjectManager::need_update() const { - need_update = true; - scene->geometry_manager->need_update = true; - scene->light_manager->need_update = true; + return update_flags != UPDATE_NONE; } string ObjectManager::get_cryptomatte_objects(Scene *scene) diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h index 76c9c30abb0..cf1b9ca510a 100644 --- a/intern/cycles/render/object.h +++ b/intern/cycles/render/object.h @@ -122,8 +122,24 @@ class Object : public Node { /* Object Manager */ class ObjectManager { + uint32_t update_flags; + public: - bool need_update; + enum : uint32_t { + PARTICLE_MODIFIED = (1 << 0), + GEOMETRY_MANAGER = (1 << 1), + MOTION_BLUR_MODIFIED = (1 << 2), + OBJECT_ADDED = (1 << 3), + OBJECT_REMOVED = (1 << 4), + OBJECT_MODIFIED = (1 << 5), + HOLDOUT_MODIFIED = (1 << 6), + + /* tag everything in the manager for an update */ + UPDATE_ALL = ~0u, + + UPDATE_NONE = 0u, + }; + bool need_flags_update; ObjectManager(); @@ -139,9 +155,11 @@ class ObjectManager { bool bounds_valid = true); void device_update_mesh_offsets(Device *device, DeviceScene *dscene, Scene *scene); - void device_free(Device *device, DeviceScene *dscene); + void device_free(Device *device, DeviceScene *dscene, bool force_free); - void tag_update(Scene *scene); + void tag_update(Scene *scene, uint32_t flag); + + bool need_update() const; void apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress &progress); @@ -149,7 +167,9 @@ class ObjectManager { string get_cryptomatte_assets(Scene *scene); protected: - void device_update_object_transform(UpdateObjectTransformState *state, Object *ob); + void device_update_object_transform(UpdateObjectTransformState *state, + Object *ob, + bool update_all); void device_update_object_transform_task(UpdateObjectTransformState *state); bool device_update_object_transform_pop_work(UpdateObjectTransformState *state, int *start_index, diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp index 35b62746f1b..889636fe0f3 100644 --- a/intern/cycles/render/osl.cpp +++ b/intern/cycles/render/osl.cpp @@ -96,7 +96,7 @@ void OSLShaderManager::device_update(Device *device, Scene *scene, Progress &progress) { - if (!need_update) + if (!need_update()) return; scoped_callback_timer timer([scene](double time) { @@ -132,7 +132,7 @@ void OSLShaderManager::device_update(Device *device, compiler.compile(og, shader); if (shader->get_use_mis() && shader->has_surface_emission) - scene->light_manager->need_update = true; + scene->light_manager->tag_update(scene, LightManager::SHADER_COMPILED); } /* setup shader engine */ @@ -147,7 +147,7 @@ void OSLShaderManager::device_update(Device *device, foreach (Shader *shader, scene->shaders) shader->clear_modified(); - need_update = false; + update_flags = UPDATE_NONE; /* add special builtin texture types */ services->textures.insert(ustring("@ao"), new OSLTextureHandle(OSLTextureHandle::AO)); diff --git a/intern/cycles/render/particles.cpp b/intern/cycles/render/particles.cpp index faad731d413..0e168050281 100644 --- a/intern/cycles/render/particles.cpp +++ b/intern/cycles/render/particles.cpp @@ -46,14 +46,14 @@ ParticleSystem::~ParticleSystem() void ParticleSystem::tag_update(Scene *scene) { - scene->particle_system_manager->need_update = true; + scene->particle_system_manager->tag_update(scene); } /* Particle System Manager */ ParticleSystemManager::ParticleSystemManager() { - need_update = true; + need_update_ = true; } ParticleSystemManager::~ParticleSystemManager() @@ -109,7 +109,7 @@ void ParticleSystemManager::device_update(Device *device, Scene *scene, Progress &progress) { - if (!need_update) + if (!need_update()) return; scoped_callback_timer timer([scene](double time) { @@ -128,7 +128,7 @@ void ParticleSystemManager::device_update(Device *device, if (progress.get_cancel()) return; - need_update = false; + need_update_ = false; } void ParticleSystemManager::device_free(Device *, DeviceScene *dscene) @@ -138,7 +138,12 @@ void ParticleSystemManager::device_free(Device *, DeviceScene *dscene) void ParticleSystemManager::tag_update(Scene * /*scene*/) { - need_update = true; + need_update_ = true; +} + +bool ParticleSystemManager::need_update() const +{ + return need_update_; } CCL_NAMESPACE_END diff --git a/intern/cycles/render/particles.h b/intern/cycles/render/particles.h index 0b0408184fe..8b59756f148 100644 --- a/intern/cycles/render/particles.h +++ b/intern/cycles/render/particles.h @@ -57,9 +57,9 @@ class ParticleSystem : public Node { /* ParticleSystem Manager */ class ParticleSystemManager { - public: - bool need_update; + bool need_update_; + public: ParticleSystemManager(); ~ParticleSystemManager(); @@ -71,6 +71,8 @@ class ParticleSystemManager { void device_free(Device *device, DeviceScene *dscene); void tag_update(Scene *scene); + + bool need_update() const; }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index b7720b7aa99..1c403abd0a2 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -161,10 +161,10 @@ void Scene::free_memory(bool final) camera->device_free(device, &dscene, this); film->device_free(device, &dscene, this); background->device_free(device, &dscene); - integrator->device_free(device, &dscene); + integrator->device_free(device, &dscene, true); - object_manager->device_free(device, &dscene); - geometry_manager->device_free(device, &dscene); + object_manager->device_free(device, &dscene, true); + geometry_manager->device_free(device, &dscene, true); shader_manager->device_free(device, &dscene, this); light_manager->device_free(device, &dscene); @@ -386,10 +386,11 @@ bool Scene::need_update() bool Scene::need_data_update() { - return (background->is_modified() || image_manager->need_update || object_manager->need_update || - geometry_manager->need_update || light_manager->need_update || - lookup_tables->need_update || integrator->is_modified() || shader_manager->need_update || - particle_system_manager->need_update || bake_manager->need_update || + return (background->is_modified() || image_manager->need_update() || + object_manager->need_update() || geometry_manager->need_update() || + light_manager->need_update() || lookup_tables->need_update() || + integrator->is_modified() || shader_manager->need_update() || + particle_system_manager->need_update() || bake_manager->need_update() || film->is_modified()); } @@ -407,11 +408,13 @@ void Scene::reset() camera->tag_modified(); dicing_camera->tag_modified(); film->tag_modified(); + background->tag_modified(); + background->tag_update(this); - integrator->tag_update(this); - object_manager->tag_update(this); - geometry_manager->tag_update(this); - light_manager->tag_update(this); + integrator->tag_update(this, Integrator::UPDATE_ALL); + object_manager->tag_update(this, ObjectManager::UPDATE_ALL); + geometry_manager->tag_update(this, GeometryManager::UPDATE_ALL); + light_manager->tag_update(this, LightManager::UPDATE_ALL); particle_system_manager->tag_update(this); } @@ -596,7 +599,7 @@ template<> Light *Scene::create_node<Light>() Light *node = new Light(); node->set_owner(this); lights.push_back(node); - light_manager->tag_update(this); + light_manager->tag_update(this, LightManager::LIGHT_ADDED); return node; } @@ -605,7 +608,7 @@ template<> Mesh *Scene::create_node<Mesh>() Mesh *node = new Mesh(); node->set_owner(this); geometry.push_back(node); - geometry_manager->tag_update(this); + geometry_manager->tag_update(this, GeometryManager::MESH_ADDED); return node; } @@ -614,7 +617,7 @@ template<> Hair *Scene::create_node<Hair>() Hair *node = new Hair(); node->set_owner(this); geometry.push_back(node); - geometry_manager->tag_update(this); + geometry_manager->tag_update(this, GeometryManager::HAIR_ADDED); return node; } @@ -623,7 +626,7 @@ template<> Volume *Scene::create_node<Volume>() Volume *node = new Volume(); node->set_owner(this); geometry.push_back(node); - geometry_manager->tag_update(this); + geometry_manager->tag_update(this, GeometryManager::MESH_ADDED); return node; } @@ -632,7 +635,7 @@ template<> Object *Scene::create_node<Object>() Object *node = new Object(); node->set_owner(this); objects.push_back(node); - object_manager->tag_update(this); + object_manager->tag_update(this, ObjectManager::OBJECT_ADDED); return node; } @@ -650,7 +653,7 @@ template<> Shader *Scene::create_node<Shader>() Shader *node = new Shader(); node->set_owner(this); shaders.push_back(node); - shader_manager->need_update = true; + shader_manager->tag_update(this, ShaderManager::SHADER_ADDED); return node; } @@ -664,43 +667,52 @@ template<typename T> void delete_node_from_array(vector<T> &nodes, T node) } nodes.resize(nodes.size() - 1); + delete node; } template<> void Scene::delete_node_impl(Light *node) { delete_node_from_array(lights, node); - light_manager->tag_update(this); + light_manager->tag_update(this, LightManager::LIGHT_REMOVED); } template<> void Scene::delete_node_impl(Mesh *node) { delete_node_from_array(geometry, static_cast<Geometry *>(node)); - geometry_manager->tag_update(this); + geometry_manager->tag_update(this, GeometryManager::MESH_REMOVED); } template<> void Scene::delete_node_impl(Hair *node) { delete_node_from_array(geometry, static_cast<Geometry *>(node)); - geometry_manager->tag_update(this); + geometry_manager->tag_update(this, GeometryManager::HAIR_REMOVED); } template<> void Scene::delete_node_impl(Volume *node) { delete_node_from_array(geometry, static_cast<Geometry *>(node)); - geometry_manager->tag_update(this); + geometry_manager->tag_update(this, GeometryManager::MESH_REMOVED); } template<> void Scene::delete_node_impl(Geometry *node) { + uint flag; + if (node->is_hair()) { + flag = GeometryManager::HAIR_REMOVED; + } + else { + flag = GeometryManager::MESH_REMOVED; + } + delete_node_from_array(geometry, node); - geometry_manager->tag_update(this); + geometry_manager->tag_update(this, flag); } template<> void Scene::delete_node_impl(Object *node) { delete_node_from_array(objects, node); - object_manager->tag_update(this); + object_manager->tag_update(this, ObjectManager::OBJECT_REMOVED); } template<> void Scene::delete_node_impl(ParticleSystem *node) @@ -742,19 +754,19 @@ static void remove_nodes_in_set(const set<T *> &nodes_set, template<> void Scene::delete_nodes(const set<Light *> &nodes, const NodeOwner *owner) { remove_nodes_in_set(nodes, lights, owner); - light_manager->tag_update(this); + light_manager->tag_update(this, LightManager::LIGHT_REMOVED); } template<> void Scene::delete_nodes(const set<Geometry *> &nodes, const NodeOwner *owner) { remove_nodes_in_set(nodes, geometry, owner); - geometry_manager->tag_update(this); + geometry_manager->tag_update(this, GeometryManager::GEOMETRY_REMOVED); } template<> void Scene::delete_nodes(const set<Object *> &nodes, const NodeOwner *owner) { remove_nodes_in_set(nodes, objects, owner); - object_manager->tag_update(this); + object_manager->tag_update(this, ObjectManager::OBJECT_REMOVED); } template<> void Scene::delete_nodes(const set<ParticleSystem *> &nodes, const NodeOwner *owner) diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 70b140ee9c6..d75246beaa0 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -1038,13 +1038,7 @@ bool Session::update_scene() BakeManager *bake_manager = scene->bake_manager; if (integrator->get_sampling_pattern() != SAMPLING_PATTERN_SOBOL || bake_manager->get_baking()) { - int aa_samples = tile_manager.num_samples; - - integrator->set_aa_samples(aa_samples); - - if (integrator->is_modified()) { - integrator->tag_update(scene); - } + integrator->set_aa_samples(tile_manager.num_samples); } bool kernel_switch_needed = false; diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp index 7e06b427e4d..db765878f07 100644 --- a/intern/cycles/render/shader.cpp +++ b/intern/cycles/render/shader.cpp @@ -218,7 +218,9 @@ Shader::Shader() : Node(node_type) id = -1; used = false; - need_update_geometry = true; + need_update_uvs = true; + need_update_attribute = true; + need_update_displacement = true; } Shader::~Shader() @@ -291,7 +293,7 @@ void Shader::set_graph(ShaderGraph *graph_) const char *new_hash = (graph_) ? graph_->displacement_hash.c_str() : ""; if (strcmp(old_hash, new_hash) != 0) { - need_update_geometry = true; + need_update_displacement = true; } } @@ -308,13 +310,14 @@ void Shader::tag_update(Scene *scene) { /* update tag */ tag_modified(); - scene->shader_manager->need_update = true; + + scene->shader_manager->tag_update(scene, ShaderManager::SHADER_MODIFIED); /* if the shader previously was emissive, update light distribution, * if the new shader is emissive, a light manager update tag will be * done in the shader manager device update. */ if (use_mis && has_surface_emission) - scene->light_manager->need_update = true; + scene->light_manager->tag_update(scene, LightManager::SHADER_MODIFIED); /* Special handle of background MIS light for now: for some reason it * has use_mis set to false. We are quite close to release now, so @@ -323,7 +326,7 @@ void Shader::tag_update(Scene *scene) if (this == scene->background->get_shader(scene)) { scene->light_manager->need_update_background = true; if (scene->light_manager->has_background_light(scene)) { - scene->light_manager->need_update = true; + scene->light_manager->tag_update(scene, LightManager::SHADER_MODIFIED); } } @@ -352,17 +355,17 @@ void Shader::tag_update(Scene *scene) attributes.add(ATTR_STD_POSITION_UNDISPLACED); } if (displacement_method_is_modified()) { - need_update_geometry = true; - scene->geometry_manager->need_update = true; + need_update_displacement = true; + scene->geometry_manager->tag_update(scene, GeometryManager::SHADER_DISPLACEMENT_MODIFIED); scene->object_manager->need_flags_update = true; } } /* compare if the attributes changed, mesh manager will check - * need_update_geometry, update the relevant meshes and clear it. */ + * need_update_attribute, update the relevant meshes and clear it. */ if (attributes.modified(prev_attributes)) { - need_update_geometry = true; - scene->geometry_manager->need_update = true; + need_update_attribute = true; + scene->geometry_manager->tag_update(scene, GeometryManager::SHADER_ATTRIBUTE_MODIFIED); } if (has_volume != prev_has_volume || volume_step_rate != prev_volume_step_rate) { @@ -378,15 +381,20 @@ void Shader::tag_used(Scene *scene) * recompiled because it was skipped for compilation before */ if (!used) { tag_modified(); - scene->shader_manager->need_update = true; + scene->shader_manager->tag_update(scene, ShaderManager::SHADER_MODIFIED); } } +bool Shader::need_update_geometry() const +{ + return need_update_uvs || need_update_attribute || need_update_displacement; +} + /* Shader Manager */ ShaderManager::ShaderManager() { - need_update = true; + update_flags = UPDATE_ALL; beckmann_table_offset = TABLE_OFFSET_INVALID; xyz_to_r = make_float3(3.2404542f, -1.5371385f, -0.4985314f); @@ -484,7 +492,7 @@ int ShaderManager::get_shader_id(Shader *shader, bool smooth) void ShaderManager::update_shaders_used(Scene *scene) { - if (!need_update) { + if (!need_update()) { return; } @@ -793,4 +801,15 @@ string ShaderManager::get_cryptomatte_materials(Scene *scene) return manifest; } +void ShaderManager::tag_update(Scene * /*scene*/, uint32_t /*flag*/) +{ + /* update everything for now */ + update_flags = ShaderManager::UPDATE_ALL; +} + +bool ShaderManager::need_update() const +{ + return update_flags != UPDATE_NONE; +} + CCL_NAMESPACE_END diff --git a/intern/cycles/render/shader.h b/intern/cycles/render/shader.h index de19048d8e1..4375ef9e978 100644 --- a/intern/cycles/render/shader.h +++ b/intern/cycles/render/shader.h @@ -100,7 +100,9 @@ class Shader : public Node { float prev_volume_step_rate; /* synchronization */ - bool need_update_geometry; + bool need_update_uvs; + bool need_update_attribute; + bool need_update_displacement; /* If the shader has only volume components, the surface is assumed to * be transparent. @@ -152,6 +154,8 @@ class Shader : public Node { void set_graph(ShaderGraph *graph); void tag_update(Scene *scene); void tag_used(Scene *scene); + + bool need_update_geometry() const; }; /* Shader Manager virtual base class @@ -161,7 +165,16 @@ class Shader : public Node { class ShaderManager { public: - bool need_update; + enum : uint32_t { + SHADER_ADDED = (1 << 0), + SHADER_MODIFIED = (1 << 2), + INTEGRATOR_MODIFIED = (1 << 3), + + /* tag everything in the manager for an update */ + UPDATE_ALL = ~0u, + + UPDATE_NONE = 0u, + }; static ShaderManager *create(int shadingsystem); virtual ~ShaderManager(); @@ -204,9 +217,15 @@ class ShaderManager { string get_cryptomatte_materials(Scene *scene); + void tag_update(Scene *scene, uint32_t flag); + + bool need_update() const; + protected: ShaderManager(); + uint32_t update_flags; + typedef unordered_map<ustring, uint, ustringHash> AttributeIDMap; AttributeIDMap unique_attribute_id; diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp index 6f5a03124f2..fce604234f1 100644 --- a/intern/cycles/render/svm.cpp +++ b/intern/cycles/render/svm.cpp @@ -74,7 +74,7 @@ void SVMShaderManager::device_update(Device *device, Scene *scene, Progress &progress) { - if (!need_update) + if (!need_update()) return; scoped_callback_timer timer([scene](double time) { @@ -125,7 +125,7 @@ void SVMShaderManager::device_update(Device *device, shader->clear_modified(); if (shader->get_use_mis() && shader->has_surface_emission) { - scene->light_manager->need_update = true; + scene->light_manager->tag_update(scene, LightManager::SHADER_COMPILED); } /* Update the global jump table. @@ -159,7 +159,7 @@ void SVMShaderManager::device_update(Device *device, device_update_common(device, dscene, scene, progress); - need_update = false; + update_flags = UPDATE_NONE; VLOG(1) << "Shader manager updated " << num_shaders << " shaders in " << time_dt() - start_time << " seconds."; diff --git a/intern/cycles/render/tables.cpp b/intern/cycles/render/tables.cpp index b581537c852..a0813400b1c 100644 --- a/intern/cycles/render/tables.cpp +++ b/intern/cycles/render/tables.cpp @@ -28,7 +28,7 @@ CCL_NAMESPACE_BEGIN LookupTables::LookupTables() { - need_update = true; + need_update_ = true; } LookupTables::~LookupTables() @@ -38,7 +38,7 @@ LookupTables::~LookupTables() void LookupTables::device_update(Device *, DeviceScene *dscene, Scene *scene) { - if (!need_update) + if (!need_update()) return; scoped_callback_timer timer([scene](double time) { @@ -52,7 +52,7 @@ void LookupTables::device_update(Device *, DeviceScene *dscene, Scene *scene) if (lookup_tables.size() > 0) dscene->lookup_table.copy_to_device(); - need_update = false; + need_update_ = false; } void LookupTables::device_free(Device *, DeviceScene *dscene) @@ -60,6 +60,11 @@ void LookupTables::device_free(Device *, DeviceScene *dscene) dscene->lookup_table.free(); } +bool LookupTables::need_update() const +{ + return need_update_; +} + static size_t round_up_to_multiple(size_t size, size_t chunk) { return ((size + chunk - 1) / chunk) * chunk; @@ -69,7 +74,7 @@ size_t LookupTables::add_table(DeviceScene *dscene, vector<float> &data) { assert(data.size() > 0); - need_update = true; + need_update_ = true; Table new_table; new_table.offset = 0; @@ -107,7 +112,7 @@ void LookupTables::remove_table(size_t *offset) return; } - need_update = true; + need_update_ = true; list<Table>::iterator table; diff --git a/intern/cycles/render/tables.h b/intern/cycles/render/tables.h index e912d9c01f4..de538e2af78 100644 --- a/intern/cycles/render/tables.h +++ b/intern/cycles/render/tables.h @@ -30,13 +30,14 @@ enum { TABLE_CHUNK_SIZE = 256 }; enum { TABLE_OFFSET_INVALID = -1 }; class LookupTables { + bool need_update_; + public: struct Table { size_t offset; size_t size; }; - bool need_update; list<Table> lookup_tables; LookupTables(); @@ -45,6 +46,8 @@ class LookupTables { void device_update(Device *device, DeviceScene *dscene, Scene *scene); void device_free(Device *device, DeviceScene *dscene); + bool need_update() const; + size_t add_table(DeviceScene *dscene, vector<float> &data); void remove_table(size_t *offset); }; diff --git a/intern/cycles/util/util_array.h b/intern/cycles/util/util_array.h index ea481787018..73f7d6cf7f8 100644 --- a/intern/cycles/util/util_array.h +++ b/intern/cycles/util/util_array.h @@ -131,6 +131,14 @@ template<typename T, size_t alignment = MIN_ALIGNMENT_CPU_DATA_TYPES> class arra } } + void set_data(T *ptr_, size_t datasize) + { + clear(); + data_ = ptr_; + datasize_ = datasize; + capacity_ = datasize; + } + T *steal_pointer() { T *ptr = data_; |