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:
committed by
Jesse Yurkovich
parent
6b2463c2b6
commit
96e7242678
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user