1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4 
5 #include <sys/time.h>
6 #include <sys/utsname.h>
7 
8 #include "evas_common_private.h"
9 #include "evas_macros.h"
10 
11 #include "evas_xlib_swapbuf.h"
12 #include "evas_xlib_color.h"
13 #include "evas_xlib_swapper.h"
14 
15 typedef struct _Outbuf_Region Outbuf_Region;
16 
17 struct _Outbuf_Region
18 {
19    RGBA_Image *im;
20    int         x;
21    int         y;
22    int         w;
23    int         h;
24 };
25 
26 void
evas_software_xlib_swapbuf_init(void)27 evas_software_xlib_swapbuf_init(void)
28 {
29 }
30 
31 void
evas_software_xlib_swapbuf_free(Outbuf * buf)32 evas_software_xlib_swapbuf_free(Outbuf *buf)
33 {
34    evas_software_xlib_swapbuf_flush(buf, NULL, NULL, EVAS_RENDER_MODE_UNDEF);
35    evas_software_xlib_swapbuf_idle_flush(buf);
36    if (buf->priv.pal)
37      evas_software_xlib_x_color_deallocate
38        (buf->priv.x11.xlib.disp, buf->priv.x11.xlib.cmap,
39        buf->priv.x11.xlib.vis, buf->priv.pal);
40    evas_xlib_swapper_free(buf->priv.swapper);
41    eina_array_flush(&buf->priv.onebuf_regions);
42    free(buf);
43 }
44 
45 Outbuf *
evas_software_xlib_swapbuf_setup_x(int w,int h,int rot,Outbuf_Depth depth,Display * disp,Drawable draw,Visual * vis,Colormap cmap,int x_depth,int grayscale,int max_colors,Pixmap mask EINA_UNUSED,int shape_dither,int destination_alpha)46 evas_software_xlib_swapbuf_setup_x(int w, int h, int rot, Outbuf_Depth depth,
47                                    Display *disp, Drawable draw, Visual *vis,
48                                    Colormap cmap, int x_depth,
49                                    int grayscale, int max_colors,
50                                    Pixmap mask EINA_UNUSED,
51                                    int shape_dither, int destination_alpha)
52 {
53    Outbuf *buf;
54    Gfx_Func_Convert conv_func = NULL;
55    int d;
56 
57    buf = calloc(1, sizeof(Outbuf));
58    if (!buf) return NULL;
59 
60    if (x_depth < 15) rot = 0;
61 
62    buf->onebuf = 1;
63    buf->w = w;
64    buf->h = h;
65    buf->depth = depth;
66    buf->rot = rot;
67    buf->priv.x11.xlib.disp = disp;
68    buf->priv.x11.xlib.win = draw;
69    buf->priv.x11.xlib.vis = vis;
70    buf->priv.x11.xlib.cmap = cmap;
71    buf->priv.x11.xlib.depth = x_depth;
72    buf->priv.mask_dither = shape_dither;
73    buf->priv.destination_alpha = destination_alpha;
74 
75    if ((buf->rot == 0) || (buf->rot == 180))
76      buf->priv.swapper = evas_xlib_swapper_new(buf->priv.x11.xlib.disp,
77                                                buf->priv.x11.xlib.win,
78                                                buf->priv.x11.xlib.vis,
79                                                buf->priv.x11.xlib.depth,
80                                                buf->w, buf->h);
81    else if ((buf->rot == 90) || (buf->rot == 270))
82      buf->priv.swapper = evas_xlib_swapper_new(buf->priv.x11.xlib.disp,
83                                                buf->priv.x11.xlib.win,
84                                                buf->priv.x11.xlib.vis,
85                                                buf->priv.x11.xlib.depth,
86                                                buf->h, buf->w);
87    if (!buf->priv.swapper)
88      {
89         free(buf);
90         return NULL;
91      }
92 
93    eina_array_step_set(&buf->priv.onebuf_regions, sizeof (Eina_Array), 8);
94 
95 #ifdef WORDS_BIGENDIAN
96    if (evas_xlib_swapper_byte_order_get(buf->priv.swapper) == LSBFirst)
97      buf->priv.x11.xlib.swap = 1;
98    if (evas_xlib_swapper_bit_order_get(buf->priv.swapper) == MSBFirst)
99      buf->priv.x11.xlib.bit_swap = 1;
100 #else
101    if (evas_xlib_swapper_byte_order_get(buf->priv.swapper) == MSBFirst)
102      buf->priv.x11.xlib.swap = 1;
103    if (evas_xlib_swapper_bit_order_get(buf->priv.swapper) == MSBFirst)
104      buf->priv.x11.xlib.bit_swap = 1;
105 #endif
106    if (((vis->class == TrueColor) || (vis->class == DirectColor)) &&
107        (x_depth > 8))
108      {
109         buf->priv.mask.r = (DATA32)vis->red_mask;
110         buf->priv.mask.g = (DATA32)vis->green_mask;
111         buf->priv.mask.b = (DATA32)vis->blue_mask;
112         if (buf->priv.x11.xlib.swap)
113           {
114              SWAP32(buf->priv.mask.r);
115              SWAP32(buf->priv.mask.g);
116              SWAP32(buf->priv.mask.b);
117           }
118      }
119    else if ((vis->class == PseudoColor) || (vis->class == StaticColor) ||
120             (vis->class == GrayScale) || (vis->class == StaticGray) ||
121             (x_depth <= 8))
122      {
123         Convert_Pal_Mode pm = PAL_MODE_RGB332;
124 
125         if ((vis->class == GrayScale) || (vis->class == StaticGray))
126           grayscale = 1;
127         if (grayscale)
128           {
129              if (max_colors >= 256) pm = PAL_MODE_GRAY256;
130              else if (max_colors >= 64)
131                pm = PAL_MODE_GRAY64;
132              else if (max_colors >= 16)
133                pm = PAL_MODE_GRAY16;
134              else if (max_colors >= 4)
135                pm = PAL_MODE_GRAY4;
136              else pm = PAL_MODE_MONO;
137           }
138         else
139           {
140              if (max_colors >= 256) pm = PAL_MODE_RGB332;
141              else if (max_colors >= 216)
142                pm = PAL_MODE_RGB666;
143              else if (max_colors >= 128)
144                pm = PAL_MODE_RGB232;
145              else if (max_colors >= 64)
146                pm = PAL_MODE_RGB222;
147              else if (max_colors >= 32)
148                pm = PAL_MODE_RGB221;
149              else if (max_colors >= 16)
150                pm = PAL_MODE_RGB121;
151              else if (max_colors >= 8)
152                pm = PAL_MODE_RGB111;
153              else if (max_colors >= 4)
154                pm = PAL_MODE_GRAY4;
155              else pm = PAL_MODE_MONO;
156           }
157         /* FIXME: only alloc once per display+cmap */
158         buf->priv.pal = evas_software_xlib_x_color_allocate
159             (disp, cmap, vis, pm);
160         if (!buf->priv.pal)
161           {
162              evas_xlib_swapper_free(buf->priv.swapper);
163              free(buf);
164              return NULL;
165           }
166      }
167    d = evas_xlib_swapper_depth_get(buf->priv.swapper);
168    if (buf->priv.pal)
169      {
170         if (buf->rot == 0 || buf->rot == 180)
171           conv_func = evas_common_convert_func_get(0, buf->w, buf->h, d,
172                                                    buf->priv.mask.r,
173                                                    buf->priv.mask.g,
174                                                    buf->priv.mask.b,
175                                                    buf->priv.pal->colors,
176                                                    buf->rot);
177         else if (buf->rot == 90 || buf->rot == 270)
178           conv_func = evas_common_convert_func_get(0, buf->h, buf->w, d,
179                                                    buf->priv.mask.r,
180                                                    buf->priv.mask.g,
181                                                    buf->priv.mask.b,
182                                                    buf->priv.pal->colors,
183                                                    buf->rot);
184      }
185    else
186      {
187         if (buf->rot == 0 || buf->rot == 180)
188           conv_func = evas_common_convert_func_get(0, buf->w, buf->h, d,
189                                                    buf->priv.mask.r,
190                                                    buf->priv.mask.g,
191                                                    buf->priv.mask.b,
192                                                    PAL_MODE_NONE,
193                                                    buf->rot);
194         else if (buf->rot == 90 || buf->rot == 270)
195           conv_func = evas_common_convert_func_get(0, buf->h, buf->w, d,
196                                                    buf->priv.mask.r,
197                                                    buf->priv.mask.g,
198                                                    buf->priv.mask.b,
199                                                    PAL_MODE_NONE,
200                                                    buf->rot);
201      }
202    if (!conv_func)
203      {
204         ERR("At depth: %i, RGB format mask: %08x %08x %08x, "
205             "Palette mode: %i. "
206             "Not supported by compiled in converters!",
207             buf->priv.x11.xlib.depth,
208             buf->priv.mask.r,
209             buf->priv.mask.g,
210             buf->priv.mask.b,
211             buf->priv.pal ? (int)buf->priv.pal->colors : -1);
212      }
213    return buf;
214 }
215 
216 void *
evas_software_xlib_swapbuf_new_region_for_update(Outbuf * buf,int x,int y,int w,int h,int * cx,int * cy,int * cw,int * ch)217 evas_software_xlib_swapbuf_new_region_for_update(Outbuf *buf, int x, int y, int w, int h, int *cx, int *cy, int *cw, int *ch)
218 {
219    RECTS_CLIP_TO_RECT(x, y, w, h, 0, 0, buf->w, buf->h);
220    if ((w <= 0) || (h <= 0)) return NULL;
221    // if rotation is 0, and 32bit argb, we can use the buffer directly
222    if ((buf->rot == 0) &&
223        (buf->priv.mask.r == 0xff0000) &&
224        (buf->priv.mask.g == 0x00ff00) &&
225        (buf->priv.mask.b == 0x0000ff))
226      {
227         RGBA_Image *im;
228         void *data;
229         int bpl = 0;
230         Eina_Rectangle *rect;
231 
232         im = buf->priv.onebuf;
233         if (!im)
234           {
235              int ww = 0, hh = 0;
236              int d, bpp;
237 
238              d = evas_xlib_swapper_depth_get(buf->priv.swapper);
239              bpp = d / 8;
240 
241              data = evas_xlib_swapper_buffer_map(buf->priv.swapper, &bpl,
242                                                  &(ww), &(hh));
243              // To take stride into account, we do use bpl as the real image width, but return the real useful one.
244              im = (RGBA_Image *)evas_cache_image_data(evas_common_image_cache_get(),
245                                                       bpl / bpp, hh, data,
246                                                       buf->priv.destination_alpha,
247                                                       EVAS_COLORSPACE_ARGB8888);
248              buf->priv.onebuf = im;
249              if (!im) return NULL;
250           }
251         rect = eina_rectangle_new(x, y, w, h);
252         if (!eina_array_push(&buf->priv.onebuf_regions, rect))
253           {
254              evas_cache_image_drop(&im->cache_entry);
255              eina_rectangle_free(rect);
256              return NULL;
257           }
258 
259         // the clip region of the onebuf to render
260         *cx = x;
261         *cy = y;
262         *cw = w;
263         *ch = h;
264         return im;
265      }
266    else
267      {
268         RGBA_Image *im;
269         Eina_Rectangle *rect;
270 
271         rect = eina_rectangle_new(x, y, w, h);
272         if (!rect) return NULL;
273         im = (RGBA_Image *)evas_cache_image_empty(evas_common_image_cache_get());
274         if (!im)
275           {
276              eina_rectangle_free(rect);
277              return NULL;
278           }
279         im->cache_entry.flags.alpha |= buf->priv.destination_alpha ? 1 : 0;
280         evas_cache_image_surface_alloc(&im->cache_entry, w, h);
281         im->extended_info = rect;
282         buf->priv.pending_writes = eina_list_append(buf->priv.pending_writes, im);
283 
284         // the region is the update image
285         *cx = 0;
286         *cy = 0;
287         *cw = w;
288         *ch = h;
289         return im;
290      }
291    return NULL;
292 }
293 
294 void
evas_software_xlib_swapbuf_flush(Outbuf * buf,Tilebuf_Rect * surface_damage EINA_UNUSED,Tilebuf_Rect * buffer_damage EINA_UNUSED,Evas_Render_Mode render_mode)295 evas_software_xlib_swapbuf_flush(Outbuf *buf, Tilebuf_Rect *surface_damage EINA_UNUSED, Tilebuf_Rect *buffer_damage EINA_UNUSED, Evas_Render_Mode render_mode)
296 {
297    if (render_mode == EVAS_RENDER_MODE_ASYNC_INIT) return;
298 
299    if (!buf->priv.pending_writes)
300      {
301         Eina_Rectangle *result, *rect;
302         Eina_Array_Iterator it;
303         unsigned int n, i;
304         RGBA_Image *im;
305 
306         n = eina_array_count_get(&buf->priv.onebuf_regions);
307         if (n == 0) return;
308         result = alloca(n * sizeof(Eina_Rectangle));
309         EINA_ARRAY_ITER_NEXT(&buf->priv.onebuf_regions, i, rect, it)
310         {
311            result[i] = *rect;
312            eina_rectangle_free(rect);
313         }
314         evas_xlib_swapper_buffer_unmap(buf->priv.swapper);
315         evas_xlib_swapper_swap(buf->priv.swapper, result, n);
316         eina_array_clean(&buf->priv.onebuf_regions);
317         im = buf->priv.onebuf;
318         buf->priv.onebuf = NULL;
319         if (im)
320           evas_cache_image_drop(&im->cache_entry);
321      }
322    else
323      {
324         RGBA_Image *im;
325         Eina_Rectangle *result;
326         unsigned int n, i = 0;
327 
328         n = eina_list_count(buf->priv.pending_writes);
329         if (n == 0) return;
330         result = alloca(n * sizeof(Eina_Rectangle));
331         EINA_LIST_FREE(buf->priv.pending_writes, im)
332           {
333              Eina_Rectangle *rect = im->extended_info;
334              int x, y, w, h;
335 
336              x = rect->x; y = rect->y; w = rect->w; h = rect->h;
337              if (buf->rot == 0)
338                {
339                   result[i].x = x;
340                   result[i].y = y;
341                }
342              else if (buf->rot == 90)
343                {
344                   result[i].x = y;
345                   result[i].y = buf->w - x - w;
346                }
347              else if (buf->rot == 180)
348                {
349                   result[i].x = buf->w - x - w;
350                   result[i].y = buf->h - y - h;
351                }
352              else if (buf->rot == 270)
353                {
354                   result[i].x = buf->h - y - h;
355                   result[i].y = x;
356                }
357              if ((buf->rot == 0) || (buf->rot == 180))
358                {
359                   result[i].w = w;
360                   result[i].h = h;
361                }
362              else if ((buf->rot == 90) || (buf->rot == 270))
363                {
364                   result[i].w = h;
365                   result[i].h = w;
366                }
367              eina_rectangle_free(rect);
368              evas_cache_image_drop(&im->cache_entry);
369              i++;
370           }
371         evas_xlib_swapper_buffer_unmap(buf->priv.swapper);
372         evas_xlib_swapper_swap(buf->priv.swapper, result, n);
373 //        evas_xlib_swapper_swap(buf->priv.swapper, NULL, 0);
374      }
375 }
376 
377 void
evas_software_xlib_swapbuf_idle_flush(Outbuf * buf EINA_UNUSED)378 evas_software_xlib_swapbuf_idle_flush(Outbuf *buf EINA_UNUSED)
379 {
380    return;
381 }
382 
383 void
evas_software_xlib_swapbuf_push_updated_region(Outbuf * buf,RGBA_Image * update,int x,int y,int w,int h)384 evas_software_xlib_swapbuf_push_updated_region(Outbuf *buf, RGBA_Image *update, int x, int y, int w, int h)
385 {
386    Gfx_Func_Convert conv_func = NULL;
387    Eina_Rectangle r = { 0, 0, 0, 0 }, pr;
388    int d, bpl = 0, wid, bpp, rx = 0, ry = 0, ww = 0, hh = 0;
389    DATA32 *src_data;
390    DATA8 *dst_data;
391 
392    if (!buf->priv.pending_writes) return;
393    d = evas_xlib_swapper_depth_get(buf->priv.swapper);
394    bpp = d / 8;
395    if (bpp <= 0) return;
396    if (buf->priv.pal)
397      {
398         if ((buf->rot == 0) || (buf->rot == 180))
399           conv_func = evas_common_convert_func_get(0, w, h, d,
400                                                    buf->priv.mask.r,
401                                                    buf->priv.mask.g,
402                                                    buf->priv.mask.b,
403                                                    buf->priv.pal->colors,
404                                                    buf->rot);
405         else if ((buf->rot == 90) || (buf->rot == 270))
406           conv_func = evas_common_convert_func_get(0, h, w, d,
407                                                    buf->priv.mask.r,
408                                                    buf->priv.mask.g,
409                                                    buf->priv.mask.b,
410                                                    buf->priv.pal->colors,
411                                                    buf->rot);
412      }
413    else
414      {
415         if ((buf->rot == 0) || (buf->rot == 180))
416           conv_func = evas_common_convert_func_get(0, w, h, d,
417                                                    buf->priv.mask.r,
418                                                    buf->priv.mask.g,
419                                                    buf->priv.mask.b,
420                                                    PAL_MODE_NONE,
421                                                    buf->rot);
422         else if ((buf->rot == 90) || (buf->rot == 270))
423           conv_func = evas_common_convert_func_get(0, h, w, d,
424                                                    buf->priv.mask.r,
425                                                    buf->priv.mask.g,
426                                                    buf->priv.mask.b,
427                                                    PAL_MODE_NONE,
428                                                    buf->rot);
429      }
430    if (!conv_func) return;
431    if (buf->rot == 0)
432      {
433         r.x = x;
434         r.y = y;
435      }
436    else if (buf->rot == 90)
437      {
438         r.x = y;
439         r.y = buf->w - x - w;
440      }
441    else if (buf->rot == 180)
442      {
443         r.x = buf->w - x - w;
444         r.y = buf->h - y - h;
445      }
446    else if (buf->rot == 270)
447      {
448         r.x = buf->h - y - h;
449         r.y = x;
450      }
451    if ((buf->rot == 0) || (buf->rot == 180))
452      {
453         r.w = w;
454         r.h = h;
455      }
456    else if ((buf->rot == 90) || (buf->rot == 270))
457      {
458         r.w = h;
459         r.h = w;
460      }
461    src_data = update->image.data;
462    if (!src_data) return;
463    if ((buf->rot == 0) || (buf->rot == 180))
464      {
465         dst_data = evas_xlib_swapper_buffer_map(buf->priv.swapper, &bpl,
466                                                 &(ww), &(hh));
467         if (!dst_data) return;
468         if (buf->rot == 0)
469           {
470              RECTS_CLIP_TO_RECT(r.x, r.y, r.w, r.h, 0, 0, ww, hh);
471              dst_data += (bpl * r.y) + (r.x * bpp);
472              w -= rx;
473           }
474         else if (buf->rot == 180)
475           {
476              pr = r;
477              RECTS_CLIP_TO_RECT(r.x, r.y, r.w, r.h, 0, 0, ww, hh);
478              rx = pr.w - r.w; ry = pr.h - r.h;
479              src_data += (update->cache_entry.w * ry) + rx;
480              w -= rx;
481           }
482      }
483    else
484      {
485         dst_data = evas_xlib_swapper_buffer_map(buf->priv.swapper, &bpl,
486                                                 &(ww), &(hh));
487         if (!dst_data) return;
488         if (buf->rot == 90)
489           {
490              pr = r;
491              RECTS_CLIP_TO_RECT(r.x, r.y, r.w, r.h, 0, 0, ww, hh);
492              rx = pr.w - r.w; ry = pr.h - r.h;
493              src_data += ry;
494              w -= ry;
495           }
496         else if (buf->rot == 270)
497           {
498              pr = r;
499              RECTS_CLIP_TO_RECT(r.x, r.y, r.w, r.h, 0, 0, ww, hh);
500              rx = pr.w - r.w; ry = pr.h - r.h;
501              src_data += (update->cache_entry.w * rx);
502              w -= ry;
503           }
504      }
505    if ((r.w <= 0) || (r.h <= 0)) return;
506    wid = bpl / bpp;
507    dst_data += (bpl * r.y) + (r.x * bpp);
508    if (buf->priv.pal)
509      conv_func(src_data, dst_data,
510                update->cache_entry.w - w,
511                wid - r.w,
512                r.w, r.h,
513                x + rx, y + ry,
514                buf->priv.pal->lookup);
515    else
516      conv_func(src_data, dst_data,
517                update->cache_entry.w - w,
518                wid - r.w,
519                r.w, r.h,
520                x + rx, y + ry,
521                NULL);
522 }
523 
524 void
evas_software_xlib_swapbuf_reconfigure(Outbuf * buf,int w,int h,int rot,Outbuf_Depth depth)525 evas_software_xlib_swapbuf_reconfigure(Outbuf *buf, int w, int h, int rot,
526                                        Outbuf_Depth depth)
527 {
528    if ((w == buf->w) && (h == buf->h) && (rot == buf->rot) &&
529        (depth == buf->depth))
530      return;
531    buf->w = w;
532    buf->h = h;
533    buf->rot = rot;
534    evas_xlib_swapper_free(buf->priv.swapper);
535    if ((buf->rot == 0) || (buf->rot == 180))
536      buf->priv.swapper = evas_xlib_swapper_new(buf->priv.x11.xlib.disp,
537                                                buf->priv.x11.xlib.win,
538                                                buf->priv.x11.xlib.vis,
539                                                buf->priv.x11.xlib.depth,
540                                                buf->w, buf->h);
541    else if ((buf->rot == 90) || (buf->rot == 270))
542      buf->priv.swapper = evas_xlib_swapper_new(buf->priv.x11.xlib.disp,
543                                                buf->priv.x11.xlib.win,
544                                                buf->priv.x11.xlib.vis,
545                                                buf->priv.x11.xlib.depth,
546                                                buf->h, buf->w);
547 }
548 
549 int
evas_software_xlib_swapbuf_get_rot(Outbuf * buf)550 evas_software_xlib_swapbuf_get_rot(Outbuf *buf)
551 {
552    return buf->rot;
553 }
554 
555 Eina_Bool
evas_software_xlib_swapbuf_alpha_get(Outbuf * buf)556 evas_software_xlib_swapbuf_alpha_get(Outbuf *buf)
557 {
558    return buf->priv.destination_alpha;
559 }
560 
561 Render_Output_Swap_Mode
evas_software_xlib_swapbuf_buffer_state_get(Outbuf * buf)562 evas_software_xlib_swapbuf_buffer_state_get(Outbuf *buf)
563 {
564    if (!buf->priv.swapper) return MODE_FULL;
565    return evas_xlib_swapper_buffer_state_get(buf->priv.swapper);
566 }
567 
568