The open source OpenXR runtime
at main 203 lines 4.1 kB view raw
1// Copyright 2022, Collabora, Ltd. 2// Copyright 2024-2025, NVIDIA CORPORATION. 3// SPDX-License-Identifier: BSL-1.0 4/*! 5 * @file 6 * @brief C++ wrappers for workers. 7 * @author Jakob Bornecrantz <jakob@collabora.com> 8 * 9 * @ingroup aux_util 10 */ 11 12#pragma once 13 14#include "util/u_worker.h" 15 16#include <vector> 17#include <cassert> 18#include <functional> 19 20 21namespace xrt::auxiliary::util { 22 23class TaskCollection; 24class SharedThreadGroup; 25 26/*! 27 * Wrapper around @ref u_worker_thread_pool. 28 * 29 * @ingroup aux_util 30 */ 31class SharedThreadPool 32{ 33private: 34 u_worker_thread_pool *mPool = nullptr; 35 36 37public: 38 SharedThreadPool(SharedThreadPool const &copy) 39 { 40 u_worker_thread_pool_reference(&mPool, copy.mPool); 41 } 42 43 /*! 44 * Take a C thread pool as argument in case the pool is shared between 45 * different C++ components over C interfaces, or created externally. 46 */ 47 explicit SharedThreadPool(u_worker_thread_pool *uwtp) 48 { 49 u_worker_thread_pool_reference(&mPool, uwtp); 50 } 51 52 /*! 53 * @copydoc u_worker_thread_pool_create 54 */ 55 SharedThreadPool(uint32_t starting_worker_count, uint32_t thread_count, const char *prefix) 56 { 57 mPool = u_worker_thread_pool_create(starting_worker_count, thread_count, prefix); 58 } 59 60 ~SharedThreadPool() 61 { 62 u_worker_thread_pool_reference(&mPool, nullptr); 63 } 64 65 SharedThreadPool & 66 operator=(const SharedThreadPool &other) 67 { 68 if (this == &other) { 69 return *this; 70 } 71 72 u_worker_thread_pool_reference(&mPool, other.mPool); 73 return *this; 74 } 75 76 friend SharedThreadGroup; 77 78 // No default constructor. 79 SharedThreadPool() = delete; 80 // No move. 81 SharedThreadPool(SharedThreadPool &&) = delete; 82 // No move assign. 83 SharedThreadPool & 84 operator=(SharedThreadPool &&) = delete; 85}; 86 87/*! 88 * Wrapper around @ref u_worker_group, use @ref TaskCollection to dispatch work. 89 * 90 * @ingroup aux_util 91 */ 92class SharedThreadGroup 93{ 94private: 95 u_worker_group *mGroup = nullptr; 96 97 98public: 99 SharedThreadGroup(SharedThreadPool const &stp) 100 { 101 mGroup = u_worker_group_create(stp.mPool); 102 } 103 104 ~SharedThreadGroup() 105 { 106 u_worker_group_reference(&mGroup, nullptr); 107 } 108 109 /*! 110 * In-general it's recommended to use the TaskCollection helper, 111 * but some use cases requires direct access to the push function, 112 * so it's provided here. 113 */ 114 void 115 push(u_worker_group_func_t f, void *data) 116 { 117 u_worker_group_push(mGroup, f, data); 118 } 119 120 friend TaskCollection; 121 122 // No default constructor. 123 SharedThreadGroup() = delete; 124 // Do not move or copy the shared thread group. 125 SharedThreadGroup(SharedThreadGroup const &) = delete; 126 SharedThreadGroup(SharedThreadGroup &&) = delete; 127 SharedThreadGroup & 128 operator=(SharedThreadGroup const &) = delete; 129 SharedThreadGroup & 130 operator=(SharedThreadGroup &&) = delete; 131}; 132 133/*! 134 * Class to let users fall into a pit of success by 135 * being designed as a one shot dispatcher instance. 136 * 137 * @ingroup aux_util 138 */ 139class TaskCollection 140{ 141public: 142 typedef std::function<void()> Functor; 143 144 145private: 146 static constexpr size_t kSize = 16; 147 148 Functor mFunctors[kSize] = {}; 149 u_worker_group *mGroup = nullptr; 150 151 152public: 153 /*! 154 * Give all Functors when constructed, some what partially 155 * avoids use after leaving scope issues of function delegates. 156 */ 157 TaskCollection(SharedThreadGroup const &stc, std::vector<Functor> const &funcs) 158 { 159 assert(funcs.size() <= kSize); 160 161 u_worker_group_reference(&mGroup, stc.mGroup); 162 163 for (size_t i = 0; i < kSize && i < funcs.size(); i++) { 164 mFunctors[i] = funcs[i]; 165 u_worker_group_push(mGroup, &cCallback, &mFunctors[i]); 166 } 167 } 168 169 ~TaskCollection() 170 { 171 // Also unreferences the group. 172 waitAll(); 173 } 174 175 /*! 176 * Waits for all given tasks to complete, also frees the group. 177 */ 178 void 179 waitAll() 180 { 181 if (mGroup == nullptr) { 182 return; 183 } 184 u_worker_group_wait_all(mGroup); 185 u_worker_group_reference(&mGroup, nullptr); 186 } 187 188 189 // Do not move or copy the task collection. 190 TaskCollection(TaskCollection const &) = delete; 191 TaskCollection(TaskCollection &&) = delete; 192 TaskCollection & 193 operator=(TaskCollection const &) = delete; 194 TaskCollection & 195 operator=(TaskCollection &&) = delete; 196 197 198private: 199 static void 200 cCallback(void *data_ptr); 201}; 202 203} // namespace xrt::auxiliary::util