1
1
// SPDX-License-Identifier: Apache-2.0
2
2
// ----------------------------------------------------------------------------
3
- // Copyright 2011-2022 Arm Limited
3
+ // Copyright 2011-2024 Arm Limited
4
4
//
5
5
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
6
6
// use this file except in compliance with the License. You may obtain a copy
@@ -118,6 +118,18 @@ class ParallelManager
118
118
/* * @brief Number of tasks that need to be processed. */
119
119
unsigned int m_task_count;
120
120
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
+
121
133
public:
122
134
/* * @brief Create a new ParallelManager. */
123
135
ParallelManager ()
@@ -138,6 +150,8 @@ class ParallelManager
138
150
m_start_count = 0 ;
139
151
m_done_count = 0 ;
140
152
m_task_count = 0 ;
153
+ m_callback_last_value = 0 .0f ;
154
+ m_callback_min_diff = 1 .0f ;
141
155
}
142
156
143
157
/* *
@@ -166,14 +180,20 @@ class ParallelManager
166
180
* initialization. Other threads will block and wait for it to complete.
167
181
*
168
182
* @param task_count Total number of tasks needing processing.
183
+ * @param callback Function pointer for progress status callbacks.
169
184
*/
170
- void init (unsigned int task_count)
185
+ void init (unsigned int task_count, astcenc_progress_callback callback )
171
186
{
172
187
std::lock_guard<std::mutex> lck (m_lock);
173
188
if (!m_init_done)
174
189
{
190
+ m_callback = callback;
175
191
m_task_count = task_count;
176
192
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 );
177
197
}
178
198
}
179
199
@@ -212,12 +232,49 @@ class ParallelManager
212
232
{
213
233
// Note: m_done_count cannot use an atomic without the mutex; this has a race between the
214
234
// 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;
218
237
{
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
+ }
221
278
}
222
279
}
223
280
0 commit comments