Cycles: Tesselate adaptive subdivision meshes in parallel

Meshes that require adaptive subdivision are currently tesselated one at
a time. Change this part of device update to be done in parallel.

To remove the possibility of the status message going backwards, a mutex
was required to keep that portion of the loop atomic.

Results for the loop in question: On one particular scene with over 300
meshes requiring tesselation, the update time drops from ~16 seconds to
~3 seconds. The attached synthetic test drops from ~9 seconds down to ~1
second.

Pull Request: https://projects.blender.org/blender/blender/pulls/145220
This commit is contained in:
Jesse Yurkovich
2025-08-28 20:22:14 +02:00
committed by Jesse Yurkovich
parent 6b2463c2b6
commit 96e7242678
2 changed files with 73 additions and 18 deletions

View File

@@ -774,24 +774,33 @@ void GeometryManager::device_update(Device *device,
}
size_t i = 0;
for (Geometry *geom : scene->geometry) {
thread_mutex status_mutex;
parallel_for_each(scene->geometry.begin(), scene->geometry.end(), [&](Geometry *geom) {
if (progress.get_cancel()) {
return;
}
if (!(geom->is_modified() && geom->is_mesh())) {
continue;
return;
}
Mesh *mesh = static_cast<Mesh *>(geom);
if (num_tessellation && mesh->need_tesselation()) {
string msg = "Tessellating ";
if (mesh->name.empty()) {
msg += string_printf("%u/%u", (uint)(i + 1), (uint)num_tessellation);
}
else {
msg += string_printf(
"%s %u/%u", mesh->name.c_str(), (uint)(i + 1), (uint)num_tessellation);
}
{
const thread_scoped_lock status_lock(status_mutex);
string msg = "Tessellating ";
if (mesh->name.empty()) {
msg += string_printf("%u/%u", (uint)(i + 1), (uint)num_tessellation);
}
else {
msg += string_printf(
"%s %u/%u", mesh->name.c_str(), (uint)(i + 1), (uint)num_tessellation);
}
progress.set_status("Updating Mesh", msg);
progress.set_status("Updating Mesh", msg);
i++;
}
SubdParams subd_params(mesh);
subd_params.dicing_rate = mesh->get_subd_dicing_rate();
@@ -800,8 +809,6 @@ void GeometryManager::device_update(Device *device,
subd_params.camera = dicing_camera;
mesh->tessellate(subd_params);
i++;
}
/* Apply generated attribute if needed or remove if not needed */
@@ -811,11 +818,7 @@ void GeometryManager::device_update(Device *device,
if (!mesh->has_true_displacement()) {
mesh->update_tangents(scene, false);
}
if (progress.get_cancel()) {
return;
}
}
});
if (progress.get_cancel()) {
return;

View File

@@ -104,12 +104,23 @@ template<typename T> class unique_ptr_vector {
/* Basic iterators for range based for loop. */
struct ConstIterator {
using iterator_category = std::random_access_iterator_tag;
using value_type = typename vector<unique_ptr<T>>::value_type;
using difference_type = typename vector<unique_ptr<T>>::difference_type;
using pointer = typename vector<unique_ptr<T>>::const_pointer;
using reference = typename vector<unique_ptr<T>>::reference;
typename vector<unique_ptr<T>>::const_iterator it;
const T *operator*() const
{
return it->get();
}
bool operator==(const ConstIterator &other) const
{
return it == other.it;
}
bool operator!=(const ConstIterator &other) const
{
return it != other.it;
@@ -118,6 +129,21 @@ template<typename T> class unique_ptr_vector {
{
++it;
}
difference_type operator-(const ConstIterator &other) const noexcept
{
return static_cast<difference_type>(it - other.it);
}
ConstIterator operator+(const difference_type offset) const noexcept
{
ConstIterator temp = *this;
temp += offset;
return temp;
}
ConstIterator &operator+=(const difference_type offset) noexcept
{
it += offset;
return *this;
}
};
ConstIterator begin() const
@@ -130,12 +156,23 @@ template<typename T> class unique_ptr_vector {
}
struct Iterator {
using iterator_category = std::random_access_iterator_tag;
using value_type = typename vector<unique_ptr<T>>::value_type;
using difference_type = typename vector<unique_ptr<T>>::difference_type;
using pointer = typename vector<unique_ptr<T>>::const_pointer;
using reference = typename vector<unique_ptr<T>>::reference;
typename vector<unique_ptr<T>>::const_iterator it;
T *operator*() const
{
return it->get();
}
bool operator==(const Iterator &other) const
{
return it == other.it;
}
bool operator!=(const Iterator &other) const
{
return it != other.it;
@@ -144,6 +181,21 @@ template<typename T> class unique_ptr_vector {
{
++it;
}
difference_type operator-(const Iterator &other) const noexcept
{
return static_cast<difference_type>(it - other.it);
}
Iterator operator+(const difference_type offset) const noexcept
{
Iterator temp = *this;
temp += offset;
return temp;
}
Iterator &operator+=(const difference_type offset) noexcept
{
it += offset;
return *this;
}
};
Iterator begin()
{