11// SPDX-License-Identifier: Apache-2.0
22// ----------------------------------------------------------------------------
3- // Copyright 2011-2022 Arm Limited
3+ // Copyright 2011-2024 Arm Limited
44//
55// Licensed under the Apache License, Version 2.0 (the "License"); you may not
66// use this file except in compliance with the License. You may obtain a copy
@@ -118,6 +118,18 @@ class ParallelManager
118118 /* * @brief Number of tasks that need to be processed. */
119119 unsigned int m_task_count;
120120
121+ /* * @brief Progress callback (optional). */
122+ astcenc_progress_callback m_callback;
123+
124+ /* * @brief Lock used for callback synchronization. */
125+ std::mutex m_callback_lock;
126+
127+ /* * @brief Minimum progress before making a callback. */
128+ float m_callback_min_diff;
129+
130+ /* * @brief Last progress callback value. */
131+ float m_callback_last_value;
132+
121133public:
122134 /* * @brief Create a new ParallelManager. */
123135 ParallelManager ()
@@ -138,6 +150,8 @@ class ParallelManager
138150 m_start_count = 0 ;
139151 m_done_count = 0 ;
140152 m_task_count = 0 ;
153+ m_callback_last_value = 0 .0f ;
154+ m_callback_min_diff = 1 .0f ;
141155 }
142156
143157 /* *
@@ -166,14 +180,20 @@ class ParallelManager
166180 * initialization. Other threads will block and wait for it to complete.
167181 *
168182 * @param task_count Total number of tasks needing processing.
183+ * @param callback Function pointer for progress status callbacks.
169184 */
170- void init (unsigned int task_count)
185+ void init (unsigned int task_count, astcenc_progress_callback callback )
171186 {
172187 std::lock_guard<std::mutex> lck (m_lock);
173188 if (!m_init_done)
174189 {
190+ m_callback = callback;
175191 m_task_count = task_count;
176192 m_init_done = true ;
193+
194+ // Report every 1% or 4096 blocks, whichever is larger, to avoid callback overhead
195+ float min_diff = (4096 .0f / static_cast <float >(task_count)) * 100 .0f ;
196+ m_callback_min_diff = astc::max (min_diff, 1 .0f );
177197 }
178198 }
179199
@@ -212,12 +232,49 @@ class ParallelManager
212232 {
213233 // Note: m_done_count cannot use an atomic without the mutex; this has a race between the
214234 // update here and the wait() for other threads
215- std::unique_lock<std::mutex> lck (m_lock);
216- this ->m_done_count += count;
217- if (m_done_count == m_task_count)
235+ unsigned int local_count;
236+ float local_last_value;
218237 {
219- lck.unlock ();
220- m_complete.notify_all ();
238+ std::unique_lock<std::mutex> lck (m_lock);
239+ m_done_count += count;
240+ local_count = m_done_count;
241+ local_last_value = m_callback_last_value;
242+
243+ if (m_done_count == m_task_count)
244+ {
245+ // Ensure the progress bar hits 100%
246+ if (m_callback)
247+ {
248+ std::unique_lock<std::mutex> cblck (m_callback_lock);
249+ m_callback (100 .0f );
250+ m_callback_last_value = 100 .0f ;
251+ }
252+
253+ lck.unlock ();
254+ m_complete.notify_all ();
255+ }
256+ }
257+
258+ // Process progress callback if we have one
259+ if (m_callback)
260+ {
261+ // Initial lockless test - have we progressed enough to emit?
262+ float num = static_cast <float >(local_count);
263+ float den = static_cast <float >(m_task_count);
264+ float this_value = (num / den) * 100 .0f ;
265+ bool report_test = (this_value - local_last_value) > m_callback_min_diff;
266+
267+ // Recheck under lock, because another thread might report first
268+ if (report_test)
269+ {
270+ std::unique_lock<std::mutex> cblck (m_callback_lock);
271+ bool report_retest = (this_value - m_callback_last_value) > m_callback_min_diff;
272+ if (report_retest)
273+ {
274+ m_callback (this_value);
275+ m_callback_last_value = this_value;
276+ }
277+ }
221278 }
222279 }
223280
0 commit comments