OpenShot Audio Library | OpenShotAudio  0.6.0
juce_AudioWorkgroup.cpp
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2022 - Raw Material Software Limited
6 
7  JUCE is an open source library subject to commercial or open-source
8  licensing.
9 
10  The code included in this file is provided under the terms of the ISC license
11  http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12  To use, copy, modify, and/or distribute this software for any purpose with or
13  without fee is hereby granted provided that the above copyright notice and
14  this permission notice appear in all copies.
15 
16  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18  DISCLAIMED.
19 
20  ==============================================================================
21 */
22 
23 namespace juce
24 {
25 
26 #if JUCE_AUDIOWORKGROUP_TYPES_AVAILABLE
27 
28 class WorkgroupToken::TokenProvider
29 {
30 public:
31  explicit TokenProvider (os_workgroup_t wg)
32  : workgroup (wg), attached (attach (wg, token)) {}
33 
34  ~TokenProvider()
35  {
36  if (attached)
37  detach (workgroup, token);
38  }
39 
40  TokenProvider (const TokenProvider&) = delete;
41  TokenProvider (TokenProvider&& other) noexcept
42  : workgroup (std::exchange (other.workgroup, os_workgroup_t{})),
43  token (std::exchange (other.token, os_workgroup_join_token_s{})),
44  attached (std::exchange (other.attached, false)) {}
45 
46  TokenProvider& operator= (const TokenProvider&) = delete;
47  TokenProvider& operator= (TokenProvider&& other) noexcept
48  {
49  TokenProvider { std::move (other) }.swap (*this);
50  return *this;
51  }
52 
53  bool isAttached() const { return attached; }
54  os_workgroup_t getHandle() const { return workgroup; }
55 
56 private:
57  static void detach (os_workgroup_t wg, os_workgroup_join_token_s token)
58  {
59  if (@available (macos 11.0, ios 14.0, *))
60  os_workgroup_leave (wg, &token);
61  }
62 
63  static bool attach (os_workgroup_t wg, os_workgroup_join_token_s& tokenOut)
64  {
65  if (@available (macos 11.0, ios 14.0, *))
66  {
67  if (wg != nullptr && os_workgroup_join (wg, &tokenOut) == 0)
68  return true;
69  }
70 
71  return false;
72  }
73 
74  void swap (TokenProvider& other) noexcept
75  {
76  std::swap (other.workgroup, workgroup);
77  std::swap (other.token, token);
78  std::swap (other.attached, attached);
79  }
80 
81  os_workgroup_t workgroup;
82  os_workgroup_join_token_s token;
83  bool attached;
84 };
85 
86 class AudioWorkgroup::WorkgroupProvider
87 {
88 public:
89  explicit WorkgroupProvider (os_workgroup_t ptr) : handle { ptr } {}
90 
91  void join (WorkgroupToken& token) const
92  {
93  if (const auto* tokenProvider = token.getTokenProvider())
94  if (tokenProvider->isAttached() && tokenProvider->getHandle() == handle.get())
95  return;
96 
97  // Explicit reset before constructing the new workgroup to ensure that the old workgroup
98  // is left before the new one is joined.
99  token.reset();
100 
101  if (handle.get() != nullptr)
102  token = WorkgroupToken { [provider = WorkgroupToken::TokenProvider { handle.get() }] { return &provider; } };
103  }
104 
105  static os_workgroup_t getWorkgroup (const AudioWorkgroup& wg)
106  {
107  if (auto* provider = wg.getWorkgroupProvider())
108  return provider->handle.get();
109 
110  return nullptr;
111  }
112 
113 private:
114  struct ScopedWorkgroupRetainer
115  {
116  ScopedWorkgroupRetainer (os_workgroup_t wg) : handle { wg }
117  {
118  if (handle != nullptr)
119  os_retain (handle);
120  }
121 
122  ~ScopedWorkgroupRetainer()
123  {
124  if (handle != nullptr)
125  os_release (handle);
126  }
127 
128  ScopedWorkgroupRetainer (const ScopedWorkgroupRetainer& other)
129  : ScopedWorkgroupRetainer { other.handle } {}
130 
131  ScopedWorkgroupRetainer& operator= (const ScopedWorkgroupRetainer& other)
132  {
133  ScopedWorkgroupRetainer { other }.swap (*this);
134  return *this;
135  }
136 
137  ScopedWorkgroupRetainer (ScopedWorkgroupRetainer&& other) noexcept
138  {
139  swap (other);
140  }
141 
142  ScopedWorkgroupRetainer& operator= (ScopedWorkgroupRetainer&& other) noexcept
143  {
144  swap (other);
145  return *this;
146  }
147 
148  void swap (ScopedWorkgroupRetainer& other) noexcept
149  {
150  std::swap (handle, other.handle);
151  }
152 
153  os_workgroup_t get() const noexcept { return handle; }
154 
155  private:
156  os_workgroup_t handle { nullptr };
157  };
158 
159  ScopedWorkgroupRetainer handle;
160 };
161 
162 #else
163 
164 class WorkgroupToken::TokenProvider {};
165 
166 class AudioWorkgroup::WorkgroupProvider
167 {
168 public:
169  explicit WorkgroupProvider() = default;
170 
171  void join (WorkgroupToken& t) const { t.reset(); }
172 
173  static void* getWorkgroup (const AudioWorkgroup&) { return nullptr; }
174 };
175 
176 #endif
177 
179  : erased ([&]() -> Erased
180  {
181  if (auto* p = other.getWorkgroupProvider())
182  return [provider = *p] { return &provider; };
183 
184  return nullptr;
185  }()) {}
186 
188 {
189  return WorkgroupProvider::getWorkgroup (*this) == WorkgroupProvider::getWorkgroup (other);
190 }
191 
193 {
194  #if JUCE_AUDIOWORKGROUP_TYPES_AVAILABLE
195 
196  if (const auto* p = getWorkgroupProvider())
197  {
198  p->join (token);
199  return;
200  }
201 
202  #endif
203 
204  token.reset();
205 }
206 
208 {
209  #if JUCE_AUDIOWORKGROUP_TYPES_AVAILABLE
210 
211  if (@available (macos 11.0, ios 14.0, *))
212  {
213  if (auto wg = WorkgroupProvider::getWorkgroup (*this))
214  return (size_t) os_workgroup_max_parallel_threads (wg, nullptr);
215  }
216 
217  #endif
218 
219  return 0;
220 }
221 
222 AudioWorkgroup::operator bool() const { return WorkgroupProvider::getWorkgroup (*this) != nullptr; }
223 
224 #if JUCE_AUDIOWORKGROUP_TYPES_AVAILABLE
225 
226 AudioWorkgroup makeRealAudioWorkgroup (os_workgroup_t handle)
227 {
228  if (handle == nullptr)
229  return AudioWorkgroup{};
230 
231  return AudioWorkgroup { [provider = AudioWorkgroup::WorkgroupProvider { handle }] { return &provider; } };
232 }
233 
234 #endif
235 
236 } // namespace juce
AudioWorkgroup & operator=(AudioWorkgroup &&)=default
size_t getMaxParallelThreadCount() const
AudioWorkgroup()=default
bool operator==(const AudioWorkgroup &other) const
void join(WorkgroupToken &token) const
FixedSizeFunction< 64, const WorkgroupProvider *()> Erased
WorkgroupToken & operator=(const WorkgroupToken &)=delete