35
33
#include "pixel-processor.h"
36
34
#include "pixel-region.h"
43
#warning FIXME: extern GimpBaseConfig *base_config;
45
extern GimpBaseConfig *base_config;
48
typedef void (* p1_func) (gpointer ,
50
typedef void (* p2_func) (gpointer ,
53
typedef void (* p3_func) (gpointer ,
57
typedef void (* p4_func) (gpointer ,
39
#define TILES_PER_THREAD 8
40
#define PROGRESS_TIMEOUT 64
43
static GThreadPool *pool = NULL;
44
static GMutex *pool_mutex = NULL;
45
static GCond *pool_cond = NULL;
48
typedef void (* p1_func) (gpointer data,
49
PixelRegion *region1);
50
typedef void (* p2_func) (gpointer data,
52
PixelRegion *region2);
53
typedef void (* p3_func) (gpointer data,
56
PixelRegion *region3);
57
typedef void (* p4_func) (gpointer data,
61
PixelRegion *region4);
64
typedef struct _PixelProcessor PixelProcessor;
64
66
struct _PixelProcessor
68
PixelProcessorFunc func;
68
77
PixelRegionIterator *PRI;
71
pthread_mutex_t mutex;
78
void *progress_report_data;
79
ProgressReportFunc progress_report_func;
79
PixelRegion *regions[4];
85
do_parallel_regions (PixelProcessor *p_s)
87
do_parallel_regions (PixelProcessor *processor)
92
pthread_mutex_lock (&p_s->mutex);
94
if (p_s->nthreads != 0 && p_s->PRI)
95
p_s->PRI = pixel_regions_process (p_s->PRI);
99
pthread_mutex_unlock (&p_s->mutex);
107
for (i = 0; i < p_s->n_regions; i++)
110
memcpy(&tr[i], p_s->r[i], sizeof(PixelRegion));
112
tile_lock(tr[i].curtile);
115
pthread_mutex_unlock (&p_s->mutex);
118
switch(p_s->n_regions)
121
((p1_func) p_s->f) (p_s->data,
122
p_s->r[0] ? &tr[0] : NULL);
126
((p2_func) p_s->f) (p_s->data,
127
p_s->r[0] ? &tr[0] : NULL,
128
p_s->r[1] ? &tr[1] : NULL);
132
((p3_func) p_s->f) (p_s->data,
133
p_s->r[0] ? &tr[0] : NULL,
134
p_s->r[1] ? &tr[1] : NULL,
135
p_s->r[2] ? &tr[2] : NULL);
139
((p4_func) p_s->f) (p_s->data,
140
p_s->r[0] ? &tr[0] : NULL,
141
p_s->r[1] ? &tr[1] : NULL,
142
p_s->r[2] ? &tr[2] : NULL,
143
p_s->r[3] ? &tr[3] : NULL);
147
g_warning ("do_parallel_regions: Bad number of regions %d\n",
152
pthread_mutex_lock (&p_s->mutex);
154
for (i = 0; i < p_s->n_regions; i++)
158
tile_release (tr[i].curtile, tr[i].dirty);
161
if (p_s->progress_report_func &&
162
!p_s->progress_report_func (p_s->progress_report_data,
163
p_s->r[0]->x, p_s->r[0]->y,
164
p_s->r[0]->w, p_s->r[0]->h))
169
while (cont && p_s->PRI &&
170
(p_s->PRI = pixel_regions_process (p_s->PRI)));
174
pthread_mutex_unlock (&p_s->mutex);
92
g_mutex_lock (processor->mutex);
94
/* the first thread getting here must not call pixel_regions_process() */
95
if (!processor->first && processor->PRI)
96
processor->PRI = pixel_regions_process (processor->PRI);
98
processor->first = FALSE;
100
while (processor->PRI)
102
guint pixels = (processor->PRI->portion_width *
103
processor->PRI->portion_height);
105
for (i = 0; i < processor->num_regions; i++)
106
if (processor->regions[i])
108
memcpy (&tr[i], processor->regions[i], sizeof (PixelRegion));
110
tile_lock (tr[i].curtile);
113
g_mutex_unlock (processor->mutex);
115
switch (processor->num_regions)
118
((p1_func) processor->func) (processor->data,
119
processor->regions[0] ? &tr[0] : NULL);
123
((p2_func) processor->func) (processor->data,
124
processor->regions[0] ? &tr[0] : NULL,
125
processor->regions[1] ? &tr[1] : NULL);
129
((p3_func) processor->func) (processor->data,
130
processor->regions[0] ? &tr[0] : NULL,
131
processor->regions[1] ? &tr[1] : NULL,
132
processor->regions[2] ? &tr[2] : NULL);
136
((p4_func) processor->func) (processor->data,
137
processor->regions[0] ? &tr[0] : NULL,
138
processor->regions[1] ? &tr[1] : NULL,
139
processor->regions[2] ? &tr[2] : NULL,
140
processor->regions[3] ? &tr[3] : NULL);
144
g_warning ("do_parallel_regions: Bad number of regions %d\n",
145
processor->num_regions);
149
g_mutex_lock (processor->mutex);
151
for (i = 0; i < processor->num_regions; i++)
152
if (processor->regions[i])
155
tile_release (tr[i].curtile, tr[i].dirty);
158
processor->progress += pixels;
161
processor->PRI = pixel_regions_process (processor->PRI);
164
processor->threads--;
166
if (processor->threads == 0)
168
g_mutex_unlock (processor->mutex);
170
g_mutex_lock (pool_mutex);
171
g_cond_signal (pool_cond);
172
g_mutex_unlock (pool_mutex);
176
g_mutex_unlock (processor->mutex);
180
/* do_parallel_regions_single is just like do_parallel_regions
181
/* do_parallel_regions_single is just like do_parallel_regions
181
182
* except that all the mutex and tile locks have been removed
183
* If we are processing with only a single thread we don't need to do the
184
* mutex locks etc. and aditional tile locks even if we were
184
* If we are processing with only a single thread we don't need to do
185
* the mutex locks etc. and aditional tile locks even if we were
185
186
* configured --with-mp
189
do_parallel_regions_single (PixelProcessor *p_s)
190
do_parallel_regions_single (PixelProcessor *processor,
191
PixelProcessorProgressFunc progress_func,
192
gpointer progress_data,
198
g_get_current_time (&last_time);
195
switch (p_s->n_regions)
202
switch (processor->num_regions)
198
((p1_func) p_s->f) (p_s->data,
205
((p1_func) processor->func) (processor->data,
206
processor->regions[0]);
203
((p2_func) p_s->f) (p_s->data,
210
((p2_func) processor->func) (processor->data,
211
processor->regions[0],
212
processor->regions[1]);
209
((p3_func) p_s->f) (p_s->data,
216
((p3_func) processor->func) (processor->data,
217
processor->regions[0],
218
processor->regions[1],
219
processor->regions[2]);
216
((p4_func) p_s->f) (p_s->data,
223
((p4_func) processor->func) (processor->data,
224
processor->regions[0],
225
processor->regions[1],
226
processor->regions[2],
227
processor->regions[3]);
224
231
g_warning ("do_parallel_regions_single: Bad number of regions %d\n",
228
if (p_s->progress_report_func &&
229
!p_s->progress_report_func (p_s->progress_report_data,
230
p_s->r[0]->x, p_s->r[0]->y,
231
p_s->r[0]->w, p_s->r[0]->h))
232
processor->num_regions);
240
processor->progress += (processor->PRI->portion_width *
241
processor->PRI->portion_height);
243
g_get_current_time (&now);
245
if (((now.tv_sec - last_time.tv_sec) * 1024 +
246
(now.tv_usec - last_time.tv_usec) / 1024) > PROGRESS_TIMEOUT)
248
progress_func (progress_data,
249
(gdouble) processor->progress / (gdouble) total);
235
while (cont && p_s->PRI &&
236
(p_s->PRI = pixel_regions_process (p_s->PRI)));
255
while (processor->PRI &&
256
(processor->PRI = pixel_regions_process (processor->PRI)));
241
#define MAX_THREADS 30
244
pixel_regions_do_parallel (PixelProcessor *p_s)
262
pixel_regions_do_parallel (PixelProcessor *processor,
263
PixelProcessorProgressFunc progress_func,
264
gpointer progress_data)
266
gulong pixels = (processor->PRI->region_width *
267
processor->PRI->region_height);
268
gulong tiles = pixels / (TILE_WIDTH * TILE_HEIGHT);
249
nthreads = MIN (base_config->num_processors, MAX_THREADS);
251
/* make sure we have at least one tile per thread */
252
nthreads = MIN (nthreads,
253
(p_s->PRI->region_width * p_s->PRI->region_height)
254
/ (TILE_WIDTH * TILE_HEIGHT));
271
if (pool && tiles > TILES_PER_THREAD)
259
pthread_t threads[MAX_THREADS];
260
pthread_attr_t pthread_attr;
262
pthread_attr_init (&pthread_attr);
264
for (i = 0; i < nthreads; i++)
266
pthread_create (&threads[i], &pthread_attr,
267
(void *(*)(void *)) do_parallel_regions,
270
for (i = 0; i < nthreads; i++)
274
if ((ret = pthread_join (threads[i], NULL)))
276
g_printerr ("pixel_regions_do_parallel: "
277
"pthread_join returned: %d\n", ret);
281
if (p_s->nthreads != 0)
282
g_printerr ("pixel_regions_do_prarallel: we lost a thread\n");
273
GError *error = NULL;
274
gint tasks = MIN (tiles / TILES_PER_THREAD,
275
g_thread_pool_get_max_threads (pool));
278
* g_printerr ("pushing %d tasks into the thread pool (for %lu tiles)\n",
282
processor->first = TRUE;
283
processor->threads = tasks;
284
processor->mutex = g_mutex_new();
286
g_mutex_lock (pool_mutex);
290
g_thread_pool_push (pool, processor, &error);
292
if (G_UNLIKELY (error))
294
g_warning ("thread creation failed: %s", error->message);
295
g_clear_error (&error);
296
processor->threads--;
302
while (processor->threads != 0)
307
g_get_current_time (&timeout);
308
g_time_val_add (&timeout, PROGRESS_TIMEOUT * 1024);
310
g_cond_timed_wait (pool_cond, pool_mutex, &timeout);
312
g_mutex_lock (processor->mutex);
313
progress = processor->progress;
314
g_mutex_unlock (processor->mutex);
316
progress_func (progress_data,
317
(gdouble) progress / (gdouble) pixels);
322
while (processor->threads != 0)
323
g_cond_wait (pool_cond, pool_mutex);
326
g_mutex_unlock (pool_mutex);
328
g_mutex_free (processor->mutex);
333
do_parallel_regions_single (processor,
334
progress_func, progress_data, pixels);
287
do_parallel_regions_single (p_s);
338
progress_func (progress_data, 1.0);
290
static PixelProcessor *
291
pixel_regions_real_process_parallel (p_func f,
293
ProgressReportFunc report_func,
294
gpointer report_data,
342
pixel_regions_process_parallel_valist (PixelProcessorFunc func,
344
PixelProcessorProgressFunc progress_func,
345
gpointer progress_data,
349
PixelProcessor processor = { NULL, };
301
p_s = g_new (PixelProcessor, 1);
303
352
for (i = 0; i < num_regions; i++)
304
p_s->r[i] = va_arg (ap, PixelRegion *);
353
processor.regions[i] = va_arg (ap, PixelRegion *);
309
p_s->PRI = pixel_regions_register (num_regions,
358
processor.PRI = pixel_regions_register (num_regions,
359
processor.regions[0]);
314
p_s->PRI = pixel_regions_register (num_regions,
363
processor.PRI = pixel_regions_register (num_regions,
364
processor.regions[0],
365
processor.regions[1]);
320
p_s->PRI = pixel_regions_register (num_regions,
369
processor.PRI = pixel_regions_register (num_regions,
370
processor.regions[0],
371
processor.regions[1],
372
processor.regions[2]);
327
p_s->PRI = pixel_regions_register (num_regions,
376
processor.PRI = pixel_regions_register (num_regions,
377
processor.regions[0],
378
processor.regions[1],
379
processor.regions[2],
380
processor.regions[3]);
335
g_warning ("pixel_regions_real_process_parallel:"
336
"Bad number of regions %d\n", p_s->n_regions);
341
pixel_processor_free (p_s);
384
g_warning ("pixel_regions_process_parallel: "
385
"bad number of regions (%d)", processor.num_regions);
347
p_s->n_regions = num_regions;
350
pthread_mutex_init (&p_s->mutex, NULL);
354
p_s->progress_report_data = report_data;
355
p_s->progress_report_func = report_func;
357
pixel_regions_do_parallel (p_s);
363
pthread_mutex_destroy (&p_s->mutex);
366
pixel_processor_free (p_s);
372
pixel_regions_process_parallel (p_func f,
379
va_start (va, num_regions);
381
pixel_regions_real_process_parallel (f, data, NULL, NULL, num_regions, va);
387
pixel_regions_process_parallel_progress (p_func f,
389
ProgressReportFunc progress_func,
390
gpointer progress_data,
397
va_start (va, num_regions);
399
ret = pixel_regions_real_process_parallel (f, data,
400
progress_func, progress_data,
409
pixel_processor_stop (PixelProcessor *pp)
392
processor.func = func;
393
processor.data = data;
394
processor.num_regions = num_regions;
397
processor.threads = 0;
400
processor.progress = 0;
402
pixel_regions_do_parallel (&processor, progress_func, progress_data);
406
pixel_processor_init (gint num_threads)
408
pixel_processor_set_num_threads (num_threads);
412
pixel_processor_set_num_threads (gint num_threads)
416
g_return_if_fail (num_threads > 0 && num_threads <= GIMP_MAX_NUM_THREADS);
416
pixel_regions_process_stop (pp->PRI);
422
g_thread_pool_free (pool, TRUE, TRUE);
425
g_cond_free (pool_cond);
428
g_mutex_free (pool_mutex);
420
pixel_processor_free (pp);
424
pixel_processor_cont (PixelProcessor *pp)
426
pixel_regions_do_parallel (pp);
431
pixel_processor_free (pp);
437
pixel_processor_free (PixelProcessor *pp)
440
pixel_processor_stop (pp);
434
GError *error = NULL;
438
g_thread_pool_set_max_threads (pool, num_threads, &error);
442
pool = g_thread_pool_new ((GFunc) do_parallel_regions, NULL,
443
num_threads, TRUE, &error);
445
pool_mutex = g_mutex_new ();
446
pool_cond = g_cond_new ();
449
if (G_UNLIKELY (error))
451
g_warning ("changing the number of threads to %d failed: %s",
452
num_threads, error->message);
453
g_clear_error (&error);
460
pixel_processor_exit (void)
462
pixel_processor_set_num_threads (1);
466
pixel_regions_process_parallel (PixelProcessorFunc func,
473
va_start (va, num_regions);
475
pixel_regions_process_parallel_valist (func, data,
483
pixel_regions_process_parallel_progress (PixelProcessorFunc func,
485
PixelProcessorProgressFunc progress_func,
486
gpointer progress_data,
492
va_start (va, num_regions);
494
pixel_regions_process_parallel_valist (func, data,
495
progress_func, progress_data,