/* SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once /** \file * \ingroup bli */ #ifdef WITH_TBB /* Quiet top level deprecation message, unrelated to API usage here. */ # if defined(WIN32) && !defined(NOMINMAX) /* TBB includes Windows.h which will define min/max macros causing issues * when we try to use std::min and std::max later on. */ # define NOMINMAX # define TBB_MIN_MAX_CLEANUP # endif # include # include # include # include # include # include # ifdef WIN32 /* We cannot keep this defined, since other parts of the code deal with this on their own, leading * to multiple define warnings unless we un-define this, however we can only undefine this if we * were the ones that made the definition earlier. */ # ifdef TBB_MIN_MAX_CLEANUP # undef NOMINMAX # endif # endif #endif #include "BLI_index_range.hh" #include "BLI_lazy_threading.hh" #include "BLI_utildefines.h" namespace blender::threading { template void parallel_for_each(Range &range, const Function &function) { #ifdef WITH_TBB tbb::parallel_for_each(range, function); #else for (auto &value : range) { function(value); } #endif } template void parallel_for(IndexRange range, int64_t grain_size, const Function &function) { if (range.size() == 0) { return; } #ifdef WITH_TBB /* Invoking tbb for small workloads has a large overhead. */ if (range.size() >= grain_size) { lazy_threading::send_hint(); tbb::parallel_for( tbb::blocked_range(range.first(), range.one_after_last(), grain_size), [&](const tbb::blocked_range &subrange) { function(IndexRange(subrange.begin(), subrange.size())); }); return; } #else UNUSED_VARS(grain_size); #endif function(range); } template Value parallel_reduce(IndexRange range, int64_t grain_size, const Value &identity, const Function &function, const Reduction &reduction) { #ifdef WITH_TBB if (range.size() >= grain_size) { lazy_threading::send_hint(); return tbb::parallel_reduce( tbb::blocked_range(range.first(), range.one_after_last(), grain_size), identity, [&](const tbb::blocked_range &subrange, const Value &ident) { return function(IndexRange(subrange.begin(), subrange.size()), ident); }, reduction); } #else UNUSED_VARS(grain_size, reduction); #endif return function(range, identity); } /** * Execute all of the provided functions. The functions might be executed in parallel or in serial * or some combination of both. */ template void parallel_invoke(Functions &&...functions) { #ifdef WITH_TBB tbb::parallel_invoke(std::forward(functions)...); #else (functions(), ...); #endif } /** * Same #parallel_invoke, but allows disabling threading dynamically. This is useful because when * the individual functions do very little work, there is a lot of overhead from starting parallel * tasks. */ template void parallel_invoke(const bool use_threading, Functions &&...functions) { if (use_threading) { lazy_threading::send_hint(); parallel_invoke(std::forward(functions)...); } else { (functions(), ...); } } /** See #BLI_task_isolate for a description of what isolating a task means. */ template void isolate_task(const Function &function) { #ifdef WITH_TBB tbb::this_task_arena::isolate(function); #else function(); #endif } } // namespace blender::threading