xref: /aosp_15_r20/external/skia/src/core/SkTaskGroup.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2014 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 #include "src/core/SkTaskGroup.h"
8 
9 #include "include/core/SkExecutor.h"
10 
11 #include <type_traits>
12 #include <utility>
13 
SkTaskGroup(SkExecutor & executor)14 SkTaskGroup::SkTaskGroup(SkExecutor& executor) : fPending(0), fExecutor(executor) {}
15 
add(std::function<void (void)> fn)16 void SkTaskGroup::add(std::function<void(void)> fn) {
17     fPending.fetch_add(+1, std::memory_order_relaxed);
18     fExecutor.add([this, fn{std::move(fn)}] {
19         fn();
20         fPending.fetch_add(-1, std::memory_order_release);
21     });
22 }
23 
batch(int N,std::function<void (int)> fn)24 void SkTaskGroup::batch(int N, std::function<void(int)> fn) {
25     // TODO: I really thought we had some sort of more clever chunking logic.
26     fPending.fetch_add(+N, std::memory_order_relaxed);
27     for (int i = 0; i < N; i++) {
28         fExecutor.add([fn, i, this] {
29             fn(i);
30             fPending.fetch_add(-1, std::memory_order_release);
31         });
32     }
33 }
34 
done() const35 bool SkTaskGroup::done() const {
36     return fPending.load(std::memory_order_acquire) == 0;
37 }
38 
wait()39 void SkTaskGroup::wait() {
40     // Actively help the executor do work until our task group is done.
41     // This lets SkTaskGroups nest arbitrarily deep on a single SkExecutor:
42     // no thread ever blocks waiting for others to do its work.
43     // (We may end up doing work that's not part of our task group.  That's fine.)
44     while (!this->done()) {
45         fExecutor.borrow();
46     }
47 }
48 
Enabler(int threads)49 SkTaskGroup::Enabler::Enabler(int threads) {
50     if (threads) {
51         fThreadPool = SkExecutor::MakeLIFOThreadPool(threads);
52         SkExecutor::SetDefault(fThreadPool.get());
53     }
54 }
55