diff options
author | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2019-10-09 17:27:04 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2019-10-10 18:36:12 +0300 |
commit | 6c302d6529ec5283334e5ef40d07cc46534f5020 (patch) | |
tree | f54712920f8ea8a108f456a8279433c6a1d564a3 /source/blender/blenkernel/intern | |
parent | 86042b7ced948cda215f002c125c8d850887eff0 (diff) |
Sculpt: use TBB instead of BLI_task for multithreading
This solves performance issues on some computers where there is significant
threading overhead. Rather than doing the complicated work of optimizing our
own task scheduler, use TBB which appears to work well. The downside is that
we have another thread pool, but it is already there when using OpenVDB voxel
remesh.
For future releases we can switch to using TBB to replace our task scheduler
implementation entirely, and use the same thread pool for BLI_task, Cycles,
Mantaflow, etc.
Differential Revision: https://developer.blender.org/D6030
Diffstat (limited to 'source/blender/blenkernel/intern')
-rw-r--r-- | source/blender/blenkernel/intern/pbvh.c | 28 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/pbvh_parallel.cc | 140 |
2 files changed, 152 insertions, 16 deletions
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 4e193e35109..01612ded396 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -1096,12 +1096,11 @@ static void pbvh_faces_update_normals(PBVH *bvh, PBVHNode **nodes, int totnode) .vnors = vnors, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, &settings); - - BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_store_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_normals_store_task_cb, &settings); MEM_freeN(vnors); } @@ -1151,9 +1150,9 @@ static void pbvh_update_mask_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, in .flag = flag, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, pbvh_update_mask_redraw_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_mask_redraw_task_cb, &settings); } static void pbvh_update_BB_redraw_task_cb(void *__restrict userdata, @@ -1189,9 +1188,9 @@ void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag) .flag = flag, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, pbvh_update_BB_redraw_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_BB_redraw_task_cb, &settings); } static int pbvh_get_buffers_update_flags(PBVH *bvh, bool show_vcol) @@ -1299,9 +1298,9 @@ static void pbvh_update_draw_buffers( .show_vcol = show_vcol, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, pbvh_update_draw_buffer_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_draw_buffer_cb, &settings); } static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag) @@ -2742,13 +2741,10 @@ void pbvh_show_mask_set(PBVH *bvh, bool show_mask) bvh->show_mask = show_mask; } -void BKE_pbvh_parallel_range_settings(TaskParallelSettings *settings, +void BKE_pbvh_parallel_range_settings(PBVHParallelSettings *settings, bool use_threading, int totnode) { - const int threaded_limit = 1; - BLI_parallel_range_settings_defaults(settings); - settings->use_threading = use_threading && (totnode > threaded_limit); - settings->min_iter_per_thread = 1; - settings->scheduling_mode = TASK_SCHEDULING_DYNAMIC; + memset(settings, 0, sizeof(*settings)); + settings->use_threading = use_threading && totnode > 1; } diff --git a/source/blender/blenkernel/intern/pbvh_parallel.cc b/source/blender/blenkernel/intern/pbvh_parallel.cc new file mode 100644 index 00000000000..60503c9bad0 --- /dev/null +++ b/source/blender/blenkernel/intern/pbvh_parallel.cc @@ -0,0 +1,140 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_task.h" +#include "BLI_threads.h" + +#include "BKE_pbvh.h" + +#include "atomic_ops.h" + +#ifdef WITH_TBB + +# include <tbb/tbb.h> + +/* Functor for running TBB parallel_for and parallel_reduce. */ +struct PBVHTask { + PBVHParallelRangeFunc func; + void *userdata; + const PBVHParallelSettings *settings; + + void *userdata_chunk; + bool userdata_chunk_free; + + PBVHTask() + { + } + + PBVHTask(const PBVHTask &other) + : func(other.func), + userdata(other.userdata), + settings(other.settings), + userdata_chunk(0), + userdata_chunk_free(false) + { + if (other.userdata_chunk) { + userdata_chunk = MEM_mallocN(settings->userdata_chunk_size, "PBVHTask"); + memcpy(userdata_chunk, other.userdata_chunk, settings->userdata_chunk_size); + userdata_chunk_free = true; + } + } + + PBVHTask(PBVHTask &other, tbb::split) : PBVHTask(other) + { + } + + ~PBVHTask() + { + if (userdata_chunk_free) { + MEM_freeN(userdata_chunk); + } + } + + void operator()(const tbb::blocked_range<int> &r) const + { + TaskParallelTLS tls; + tls.thread_id = get_thread_id(); + tls.userdata_chunk = userdata_chunk; + for (int i = r.begin(); i != r.end(); ++i) { + func(userdata, i, &tls); + } + } + + void join(const PBVHTask &other) + { + settings->func_reduce(userdata, userdata_chunk, other.userdata_chunk); + } + + int get_thread_id() const + { + /* Get a unique thread ID for texture nodes. In the future we should get rid + * of the thread ID and change texture evaluation to not require per-thread + * storage that can't be efficiently allocated on the stack. */ + static tbb::enumerable_thread_specific<int> pbvh_thread_id(-1); + static int pbvh_thread_id_counter = 0; + + int &thread_id = pbvh_thread_id.local(); + if (thread_id == -1) { + thread_id = atomic_fetch_and_add_int32(&pbvh_thread_id_counter, 1); + if (thread_id >= BLENDER_MAX_THREADS) { + BLI_assert(!"Maximum number of threads exceeded for sculpting"); + thread_id = thread_id % BLENDER_MAX_THREADS; + } + } + return thread_id; + } +}; + +#endif + +void BKE_pbvh_parallel_range(const int start, + const int stop, + void *userdata, + PBVHParallelRangeFunc func, + const struct PBVHParallelSettings *settings) +{ +#ifdef WITH_TBB + /* Multithreading. */ + if (settings->use_threading) { + PBVHTask task; + task.func = func; + task.userdata = userdata; + task.settings = settings; + task.userdata_chunk = settings->userdata_chunk; + task.userdata_chunk_free = false; + + if (settings->func_reduce) { + parallel_reduce(tbb::blocked_range<int>(start, stop), task); + } + else { + parallel_for(tbb::blocked_range<int>(start, stop), task); + } + + return; + } +#endif + + /* Single threaded. Nothing to reduce as everything is accumulated into the + * main userdata chunk directly. */ + TaskParallelTLS tls; + tls.thread_id = 0; + tls.userdata_chunk = settings->userdata_chunk; + for (int i = start; i < stop; i++) { + func(userdata, i, &tls); + } +} |