The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

237 lines
6.6KB

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