LCOV - code coverage report
Current view: top level - muse/framework/audio/common - audioworkgroup.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 55.6 % 18 10
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore-CLA-applies
       4              :  *
       5              :  * MuseScore
       6              :  * Music Composition & Notation
       7              :  *
       8              :  * Copyright (C) 2026 MuseScore Limited and others
       9              :  *
      10              :  * This program is free software: you can redistribute it and/or modify
      11              :  * it under the terms of the GNU General Public License version 3 as
      12              :  * published by the Free Software Foundation.
      13              :  *
      14              :  * This program is distributed in the hope that it will be useful,
      15              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17              :  * GNU General Public License for more details.
      18              :  *
      19              :  * You should have received a copy of the GNU General Public License
      20              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      21              :  */
      22              : 
      23              : #include "audioworkgroup.h"
      24              : 
      25              : #include <memory>
      26              : #include <utility>
      27              : 
      28              : #ifdef __APPLE__
      29              : #include <os/object.h>
      30              : #include <os/workgroup.h>
      31              : #else
      32              : #include <thread>
      33              : #endif
      34              : 
      35              : namespace muse::audio {
      36              : #ifdef __APPLE__
      37              : class AudioWorkgroupTokenProvider
      38              : {
      39              : public:
      40              :     AudioWorkgroupTokenProvider(os_workgroup_t workgroup)
      41              :         : m_workgroup(workgroup)
      42              :     {
      43              :         if (!m_workgroup) {
      44              :             return;
      45              :         }
      46              : 
      47              :         if (__builtin_available(macOS 11.0, *)) {
      48              :             os_retain(m_workgroup);
      49              :             auto status = os_workgroup_join(m_workgroup, &m_joinToken);
      50              :             if (status == 0) {
      51              :                 return;
      52              :             }
      53              : 
      54              :             os_release(m_workgroup);
      55              :             m_workgroup = nullptr;
      56              :             m_joinToken = {};
      57              :             return;
      58              :         }
      59              : 
      60              :         m_workgroup = nullptr;
      61              :     }
      62              : 
      63              :     bool isAttachedTo(os_workgroup_t wg) const { return m_workgroup == wg; }
      64              :     bool isValid() const { return m_workgroup != nullptr; }
      65              : 
      66              :     AudioWorkgroupTokenProvider(const AudioWorkgroupTokenProvider& other) = delete;
      67              : 
      68              :     AudioWorkgroupTokenProvider& operator=(const AudioWorkgroupTokenProvider&) = delete;
      69              : 
      70              :     AudioWorkgroupTokenProvider(AudioWorkgroupTokenProvider&& other) noexcept
      71              :         : m_workgroup(other.m_workgroup), m_joinToken(other.m_joinToken)
      72              :     {
      73              :         other.m_workgroup = nullptr;
      74              :         other.m_joinToken = {};
      75              :     }
      76              : 
      77              :     ~AudioWorkgroupTokenProvider()
      78              :     {
      79              :         leave();
      80              :     }
      81              : 
      82              : private:
      83              :     void leave() noexcept
      84              :     {
      85              :         if (!m_workgroup) {
      86              :             return;
      87              :         }
      88              : 
      89              :         if (__builtin_available(macOS 11.0, *)) {
      90              :             os_workgroup_leave(m_workgroup, &m_joinToken);
      91              :         }
      92              :         os_release(m_workgroup);
      93              :         m_workgroup = nullptr;
      94              :         m_joinToken = {};
      95              :     }
      96              : 
      97              :     os_workgroup_t m_workgroup;
      98              :     os_workgroup_join_token_s m_joinToken;
      99              : };
     100              : 
     101              : class AudioWorkgroupProvider
     102              : {
     103              : public:
     104              :     explicit AudioWorkgroupProvider(os_workgroup_t wg)
     105              :         : m_workgroup(wg)
     106              :     {
     107              :         os_retain(m_workgroup);
     108              :     }
     109              : 
     110              :     ~AudioWorkgroupProvider()
     111              :     {
     112              :         if (m_workgroup) {
     113              :             os_release(m_workgroup);
     114              :         }
     115              :     }
     116              : 
     117              :     AudioWorkgroupProvider(const AudioWorkgroupProvider& other)
     118              :         : m_workgroup(other.m_workgroup)
     119              :     {
     120              :         os_retain(m_workgroup);
     121              :     }
     122              : 
     123              :     AudioWorkgroupProvider& operator=(const AudioWorkgroupProvider& other)
     124              :     {
     125              :         if (this != &other) {
     126              :             os_retain(other.m_workgroup);
     127              :             if (m_workgroup) {
     128              :                 os_release(m_workgroup);
     129              :             }
     130              :             m_workgroup = other.m_workgroup;
     131              :         }
     132              :         return *this;
     133              :     }
     134              : 
     135              :     AudioWorkgroupProvider(AudioWorkgroupProvider&& other) noexcept
     136              :         : m_workgroup(other.m_workgroup)
     137              :     {
     138              :         other.m_workgroup = nullptr;
     139              :     }
     140              : 
     141              :     bool join(AudioWorkgroupToken& tokenProvider) const
     142              :     {
     143              :         if (auto existingProvider = AudioWorkGroup::providerFor(tokenProvider);
     144              :             existingProvider != nullptr && existingProvider->isAttachedTo(m_workgroup)) {
     145              :             return true;
     146              :         }
     147              :         AudioWorkGroup::resetProviderFor(tokenProvider);
     148              :         AudioWorkgroupTokenProvider provider(m_workgroup);
     149              :         if (!provider.isValid()) {
     150              :             return false;
     151              :         }
     152              : 
     153              :         AudioWorkGroup::setProviderFor(tokenProvider, [provider = std::move(provider)]() {
     154              :             return &provider;
     155              :         });
     156              :         return true;
     157              :     }
     158              : 
     159              :     size_t getMaxParallelThreadCount() const
     160              :     {
     161              :         if (__builtin_available(macOS 11.0, *)) {
     162              :             return (size_t)os_workgroup_max_parallel_threads(m_workgroup, nullptr);
     163              :         }
     164              :         return 0;
     165              :     }
     166              : 
     167              : private:
     168              : 
     169              :     os_workgroup_t m_workgroup;
     170              : };
     171              : 
     172              : bool AudioWorkGroup::join(AudioWorkgroupToken& token)
     173              : {
     174              :     auto provider = getProvider();
     175              :     if (!provider) {
     176              :         return false;
     177              :     }
     178              :     return provider->join(token);
     179              : }
     180              : 
     181              : AudioWorkGroup makeAudioWorkgroup(void* opaqueHandle)
     182              : {
     183              :     if (opaqueHandle == nullptr) {
     184              :         return {};
     185              :     }
     186              : 
     187              :     os_workgroup_t handle = reinterpret_cast<os_workgroup_t>(opaqueHandle);
     188              : 
     189              :     return AudioWorkGroup { std::make_unique<AudioWorkgroupProvider>(handle) };
     190              : }
     191              : 
     192              : size_t AudioWorkGroup::getMaxParallelThreadCount() const
     193              : {
     194              :     if (auto provider = getProvider(); provider) {
     195              :         return provider->getMaxParallelThreadCount();
     196              :     }
     197              :     return 0;
     198              : }
     199              : 
     200              : #else
     201              : 
     202              : class AudioWorkgroupProvider
     203              : {
     204              : };
     205              : 
     206            0 : size_t AudioWorkGroup::getMaxParallelThreadCount() const
     207              : {
     208            0 :     return std::thread::hardware_concurrency();
     209              : }
     210              : 
     211           47 : bool AudioWorkGroup::join(AudioWorkgroupToken&)
     212              : {
     213           47 :     return false;
     214              : }
     215              : 
     216            0 : AudioWorkGroup makeAudioWorkgroup(void*)
     217              : {
     218            0 :     return {};
     219              : }
     220              : 
     221              : #endif
     222              : 
     223           99 : AudioWorkGroup::AudioWorkGroup() = default;
     224              : 
     225            0 : AudioWorkGroup::AudioWorkGroup(std::unique_ptr<AudioWorkgroupProvider> provider)
     226            0 :     : m_provider(std::move(provider)) {}
     227              : 
     228          153 : AudioWorkGroup::~AudioWorkGroup() = default;
     229              : 
     230           54 : AudioWorkGroup::AudioWorkGroup(const AudioWorkGroup& other)
     231           54 :     : m_provider(other.m_provider ? std::make_unique<AudioWorkgroupProvider>(*other.m_provider) : nullptr) {}
     232              : 
     233            0 : AudioWorkGroup::AudioWorkGroup(AudioWorkGroup&& other) noexcept = default;
     234              : 
     235           54 : AudioWorkGroup& AudioWorkGroup::operator=(const AudioWorkGroup& other)
     236              : {
     237           54 :     if (this != &other) {
     238           54 :         m_provider = other.m_provider ? std::make_unique<AudioWorkgroupProvider>(*other.m_provider) : nullptr;
     239              :     }
     240           54 :     return *this;
     241              : }
     242              : 
     243            0 : AudioWorkGroup& AudioWorkGroup::operator=(AudioWorkGroup&& other) noexcept = default;
     244              : } // namespace muse::audio
        

Generated by: LCOV version 2.0-1