1 #include "evas_common_private.h"
2 #include "evas_blend_private.h"
3
4 #include "Ecore.h"
5
6 static Eina_Bool scale_rgba_in_to_out_clip_sample_internal(RGBA_Image *src, RGBA_Image *dst, RGBA_Draw_Context *dc, int src_region_x, int src_region_y, int src_region_w, int src_region_h, int dst_region_x, int dst_region_y, int dst_region_w, int dst_region_h);
7
8 typedef struct _Evas_Scale_Thread Evas_Scale_Thread;
9 typedef struct _Evas_Scale_Msg Evas_Scale_Msg;
10
11 struct _Evas_Scale_Msg
12 {
13 Eina_Thread_Queue_Msg head;
14 Evas_Scale_Thread *task;
15 };
16
17 struct _Evas_Scale_Thread
18 {
19 RGBA_Image *mask8;
20 DATA32 **row_ptr;
21 DATA32 *dptr;
22 int *lin_ptr;
23
24 RGBA_Gfx_Func func;
25 RGBA_Gfx_Func func2;
26
27 int dst_clip_x;
28 int dst_clip_y;
29 int dst_clip_h;
30 int dst_clip_w;
31 int dst_w;
32
33 int mask_x;
34 int mask_y;
35
36 unsigned int mul_col;
37 };
38
39 static Eina_Bool use_thread = EINA_FALSE;
40 static Eina_Thread scaling_thread;
41 static Eina_Thread_Queue *thread_queue = NULL;
42 static Eina_Thread_Queue *main_queue = NULL;
43
44 EAPI Eina_Bool
evas_common_scale_rgba_in_to_out_clip_sample(RGBA_Image * src,RGBA_Image * dst,RGBA_Draw_Context * dc,int src_region_x,int src_region_y,int src_region_w,int src_region_h,int dst_region_x,int dst_region_y,int dst_region_w,int dst_region_h)45 evas_common_scale_rgba_in_to_out_clip_sample(RGBA_Image *src, RGBA_Image *dst,
46 RGBA_Draw_Context *dc,
47 int src_region_x, int src_region_y,
48 int src_region_w, int src_region_h,
49 int dst_region_x, int dst_region_y,
50 int dst_region_w, int dst_region_h)
51 {
52 return evas_common_scale_rgba_in_to_out_clip_cb
53 (src, dst, dc,
54 src_region_x, src_region_y, src_region_w, src_region_h,
55 dst_region_x, dst_region_y, dst_region_w, dst_region_h,
56 scale_rgba_in_to_out_clip_sample_internal);
57 }
58
59 EAPI void
evas_common_scale_rgba_in_to_out_clip_sample_do(const Cutout_Rects * reuse,const Eina_Rectangle * clip,RGBA_Image * src,RGBA_Image * dst,RGBA_Draw_Context * dc,int src_region_x,int src_region_y,int src_region_w,int src_region_h,int dst_region_x,int dst_region_y,int dst_region_w,int dst_region_h)60 evas_common_scale_rgba_in_to_out_clip_sample_do(const Cutout_Rects *reuse,
61 const Eina_Rectangle *clip,
62 RGBA_Image *src, RGBA_Image *dst,
63 RGBA_Draw_Context *dc,
64 int src_region_x, int src_region_y,
65 int src_region_w, int src_region_h,
66 int dst_region_x, int dst_region_y,
67 int dst_region_w, int dst_region_h)
68 {
69 Eina_Rectangle area;
70 Cutout_Rect *r;
71 int i;
72
73 if (!reuse)
74 {
75 evas_common_draw_context_clip_clip(dc, clip->x, clip->y, clip->w, clip->h);
76 scale_rgba_in_to_out_clip_sample_internal(src, dst, dc,
77 src_region_x, src_region_y,
78 src_region_w, src_region_h,
79 dst_region_x, dst_region_y,
80 dst_region_w, dst_region_h);
81 return;
82 }
83
84 for (i = 0; i < reuse->active; ++i)
85 {
86 r = reuse->rects + i;
87
88 EINA_RECTANGLE_SET(&area, r->x, r->y, r->w, r->h);
89 if (!eina_rectangle_intersection(&area, clip)) continue ;
90 evas_common_draw_context_set_clip(dc, area.x, area.y, area.w, area.h);
91 scale_rgba_in_to_out_clip_sample_internal(src, dst, dc,
92 src_region_x, src_region_y,
93 src_region_w, src_region_h,
94 dst_region_x, dst_region_y,
95 dst_region_w, dst_region_h);
96 }
97 }
98
99 static void
_evas_common_scale_rgba_sample_scale_nomask(int y,int dst_clip_w,int dst_clip_h,int dst_w,DATA32 ** row_ptr,int * lin_ptr,DATA32 * dptr,RGBA_Gfx_Func func,unsigned int mul_col,DATA32 * srcptr,int src_w)100 _evas_common_scale_rgba_sample_scale_nomask(int y,
101 int dst_clip_w, int dst_clip_h, int dst_w,
102 DATA32 **row_ptr, int *lin_ptr,
103 DATA32 *dptr, RGBA_Gfx_Func func, unsigned int mul_col,
104 DATA32 *srcptr, int src_w)
105 {
106 int x;
107 dptr = dptr + dst_w * y;
108
109 if (srcptr)
110 {
111 for (; y < dst_clip_h; y++)
112 {
113 /* * blend here [clip_w *] buf -> dptr * */
114 func(srcptr, NULL, mul_col, dptr, dst_clip_w);
115 dptr += dst_w;
116 srcptr += src_w;
117 }
118 }
119 else
120 {
121 DATA32 *buf = alloca(dst_clip_w * sizeof(DATA32));
122 for (; y < dst_clip_h; y++)
123 {
124 DATA32 *dst_ptr = buf;
125 for (x = 0; x < dst_clip_w; x++)
126 {
127 DATA32 *ptr = row_ptr[y] + lin_ptr[x];
128 *dst_ptr = *ptr;
129 dst_ptr++;
130 }
131 /* * blend here [clip_w *] buf -> dptr * */
132 func(buf, NULL, mul_col, dptr, dst_clip_w);
133 dptr += dst_w;
134 }
135 }
136 }
137
138 static void
_evas_common_scale_rgba_sample_scale_mask(int y,int dst_clip_x,int dst_clip_y,int dst_clip_w,int dst_clip_h,int dst_w,int mask_x,int mask_y,DATA32 ** row_ptr,int * lin_ptr,RGBA_Image * mask_ie,DATA32 * dptr,RGBA_Gfx_Func func,RGBA_Gfx_Func func2,unsigned int mul_col,DATA32 * srcptr,int src_w)139 _evas_common_scale_rgba_sample_scale_mask(int y,
140 int dst_clip_x, int dst_clip_y,
141 int dst_clip_w, int dst_clip_h, int dst_w,
142 int mask_x, int mask_y,
143 DATA32 **row_ptr, int *lin_ptr, RGBA_Image *mask_ie,
144 DATA32 *dptr, RGBA_Gfx_Func func, RGBA_Gfx_Func func2,
145 unsigned int mul_col,
146 DATA32 *srcptr, int src_w)
147 {
148 DATA32 *buf;
149 int x;
150
151 /* clamp/map to mask geometry */
152 if (EINA_UNLIKELY(dst_clip_x < mask_x))
153 dst_clip_x = mask_x;
154 if (EINA_UNLIKELY(dst_clip_y < mask_y))
155 dst_clip_y = mask_y;
156 if (EINA_UNLIKELY(dst_clip_x + dst_clip_w > mask_x + (int)mask_ie->cache_entry.w))
157 dst_clip_w = mask_x + mask_ie->cache_entry.w - dst_clip_x;
158 if (EINA_UNLIKELY(dst_clip_y + dst_clip_h > mask_y + (int)mask_ie->cache_entry.h))
159 dst_clip_h = mask_y + mask_ie->cache_entry.h - dst_clip_y;
160
161 /* a scanline buffer */
162 buf = alloca(dst_clip_w * sizeof(DATA32));
163
164 dptr = dptr + dst_w * y;
165 for (; y < dst_clip_h; y++)
166 {
167 DATA8 *mask;
168
169 mask = mask_ie->image.data8
170 + ((dst_clip_y - mask_y + y) * mask_ie->cache_entry.w)
171 + (dst_clip_x - mask_x);
172
173 if (!srcptr)
174 {
175 DATA32 *dst_ptr = buf;
176 for (x = 0; x < dst_clip_w; x++)
177 {
178 DATA32 *ptr;
179
180 ptr = row_ptr[y] + lin_ptr[x];
181 *dst_ptr = *ptr;
182 dst_ptr++;
183 }
184 }
185
186 /* * blend here [clip_w *] buf -> dptr * */
187 if (mul_col != 0xFFFFFFFF)
188 {
189 func2(srcptr ?: buf, NULL, mul_col, buf, dst_clip_w);
190 func(buf, mask, 0, dptr, dst_clip_w);
191 }
192 else
193 func(srcptr ?: buf, mask, 0, dptr, dst_clip_w);
194
195 dptr += dst_w;
196 if (srcptr) srcptr += src_w;
197 }
198 }
199
200 EAPI void
evas_common_scale_rgba_sample_draw(RGBA_Image * src,RGBA_Image * dst,int dst_clip_x,int dst_clip_y,int dst_clip_w,int dst_clip_h,DATA32 mul_col,int render_op,int src_region_x,int src_region_y,int src_region_w,int src_region_h,int dst_region_x,int dst_region_y,int dst_region_w,int dst_region_h,RGBA_Image * mask_ie,int mask_x,int mask_y)201 evas_common_scale_rgba_sample_draw(RGBA_Image *src, RGBA_Image *dst, int dst_clip_x, int dst_clip_y, int dst_clip_w, int dst_clip_h, DATA32 mul_col, int render_op, int src_region_x, int src_region_y, int src_region_w, int src_region_h, int dst_region_x, int dst_region_y, int dst_region_w, int dst_region_h, RGBA_Image *mask_ie, int mask_x, int mask_y)
202 {
203 int x, y;
204 int *lin_ptr;
205 DATA32 **row_ptr;
206 DATA32 *ptr, *dst_ptr, *src_data, *dst_data;
207 int src_w, src_h, dst_w, dst_h;
208 RGBA_Gfx_Func func, func2 = NULL;
209
210 if ((!src->image.data) || (!dst->image.data)) return;
211 if (!(RECTS_INTERSECT(dst_region_x, dst_region_y, dst_region_w, dst_region_h,
212 0, 0, dst->cache_entry.w, dst->cache_entry.h))) return;
213 if (!(RECTS_INTERSECT(src_region_x, src_region_y, src_region_w, src_region_h,
214 0, 0, src->cache_entry.w, src->cache_entry.h))) return;
215
216 if ((src_region_w <= 0) || (src_region_h <= 0) ||
217 (dst_region_w <= 0) || (dst_region_h <= 0)) return;
218
219 src_w = src->cache_entry.w;
220 if (src_region_x >= src_w) return;
221
222 src_h = src->cache_entry.h;
223 if (src_region_y >= src_h) return;
224
225 dst_w = dst->cache_entry.w;
226 dst_h = dst->cache_entry.h;
227
228 src_data = src->image.data;
229 dst_data = dst->image.data;
230
231 /* sanitise clip x */
232 if (dst_clip_x < 0)
233 {
234 dst_clip_w += dst_clip_x;
235 dst_clip_x = 0;
236 }
237
238 if ((dst_clip_x + dst_clip_w) > dst_w)
239 dst_clip_w = dst_w - dst_clip_x;
240
241 if (dst_clip_x < dst_region_x)
242 {
243 dst_clip_w += dst_clip_x - dst_region_x;
244 dst_clip_x = dst_region_x;
245 }
246
247 if (dst_clip_x >= dst_w) return;
248
249 if ((dst_clip_x + dst_clip_w) > (dst_region_x + dst_region_w))
250 dst_clip_w = dst_region_x + dst_region_w - dst_clip_x;
251
252 if (dst_clip_w <= 0) return;
253
254 /* sanitise clip y */
255 if (dst_clip_y < 0)
256 {
257 dst_clip_h += dst_clip_y;
258 dst_clip_y = 0;
259 }
260
261 if ((dst_clip_y + dst_clip_h) > dst_h)
262 dst_clip_h = dst_h - dst_clip_y;
263
264 if (dst_clip_y < dst_region_y)
265 {
266 dst_clip_h += dst_clip_y - dst_region_y;
267 dst_clip_y = dst_region_y;
268 }
269
270 if (dst_clip_y >= dst_h) return;
271
272 if ((dst_clip_y + dst_clip_h) > (dst_region_y + dst_region_h))
273 dst_clip_h = dst_region_y + dst_region_h - dst_clip_y;
274
275 if (dst_clip_h <= 0) return;
276
277 /* sanitise region x */
278 if (src_region_x < 0)
279 {
280 dst_region_x -= (src_region_x * dst_region_w) / src_region_w;
281 dst_region_w += (src_region_x * dst_region_w) / src_region_w;
282 src_region_w += src_region_x;
283 src_region_x = 0;
284
285 if (dst_clip_x < dst_region_x)
286 {
287 dst_clip_w += (dst_clip_x - dst_region_x);
288 dst_clip_x = dst_region_x;
289 }
290 }
291
292 if ((dst_clip_x + dst_clip_w) > dst_w)
293 dst_clip_w = dst_w - dst_clip_x;
294
295 if (dst_clip_w <= 0) return;
296
297 if ((src_region_x + src_region_w) > src_w)
298 {
299 dst_region_w = (dst_region_w * (src_w - src_region_x)) / (src_region_w);
300 src_region_w = src_w - src_region_x;
301 }
302
303 if ((dst_region_w <= 0) || (src_region_w <= 0)) return;
304
305 /* sanitise region y */
306 if (src_region_y < 0)
307 {
308 dst_region_y -= (src_region_y * dst_region_h) / src_region_h;
309 dst_region_h += (src_region_y * dst_region_h) / src_region_h;
310 src_region_h += src_region_y;
311 src_region_y = 0;
312
313 if (dst_clip_y < dst_region_y)
314 {
315 dst_clip_h += (dst_clip_y - dst_region_y);
316 dst_clip_y = dst_region_y;
317 }
318 }
319
320 if ((dst_clip_y + dst_clip_h) > dst_h)
321 dst_clip_h = dst_h - dst_clip_y;
322
323 if (dst_clip_h <= 0) return;
324
325 if ((src_region_y + src_region_h) > src_h)
326 {
327 dst_region_h = (dst_region_h * (src_h - src_region_y)) / (src_region_h);
328 src_region_h = src_h - src_region_y;
329 }
330
331 if ((dst_region_h <= 0) || (src_region_h <= 0)) return;
332
333 /* figure out dst jump */
334 //dst_jump = dst_w - dst_clip_w;
335
336 /* figure out dest start ptr */
337 dst_ptr = dst_data + dst_clip_x + (dst_clip_y * dst_w);
338
339 if (!mask_ie)
340 {
341 if (mul_col != 0xffffffff)
342 func = evas_common_gfx_func_composite_pixel_color_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, mul_col, dst->cache_entry.flags.alpha, dst_clip_w, render_op);
343 else
344 func = evas_common_gfx_func_composite_pixel_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, dst->cache_entry.flags.alpha, dst_clip_w, render_op);
345 }
346 else
347 {
348 if (mul_col != 0xffffffff)
349 {
350 func = evas_common_gfx_func_composite_pixel_mask_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, dst->cache_entry.flags.alpha, dst_clip_w, render_op);
351 func2 = evas_common_gfx_func_composite_pixel_color_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, mul_col, dst->cache_entry.flags.alpha, dst_clip_w, EVAS_RENDER_COPY);
352 }
353 else
354 func = evas_common_gfx_func_composite_pixel_mask_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, dst->cache_entry.flags.alpha, dst_clip_w, render_op);
355 }
356
357 if ((dst_region_w == src_region_w) && (dst_region_h == src_region_h))
358 {
359 ptr = src_data + (((dst_clip_y - dst_region_y) + src_region_y) * src_w) + ((dst_clip_x - dst_region_x) + src_region_x);
360
361
362 if (mask_ie)
363 _evas_common_scale_rgba_sample_scale_mask(0,
364 dst_clip_x, dst_clip_y, dst_clip_w, dst_clip_h,
365 dst_w, mask_x, mask_y,
366 NULL, NULL,
367 mask_ie, dst_ptr,
368 func, func2, mul_col,
369 ptr, src_w);
370 else
371 _evas_common_scale_rgba_sample_scale_nomask(0,
372 dst_clip_w, dst_clip_h, dst_w,
373 NULL, NULL,
374 dst_ptr,
375 func, mul_col,
376 ptr, src_w);
377 }
378 else
379 {
380 /* allocate scale lookup tables */
381 lin_ptr = alloca(dst_clip_w * sizeof(int));
382 row_ptr = alloca(dst_clip_h * sizeof(DATA32 *));
383
384 /* fill scale tables */
385 for (x = 0; x < dst_clip_w; x++)
386 lin_ptr[x] = (((x + dst_clip_x - dst_region_x) * src_region_w) / dst_region_w) + src_region_x;
387 for (y = 0; y < dst_clip_h; y++)
388 row_ptr[y] = src_data + (((((y + dst_clip_y - dst_region_y) * src_region_h) / dst_region_h)
389 + src_region_y) * src_w);
390
391 if (mask_ie)
392 _evas_common_scale_rgba_sample_scale_mask(0,
393 dst_clip_x, dst_clip_y, dst_clip_w, dst_clip_h,
394 dst_w, mask_x, mask_y,
395 row_ptr, lin_ptr,
396 mask_ie, dst_ptr,
397 func, func2, mul_col,
398 NULL, 0);
399 else
400 _evas_common_scale_rgba_sample_scale_nomask(0,
401 dst_clip_w, dst_clip_h, dst_w,
402 row_ptr, lin_ptr,
403 dst_ptr,
404 func, mul_col,
405 NULL, 0);
406 }
407 }
408
409 static Eina_Bool
scale_rgba_in_to_out_clip_sample_internal(RGBA_Image * src,RGBA_Image * dst,RGBA_Draw_Context * dc,int src_region_x,int src_region_y,int src_region_w,int src_region_h,int dst_region_x,int dst_region_y,int dst_region_w,int dst_region_h)410 scale_rgba_in_to_out_clip_sample_internal(RGBA_Image *src, RGBA_Image *dst,
411 RGBA_Draw_Context *dc,
412 int src_region_x, int src_region_y,
413 int src_region_w, int src_region_h,
414 int dst_region_x, int dst_region_y,
415 int dst_region_w, int dst_region_h)
416 {
417 int x, y;
418 int *lin_ptr;
419 DATA32 *dptr;
420 DATA32 **row_ptr;
421 DATA32 *ptr, *dst_ptr, *src_data, *dst_data;
422 int dst_clip_x, dst_clip_y, dst_clip_w, dst_clip_h;
423 int src_w, src_h, dst_w, dst_h, mask_x, mask_y;
424 RGBA_Gfx_Func func, func2 = NULL;
425 RGBA_Image *mask_ie = dc->clip.mask;
426
427 if (!(RECTS_INTERSECT(dst_region_x, dst_region_y, dst_region_w, dst_region_h, 0, 0, dst->cache_entry.w, dst->cache_entry.h)))
428 return EINA_FALSE;
429 if (!(RECTS_INTERSECT(src_region_x, src_region_y, src_region_w, src_region_h, 0, 0, src->cache_entry.w, src->cache_entry.h)))
430 return EINA_FALSE;
431
432 src_w = src->cache_entry.w;
433 src_h = src->cache_entry.h;
434 dst_w = dst->cache_entry.w;
435 dst_h = dst->cache_entry.h;
436
437 src_data = src->image.data;
438 dst_data = dst->image.data;
439
440 mask_x = dc->clip.mask_x;
441 mask_y = dc->clip.mask_y;
442
443 if (dc->clip.use)
444 {
445 dst_clip_x = dc->clip.x;
446 dst_clip_y = dc->clip.y;
447 dst_clip_w = dc->clip.w;
448 dst_clip_h = dc->clip.h;
449 if (dst_clip_x < 0)
450 {
451 dst_clip_w += dst_clip_x;
452 dst_clip_x = 0;
453 }
454 if (dst_clip_y < 0)
455 {
456 dst_clip_h += dst_clip_y;
457 dst_clip_y = 0;
458 }
459 if ((dst_clip_x + dst_clip_w) > dst_w)
460 dst_clip_w = dst_w - dst_clip_x;
461 if ((dst_clip_y + dst_clip_h) > dst_h)
462 dst_clip_h = dst_h - dst_clip_y;
463 }
464 else
465 {
466 dst_clip_x = 0;
467 dst_clip_y = 0;
468 dst_clip_w = dst_w;
469 dst_clip_h = dst_h;
470 }
471
472 if (dst_clip_x < dst_region_x)
473 {
474 dst_clip_w += dst_clip_x - dst_region_x;
475 dst_clip_x = dst_region_x;
476 }
477 if ((dst_clip_x + dst_clip_w) > (dst_region_x + dst_region_w))
478 dst_clip_w = dst_region_x + dst_region_w - dst_clip_x;
479 if (dst_clip_y < dst_region_y)
480 {
481 dst_clip_h += dst_clip_y - dst_region_y;
482 dst_clip_y = dst_region_y;
483 }
484 if ((dst_clip_y + dst_clip_h) > (dst_region_y + dst_region_h))
485 dst_clip_h = dst_region_y + dst_region_h - dst_clip_y;
486
487 if ((src_region_w <= 0) || (src_region_h <= 0) ||
488 (dst_region_w <= 0) || (dst_region_h <= 0) ||
489 (dst_clip_w <= 0) || (dst_clip_h <= 0))
490 return EINA_FALSE;
491
492 /* sanitise x */
493 if (src_region_x < 0)
494 {
495 dst_region_x -= (src_region_x * dst_region_w) / src_region_w;
496 dst_region_w += (src_region_x * dst_region_w) / src_region_w;
497 src_region_w += src_region_x;
498 src_region_x = 0;
499 }
500 if (src_region_x >= src_w) return EINA_FALSE;
501 if ((src_region_x + src_region_w) > src_w)
502 {
503 dst_region_w = (dst_region_w * (src_w - src_region_x)) / (src_region_w);
504 src_region_w = src_w - src_region_x;
505 }
506 if (dst_region_w <= 0) return EINA_FALSE;
507 if (src_region_w <= 0) return EINA_FALSE;
508 if (dst_clip_x >= dst_w) return EINA_FALSE;
509 if (dst_clip_x < dst_region_x)
510 {
511 dst_clip_w += (dst_clip_x - dst_region_x);
512 dst_clip_x = dst_region_x;
513 }
514 if ((dst_clip_x + dst_clip_w) > dst_w)
515 {
516 dst_clip_w = dst_w - dst_clip_x;
517 }
518 if (dst_clip_w <= 0) return EINA_FALSE;
519
520 /* sanitise y */
521 if (src_region_y < 0)
522 {
523 dst_region_y -= (src_region_y * dst_region_h) / src_region_h;
524 dst_region_h += (src_region_y * dst_region_h) / src_region_h;
525 src_region_h += src_region_y;
526 src_region_y = 0;
527 }
528 if (src_region_y >= src_h) return EINA_FALSE;
529 if ((src_region_y + src_region_h) > src_h)
530 {
531 dst_region_h = (dst_region_h * (src_h - src_region_y)) / (src_region_h);
532 src_region_h = src_h - src_region_y;
533 }
534 if (dst_region_h <= 0) return EINA_FALSE;
535 if (src_region_h <= 0) return EINA_FALSE;
536 if (dst_clip_y >= dst_h) return EINA_FALSE;
537 if (dst_clip_y < dst_region_y)
538 {
539 dst_clip_h += (dst_clip_y - dst_region_y);
540 dst_clip_y = dst_region_y;
541 }
542 if ((dst_clip_y + dst_clip_h) > dst_h)
543 {
544 dst_clip_h = dst_h - dst_clip_y;
545 }
546 if (dst_clip_h <= 0) return EINA_FALSE;
547
548 /* figure out dst jump */
549 //dst_jump = dst_w - dst_clip_w;
550
551 /* figure out dest start ptr */
552 dst_ptr = dst_data + dst_clip_x + (dst_clip_y * dst_w);
553
554 if (!mask_ie)
555 {
556 if (dc->mul.use)
557 func = evas_common_gfx_func_composite_pixel_color_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, dc->mul.col, dst->cache_entry.flags.alpha, dst_clip_w, dc->render_op);
558 else
559 func = evas_common_gfx_func_composite_pixel_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, dst->cache_entry.flags.alpha, dst_clip_w, dc->render_op);
560 }
561 else
562 {
563 func = evas_common_gfx_func_composite_pixel_mask_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, dst->cache_entry.flags.alpha, dst_clip_w, dc->render_op);
564 if (dc->mul.use)
565 func2 = evas_common_gfx_func_composite_pixel_color_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, dc->mul.col, dst->cache_entry.flags.alpha, dst_clip_w, EVAS_RENDER_COPY);
566 }
567
568 if ((dst_region_w == src_region_w) && (dst_region_h == src_region_h))
569 {
570 #ifdef HAVE_PIXMAN
571 # ifdef PIXMAN_IMAGE_SCALE_SAMPLE
572 if ((src->pixman.im) && (dst->pixman.im) && (!dc->clip.mask) &&
573 ((!dc->mul.use) || ((dc->mul.use) && (dc->mul.col == 0xffffffff))) &&
574 ((dc->render_op == _EVAS_RENDER_COPY) ||
575 (dc->render_op == _EVAS_RENDER_BLEND)))
576 {
577 pixman_op_t op = PIXMAN_OP_SRC; // _EVAS_RENDER_COPY
578 if (dc->render_op == _EVAS_RENDER_BLEND)
579 op = PIXMAN_OP_OVER;
580
581 pixman_image_composite(op,
582 src->pixman.im, NULL,
583 dst->pixman.im,
584 (dst_clip_x - dst_region_x) + src_region_x,
585 (dst_clip_y - dst_region_y) + src_region_y,
586 0, 0,
587 dst_clip_x, dst_clip_y,
588 dst_clip_w, dst_clip_h);
589 }
590 else
591 # endif
592 #endif
593 {
594 int mul_col = dc->mul.use ? dc->mul.col : 0xffffffff;
595 ptr = src_data + ((dst_clip_y - dst_region_y + src_region_y) * src_w) + (dst_clip_x - dst_region_x) + src_region_x;
596
597 if (mask_ie)
598 _evas_common_scale_rgba_sample_scale_mask(0,
599 dst_clip_x, dst_clip_y, dst_clip_w, dst_clip_h,
600 dst_w, mask_x, mask_y,
601 NULL, NULL,
602 mask_ie, dst_ptr,
603 func, func2, mul_col,
604 ptr, src_w);
605 else
606 _evas_common_scale_rgba_sample_scale_nomask(0,
607 dst_clip_w, dst_clip_h, dst_w,
608 NULL, NULL,
609 dst_ptr,
610 func, mul_col,
611 ptr, src_w);
612 }
613 }
614 else
615 {
616 /* allocate scale lookup tables */
617 lin_ptr = alloca(dst_clip_w * sizeof(int));
618 row_ptr = alloca(dst_clip_h * sizeof(DATA32 *));
619
620 /* fill scale tables */
621 for (x = 0; x < dst_clip_w; x++)
622 lin_ptr[x] = (((x + dst_clip_x - dst_region_x) * src_region_w) / dst_region_w) + src_region_x;
623 for (y = 0; y < dst_clip_h; y++)
624 row_ptr[y] = src_data + (((((y + dst_clip_y - dst_region_y) * src_region_h) / dst_region_h)
625 + src_region_y) * src_w);
626 /* scale to dst */
627 dptr = dst_ptr;
628 #ifdef DIRECT_SCALE
629 if ((!src->cache_entry.flags.alpha) &&
630 (!dst->cache_entry.flags.alpha) &&
631 (!dc->mul.use) &&
632 (!dc->clip.mask))
633 {
634 for (y = 0; y < dst_clip_h; y++)
635 {
636
637 dst_ptr = dptr;
638 for (x = 0; x < dst_clip_w; x++)
639 {
640 ptr = row_ptr[y] + lin_ptr[x];
641 *dst_ptr = *ptr;
642 dst_ptr++;
643 }
644
645 dptr += dst_w;
646 }
647 }
648 else
649 #endif
650 {
651 unsigned int mul_col;
652
653 mul_col = dc->mul.use ? dc->mul.col : 0xFFFFFFFF;
654
655 /* do we have enough data to start some additional thread ? */
656 if (use_thread && dst_clip_h > 32 && dst_clip_w * dst_clip_h > 4096)
657 {
658 /* Yes, we do ! */
659 Evas_Scale_Msg *msg;
660 void *ref;
661 Evas_Scale_Thread local;
662
663 local.mask8 = dc->clip.mask;
664 local.row_ptr = row_ptr;
665 local.dptr = dptr;
666 local.lin_ptr = lin_ptr;
667 local.func = func;
668 local.func2 = func2;
669 local.dst_clip_x = dst_clip_x;
670 local.dst_clip_y = dst_clip_y;
671 local.dst_clip_h = dst_clip_h;
672 local.dst_clip_w = dst_clip_w;
673 local.dst_w = dst_w;
674 local.mask_x = mask_x;
675 local.mask_y = mask_y;
676 local.mul_col = mul_col;
677
678 msg = eina_thread_queue_send(thread_queue, sizeof (Evas_Scale_Msg), &ref);
679 msg->task = &local;
680 eina_thread_queue_send_done(thread_queue, ref);
681
682 /* image masking */
683 if (dc->clip.mask)
684 {
685 _evas_common_scale_rgba_sample_scale_mask(0,
686 dst_clip_x, dst_clip_y,
687 dst_clip_w, dst_clip_h >> 1, dst_w,
688 dc->clip.mask_x, dc->clip.mask_y,
689 row_ptr, lin_ptr, dc->clip.mask,
690 dptr, func, func2, mul_col,
691 NULL, 0);
692
693 }
694 else
695 {
696 _evas_common_scale_rgba_sample_scale_nomask(0,
697 dst_clip_w, dst_clip_h >> 1, dst_w,
698 row_ptr, lin_ptr,
699 dptr, func, mul_col,
700 NULL, 0);
701 }
702
703 msg = eina_thread_queue_wait(main_queue, &ref);
704 if (msg) eina_thread_queue_wait_done(main_queue, ref);
705 }
706 else
707 {
708 /* No we don't ! */
709
710 /* image masking */
711 if (dc->clip.mask)
712 {
713 _evas_common_scale_rgba_sample_scale_mask(0,
714 dst_clip_x, dst_clip_y,
715 dst_clip_w, dst_clip_h, dst_w,
716 dc->clip.mask_x, dc->clip.mask_y,
717 row_ptr, lin_ptr, dc->clip.mask,
718 dptr, func, func2, mul_col,
719 NULL, 0);
720
721 }
722 else
723 {
724 _evas_common_scale_rgba_sample_scale_nomask(0,
725 dst_clip_w, dst_clip_h, dst_w,
726 row_ptr, lin_ptr,
727 dptr, func, mul_col,
728 NULL, 0);
729 }
730 }
731 }
732 }
733
734 return EINA_TRUE;
735 }
736
737 static void *
_evas_common_scale_sample_thread(void * data EINA_UNUSED,Eina_Thread t EINA_UNUSED)738 _evas_common_scale_sample_thread(void *data EINA_UNUSED,
739 Eina_Thread t EINA_UNUSED)
740 {
741 Evas_Scale_Msg *msg;
742 Evas_Scale_Thread *todo = NULL;
743
744 eina_thread_name_set(eina_thread_self(), "Evas-scale-sam");
745 do
746 {
747 void *ref;
748
749 todo = NULL;
750
751 msg = eina_thread_queue_wait(thread_queue, &ref);
752 if (msg)
753 {
754 int h;
755
756 todo = msg->task;
757 eina_thread_queue_wait_done(thread_queue, ref);
758
759 if (!todo) goto end;
760
761 h = todo->dst_clip_h >> 1;
762
763 if (todo->mask8)
764 _evas_common_scale_rgba_sample_scale_mask(h,
765 todo->dst_clip_x, todo->dst_clip_y,
766 todo->dst_clip_w, todo->dst_clip_h,
767 todo->dst_w,
768 todo->mask_x, todo->mask_y,
769 todo->row_ptr, todo->lin_ptr, todo->mask8,
770 todo->dptr, todo->func, todo->func2,
771 todo->mul_col,
772 NULL, 0);
773 else
774 _evas_common_scale_rgba_sample_scale_nomask(h,
775 todo->dst_clip_w, todo->dst_clip_h,
776 todo->dst_w,
777 todo->row_ptr, todo->lin_ptr,
778 todo->dptr, todo->func, todo->mul_col,
779 NULL, 0);
780 }
781
782 end:
783 msg = eina_thread_queue_send(main_queue, sizeof (Evas_Scale_Msg), &ref);
784 msg->task = NULL;
785 eina_thread_queue_send_done(main_queue, ref);
786 }
787 while (todo);
788
789 return NULL;
790 }
791
792 static void
evas_common_scale_sample_fork_reset(void * data EINA_UNUSED)793 evas_common_scale_sample_fork_reset(void *data EINA_UNUSED)
794 {
795 eina_thread_queue_free(thread_queue);
796 eina_thread_queue_free(main_queue);
797
798 thread_queue = eina_thread_queue_new();
799 main_queue = eina_thread_queue_new();
800
801 if (!eina_thread_create(&scaling_thread, EINA_THREAD_NORMAL, -1,
802 _evas_common_scale_sample_thread, NULL))
803 {
804 CRI("We failed to recreate the upscaling thread.");
805 use_thread = EINA_FALSE;
806 }
807 }
808
809 EAPI void
evas_common_scale_sample_init(void)810 evas_common_scale_sample_init(void)
811 {
812 if (eina_cpu_count() <= 2) return ;
813
814 //Eina_Thread_Queue doesn't work on WIN32.
815 #ifdef _WIN32
816 return;
817 #endif
818
819 ecore_fork_reset_callback_add(evas_common_scale_sample_fork_reset, NULL);
820
821 thread_queue = eina_thread_queue_new();
822 if (EINA_UNLIKELY(!thread_queue))
823 {
824 ERR("Failed to create thread queue");
825 goto cleanup;
826 }
827 main_queue = eina_thread_queue_new();
828 if (EINA_UNLIKELY(!thread_queue))
829 {
830 ERR("Failed to create thread queue");
831 goto cleanup;
832 }
833
834 if (!eina_thread_create(&scaling_thread, EINA_THREAD_NORMAL, -1,
835 _evas_common_scale_sample_thread, NULL))
836 {
837 CRI("We failed to create the upscaling thread.");
838 goto cleanup;
839 }
840
841 use_thread = EINA_TRUE;
842 return;
843
844 cleanup:
845 if (thread_queue) eina_thread_queue_free(thread_queue);
846 if (main_queue) eina_thread_queue_free(main_queue);
847 }
848
849 EAPI void
evas_common_scale_sample_shutdown(void)850 evas_common_scale_sample_shutdown(void)
851 {
852 Evas_Scale_Msg *msg;
853 void *ref;
854
855 if (!use_thread) return ;
856
857 ecore_fork_reset_callback_del(evas_common_scale_sample_fork_reset, NULL);
858
859 msg = eina_thread_queue_send(thread_queue, sizeof (Evas_Scale_Msg), &ref);
860 msg->task = NULL;
861 eina_thread_queue_send_done(thread_queue, ref);
862
863 /* Here is the thread commiting succide*/
864
865 msg = eina_thread_queue_wait(main_queue, &ref);
866 if (msg) eina_thread_queue_wait_done(main_queue, ref);
867
868 eina_thread_join(scaling_thread);
869
870 eina_thread_queue_free(thread_queue);
871 eina_thread_queue_free(main_queue);
872 }
873