1 /*****************************************************************************
2 * This file is part of gfxprim library. *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
9 * Gfxprim is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * Lesser General Public License for more details. *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
19 * Copyright (C) 2009-2012 Cyril Hrubis <metan@ucw.cz> *
21 *****************************************************************************/
27 #include "core/GP_Common.h"
28 #include "core/GP_Debug.h"
30 #include "GP_Linear.h"
31 #include "GP_LinearThreads.h"
33 static int nr_threads(GP_Size w
, GP_Size h
)
35 int count
= sysconf(_SC_NPROCESSORS_ONLN
);
36 int threads
= GP_MIN(count
, (int)(w
* h
/ 1024) + 1);
41 GP_DEBUG(1, "Found %u CPUs size %ux%u runnig %u threads",
42 count
, w
, h
, threads
);
48 * Multithreaded callback wrapper.
50 struct callback_priv
{
53 unsigned int nr_threads
;
54 pthread_mutex_t mutex
;
55 GP_ProgressCallback
*orig_callback
;
58 static int progress_callback_mp(GP_ProgressCallback
*self
)
60 struct callback_priv
*priv
= self
->priv
;
62 /* If any thread got non-zero return value from a callback, abort all */
66 if (pthread_mutex_trylock(&priv
->mutex
)) {
67 GP_DEBUG(1, "Mutex locked, skipping calllback.");
71 /* Compute max value for the percentage */
72 priv
->orig_callback
->percentage
= GP_MAX(self
->percentage
, priv
->max
);
73 priv
->max
= priv
->orig_callback
->percentage
;
75 /* Call the original callback */
76 int ret
= priv
->orig_callback
->callback(priv
->orig_callback
);
78 /* Turn on abort flag if callback returned nonzero */
82 pthread_mutex_unlock(&priv
->mutex
);
87 static void callback_priv_init(struct callback_priv
*priv
, int nr_threads
,
88 GP_ProgressCallback
*orig_callback
)
90 priv
->nr_threads
= nr_threads
;
91 priv
->orig_callback
= orig_callback
;
94 pthread_mutex_init(&priv
->mutex
, NULL
);
97 static void callback_priv_exit(struct callback_priv
*priv
)
99 pthread_mutex_destroy(&priv
->mutex
);
103 * This code just packs and unpacks convolution parameters.
106 const GP_Context
*src
;
120 GP_ProgressCallback
*callback
;
123 static void convolution_init(struct convolution
*conv
, const GP_Context
*src
,
124 GP_Coord x_src
, GP_Coord y_src
,
125 GP_Size w_src
, GP_Size h_src
,
126 GP_Context
*dst
, GP_Coord x_dst
, GP_Coord y_dst
,
127 float kernel
[], unsigned int ks
, float kern_div
,
128 GP_ProgressCallback
*callback
)
138 conv
->kernel
= kernel
;
140 conv
->kern_div
= kern_div
;
141 conv
->callback
= callback
;
144 static void *h_linear_convolution(void *arg
)
146 struct convolution
*conv
= arg
;
150 ret
= GP_FilterHLinearConvolution_Raw(conv
->src
, conv
->x_src
, conv
->y_src
,
151 conv
->w_src
, conv
->h_src
, conv
->dst
,
152 conv
->x_dst
, conv
->y_dst
, conv
->kernel
,
153 conv
->ks
, conv
->kern_div
, conv
->callback
);
157 static void *v_linear_convolution(void *arg
)
159 struct convolution
*conv
= arg
;
163 ret
= GP_FilterVLinearConvolution_Raw(conv
->src
, conv
->x_src
, conv
->y_src
,
164 conv
->w_src
, conv
->h_src
, conv
->dst
,
165 conv
->x_dst
, conv
->y_dst
, conv
->kernel
,
166 conv
->ks
, conv
->kern_div
, conv
->callback
);
171 int GP_FilterHLinearConvolutionMP_Raw(const GP_Context
*src
,
172 GP_Coord x_src
, GP_Coord y_src
,
173 GP_Size w_src
, GP_Size h_src
,
175 GP_Coord x_dst
, GP_Coord y_dst
,
176 float kernel
[], uint32_t kw
, float kern_div
,
177 GP_ProgressCallback
*callback
)
179 int t
= nr_threads(w_src
, h_src
);
182 return GP_FilterHLinearConvolution_Raw(src
, x_src
, y_src
,
185 kernel
, kw
, kern_div
,
189 /* Create multithreaded safe callback on the stack */
190 struct callback_priv priv
;
191 callback_priv_init(&priv
, t
, callback
);
192 GP_ProgressCallback callback_mp
= {0, progress_callback_mp
, &priv
};
196 pthread_t threads
[t
];
197 struct convolution convs
[t
];
200 for (i
= 0; i
< t
; i
++) {
201 GP_Coord y_src_2
= y_src
+ i
* h
;
202 GP_Coord y_dst_2
= y_dst
+ i
* h
;
206 h_src_2
= h_src
- i
* h
;
208 /* Pack convolution parameters into the structure */
209 convolution_init(&convs
[i
], src
, x_src
, y_src_2
, w_src
, h_src_2
,
210 dst
, x_dst
, y_dst_2
, kernel
, kw
, kern_div
,
211 callback
? &callback_mp
: NULL
);
213 pthread_create(&threads
[i
], NULL
, h_linear_convolution
, &convs
[i
]);
218 for (i
= 0; i
< t
; i
++) {
221 pthread_join(threads
[i
], (void*)&r
);
226 callback_priv_exit(&priv
);
232 int GP_FilterVLinearConvolutionMP_Raw(const GP_Context
*src
,
233 GP_Coord x_src
, GP_Coord y_src
,
234 GP_Size w_src
, GP_Size h_src
,
236 GP_Coord x_dst
, GP_Coord y_dst
,
237 float kernel
[], uint32_t kh
, float kern_div
,
238 GP_ProgressCallback
*callback
)
240 int t
= nr_threads(w_src
, h_src
);
243 return GP_FilterVLinearConvolution_Raw(src
, x_src
, y_src
,
246 kernel
, kh
, kern_div
,
250 /* Create multithreaded safe callback on the stack */
251 struct callback_priv priv
;
252 callback_priv_init(&priv
, t
, callback
);
253 GP_ProgressCallback callback_mp
= {0, progress_callback_mp
, &priv
};
256 pthread_t threads
[t
];
257 struct convolution convs
[t
];
260 for (i
= 0; i
< t
; i
++) {
261 GP_Coord y_src_2
= y_src
+ i
* h
;
262 GP_Coord y_dst_2
= y_dst
+ i
* h
;
266 h_src_2
= h_src
- i
* h
;
268 /* Pack convolution parameters into the structure */
269 convolution_init(&convs
[i
], src
, x_src
, y_src_2
, w_src
, h_src_2
,
270 dst
, x_dst
, y_dst_2
, kernel
, kh
, kern_div
,
271 callback
? &callback_mp
: NULL
);
273 pthread_create(&threads
[i
], NULL
, v_linear_convolution
, &convs
[i
]);
278 for (i
= 0; i
< t
; i
++) {
280 pthread_join(threads
[i
], (void*)&r
);
285 callback_priv_exit(&priv
);
291 int GP_FilterLinearConvolutionMP_Raw(const GP_Context *src,
292 GP_Coord x_src, GP_Coord y_src,
293 GP_Size w_src, GP_Size h_src,
295 GP_Coord x_dst, GP_Coord y_dst,
296 float kernel[], uint32_t kw, uint32_t kh,
297 float kern_div, GP_ProgressCallback *callback)