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 #include "evas_xlib_outbuf.h"
11 #include "evas_xlib_buffer.h"
12 #include "evas_xlib_color.h"
13 
14 typedef struct _Outbuf_Region Outbuf_Region;
15 
16 struct _Outbuf_Region
17 {
18    X_Output_Buffer *xob;
19    X_Output_Buffer *mxob;
20    int              x;
21    int              y;
22    int              w;
23    int              h;
24 };
25 
26 static Eina_Bool shmpool_initted = EINA_FALSE;
27 static Eina_List *shmpool = NULL;
28 static int shmsize = 0;
29 static int shmmemlimit = 0;
30 static const unsigned int shmcountlimit = 32;
31 
32 static Eina_Spinlock shmpool_lock;
33 #define SHMPOOL_LOCK()   eina_spinlock_take(&shmpool_lock)
34 #define SHMPOOL_UNLOCK() eina_spinlock_release(&shmpool_lock)
35 
36 static X_Output_Buffer *
_find_xob(Display * d,Visual * v,int depth,int w,int h,int shm,void * data)37 _find_xob(Display *d, Visual *v, int depth, int w, int h, int shm, void *data)
38 {
39    Eina_List *l, *xl = NULL;
40    X_Output_Buffer *xob = NULL;
41    X_Output_Buffer *xob2;
42    int fitness = 0x7fffffff;
43    int sz, lbytes, bpp;
44 
45    if (!shm)
46      return evas_software_xlib_x_output_buffer_new(d, v, depth, w, h, shm, data);
47    if (depth > 1)
48      {
49         bpp = depth / 8;
50         if (bpp == 3) bpp = 4;
51         lbytes = (((w * bpp) + 3) / 4) * 4;
52      }
53    else
54      lbytes = ((w + 63) / 64) * 8;
55    sz = lbytes * h;
56    SHMPOOL_LOCK();
57    EINA_LIST_FOREACH(shmpool, l, xob2)
58      {
59         int szdif;
60 
61         if ((xob2->xim->depth != depth) || (xob2->visual != v) ||
62             (xob2->display != d) || (xob2->w != w))
63           continue;
64         szdif = xob2->psize - sz;
65         if (szdif < 0) continue;
66         if (szdif == 0)
67           {
68              xob = xob2;
69              xl = l;
70              goto have_xob;
71           }
72         if (szdif < fitness)
73           {
74              fitness = szdif;
75              xob = xob2;
76              xl = l;
77           }
78      }
79    if (
80      (fitness > (400 * 400)) ||
81      (!xob)
82      )
83      {
84         SHMPOOL_UNLOCK();
85         xob = evas_software_xlib_x_output_buffer_new(d, v, depth, w, h, shm, data);
86         return xob;
87      }
88 
89 have_xob:
90    shmpool = eina_list_remove_list(shmpool, xl);
91    xob->w = w;
92    xob->h = h;
93 //   xob->bpl = lbytes;
94    xob->xim->width = xob->w;
95    xob->xim->height = xob->h;
96    xob->xim->bytes_per_line = xob->bpl;
97    shmsize -= xob->psize * (xob->xim->depth / 8);
98    SHMPOOL_UNLOCK();
99    return xob;
100 }
101 
102 static void
_unfind_xob(X_Output_Buffer * xob,int psync)103 _unfind_xob(X_Output_Buffer *xob, int psync)
104 {
105    if (xob->shm_info)
106      {
107         SHMPOOL_LOCK();
108         shmpool = eina_list_prepend(shmpool, xob);
109         shmsize += xob->psize * xob->xim->depth / 8;
110         while ((shmsize > (shmmemlimit)) ||
111                (eina_list_count(shmpool) > shmcountlimit))
112           {
113              Eina_List *xl;
114 
115              xl = eina_list_last(shmpool);
116              if (!xl)
117                {
118                   shmsize = 0;
119                   break;
120                }
121              xob = xl->data;
122              shmpool = eina_list_remove_list(shmpool, xl);
123              shmsize -= xob->psize * xob->xim->depth / 8;
124              evas_software_xlib_x_output_buffer_unref(xob, psync);
125           }
126         SHMPOOL_UNLOCK();
127      }
128    else
129      {
130         SHMPOOL_LOCK();
131         evas_software_xlib_x_output_buffer_unref(xob, psync);
132         SHMPOOL_UNLOCK();
133      }
134 }
135 
136 static void
_clear_xob(int psync)137 _clear_xob(int psync)
138 {
139    SHMPOOL_LOCK();
140    while (shmpool)
141      {
142         X_Output_Buffer *xob;
143 
144         xob = shmpool->data;
145         shmpool = eina_list_remove_list(shmpool, shmpool);
146         evas_software_xlib_x_output_buffer_unref(xob, psync);
147      }
148    shmsize = 0;
149    SHMPOOL_UNLOCK();
150 }
151 
152 void
evas_software_xlib_outbuf_init(void)153 evas_software_xlib_outbuf_init(void)
154 {
155    if (!shmpool_initted)
156      {
157         shmpool_initted = EINA_TRUE;
158         eina_spinlock_new(&shmpool_lock);
159      }
160 }
161 
162 void
evas_software_xlib_outbuf_free(Outbuf * buf)163 evas_software_xlib_outbuf_free(Outbuf *buf)
164 {
165    SHMPOOL_LOCK();
166    shmmemlimit -= ((buf->w * buf->h * (buf->depth / 8)) * 3) / 2;
167    SHMPOOL_UNLOCK();
168    eina_spinlock_take(&(buf->priv.lock));
169    while (buf->priv.pending_writes)
170      {
171         RGBA_Image *im;
172         Outbuf_Region *obr;
173 
174         im = buf->priv.pending_writes->data;
175         buf->priv.pending_writes = eina_list_remove_list(buf->priv.pending_writes, buf->priv.pending_writes);
176         obr = im->extended_info;
177         evas_cache_image_drop(&im->cache_entry);
178         if (obr->xob) _unfind_xob(obr->xob, 0);
179         if (obr->mxob) _unfind_xob(obr->mxob, 0);
180         free(obr);
181      }
182    eina_spinlock_release(&(buf->priv.lock));
183    evas_software_xlib_outbuf_idle_flush(buf);
184    evas_software_xlib_outbuf_flush(buf, NULL, NULL, EVAS_RENDER_MODE_UNDEF);
185    if (buf->priv.x11.xlib.gc)
186      XFreeGC(buf->priv.x11.xlib.disp, buf->priv.x11.xlib.gc);
187    if (buf->priv.x11.xlib.gcm)
188      XFreeGC(buf->priv.x11.xlib.disp, buf->priv.x11.xlib.gcm);
189    if (buf->priv.pal)
190      evas_software_xlib_x_color_deallocate(buf->priv.x11.xlib.disp, buf->priv.x11.xlib.cmap,
191                                            buf->priv.x11.xlib.vis, buf->priv.pal);
192 
193    /* safe because no effect on the default colormap */
194    XFreeColormap(buf->priv.x11.xlib.disp, buf->priv.x11.xlib.cmap);
195 
196    eina_array_flush(&buf->priv.onebuf_regions);
197    eina_spinlock_free(&(buf->priv.lock));
198    free(buf);
199    _clear_xob(1);
200 }
201 
202 Outbuf *
evas_software_xlib_outbuf_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,int shape_dither,int destination_alpha)203 evas_software_xlib_outbuf_setup_x(int w, int h, int rot, Outbuf_Depth depth,
204                                   Display *disp, Drawable draw, Visual *vis,
205                                   Colormap cmap, int x_depth,
206                                   int grayscale, int max_colors, Pixmap mask,
207                                   int shape_dither, int destination_alpha)
208 {
209    Outbuf *buf;
210 
211    buf = calloc(1, sizeof(Outbuf));
212    if (!buf)
213      return NULL;
214 
215    if (x_depth < 15) rot = 0;
216 
217    buf->w = w;
218    buf->h = h;
219    buf->depth = depth;
220    buf->rot = rot;
221 
222    buf->priv.x11.xlib.disp = disp;
223    buf->priv.x11.xlib.vis = vis;
224    buf->priv.x11.xlib.cmap = cmap;
225    buf->priv.x11.xlib.depth = x_depth;
226 
227    buf->priv.mask_dither = shape_dither;
228    buf->priv.destination_alpha = destination_alpha;
229 
230    eina_array_step_set(&buf->priv.onebuf_regions, sizeof (Eina_Array), 8);
231 
232    {
233       Gfx_Func_Convert conv_func;
234       X_Output_Buffer *xob;
235 
236       buf->priv.x11.xlib.shm = evas_software_xlib_x_can_do_shm(buf->priv.x11.xlib.disp);
237       xob = evas_software_xlib_x_output_buffer_new(buf->priv.x11.xlib.disp,
238                                                    buf->priv.x11.xlib.vis,
239                                                    buf->priv.x11.xlib.depth,
240                                                    1, 1, buf->priv.x11.xlib.shm, NULL);
241       conv_func = NULL;
242       if (xob)
243         {
244 #ifdef WORDS_BIGENDIAN
245            if (evas_software_xlib_x_output_buffer_byte_order(xob) == LSBFirst)
246              buf->priv.x11.xlib.swap = 1;
247            if (evas_software_xlib_x_output_buffer_bit_order(xob) == MSBFirst)
248              buf->priv.x11.xlib.bit_swap = 1;
249 #else
250            if (evas_software_xlib_x_output_buffer_byte_order(xob) == MSBFirst)
251              buf->priv.x11.xlib.swap = 1;
252            if (evas_software_xlib_x_output_buffer_bit_order(xob) == MSBFirst)
253              buf->priv.x11.xlib.bit_swap = 1;
254 #endif
255            if (((vis->class == TrueColor) || (vis->class == DirectColor)) &&
256                (x_depth > 8))
257              {
258                 buf->priv.mask.r = (DATA32)vis->red_mask;
259                 buf->priv.mask.g = (DATA32)vis->green_mask;
260                 buf->priv.mask.b = (DATA32)vis->blue_mask;
261                 if (buf->priv.x11.xlib.swap)
262                   {
263                      SWAP32(buf->priv.mask.r);
264                      SWAP32(buf->priv.mask.g);
265                      SWAP32(buf->priv.mask.b);
266                   }
267              }
268            else if ((vis->class == PseudoColor) ||
269                     (vis->class == StaticColor) ||
270                     (vis->class == GrayScale) ||
271                     (vis->class == StaticGray) ||
272                     (x_depth <= 8))
273              {
274                 Convert_Pal_Mode pm = PAL_MODE_RGB332;
275 
276                 if ((vis->class == GrayScale) || (vis->class == StaticGray))
277                   grayscale = 1;
278                 if (grayscale)
279                   {
280                      if (max_colors >= 256)
281                        pm = PAL_MODE_GRAY256;
282                      else if (max_colors >= 64)
283                        pm = PAL_MODE_GRAY64;
284                      else if (max_colors >= 16)
285                        pm = PAL_MODE_GRAY16;
286                      else if (max_colors >= 4)
287                        pm = PAL_MODE_GRAY4;
288                      else
289                        pm = PAL_MODE_MONO;
290                   }
291                 else
292                   {
293                      if (max_colors >= 256)
294                        pm = PAL_MODE_RGB332;
295                      else if (max_colors >= 216)
296                        pm = PAL_MODE_RGB666;
297                      else if (max_colors >= 128)
298                        pm = PAL_MODE_RGB232;
299                      else if (max_colors >= 64)
300                        pm = PAL_MODE_RGB222;
301                      else if (max_colors >= 32)
302                        pm = PAL_MODE_RGB221;
303                      else if (max_colors >= 16)
304                        pm = PAL_MODE_RGB121;
305                      else if (max_colors >= 8)
306                        pm = PAL_MODE_RGB111;
307                      else if (max_colors >= 4)
308                        pm = PAL_MODE_GRAY4;
309                      else
310                        pm = PAL_MODE_MONO;
311                   }
312                 /* FIXME: only alloc once per display+cmap */
313                 buf->priv.pal = evas_software_xlib_x_color_allocate(disp, cmap, vis,
314                                                                     pm);
315                 if (!buf->priv.pal)
316                   {
317                      if (xob) evas_software_xlib_x_output_buffer_unref(xob, 1);
318                      free(buf);
319                      return NULL;
320                   }
321              }
322            if (buf->priv.pal)
323              {
324                 if (buf->rot == 0 || buf->rot == 180)
325                   conv_func = evas_common_convert_func_get(0, buf->w, buf->h,
326                                                            evas_software_xlib_x_output_buffer_depth
327                                                              (xob), buf->priv.mask.r,
328                                                            buf->priv.mask.g,
329                                                            buf->priv.mask.b,
330                                                            buf->priv.pal->colors,
331                                                            buf->rot);
332                 else if (buf->rot == 90 || buf->rot == 270)
333                   conv_func = evas_common_convert_func_get(0, buf->h, buf->w,
334                                                            evas_software_xlib_x_output_buffer_depth
335                                                              (xob), buf->priv.mask.r,
336                                                            buf->priv.mask.g,
337                                                            buf->priv.mask.b,
338                                                            buf->priv.pal->colors,
339                                                            buf->rot);
340              }
341            else
342              {
343                 if (buf->rot == 0 || buf->rot == 180)
344                   conv_func = evas_common_convert_func_get(0, buf->w, buf->h,
345                                                            evas_software_xlib_x_output_buffer_depth
346                                                              (xob), buf->priv.mask.r,
347                                                            buf->priv.mask.g,
348                                                            buf->priv.mask.b, PAL_MODE_NONE,
349                                                            buf->rot);
350                 else if (buf->rot == 90 || buf->rot == 270)
351                   conv_func = evas_common_convert_func_get(0, buf->h, buf->w,
352                                                            evas_software_xlib_x_output_buffer_depth
353                                                              (xob), buf->priv.mask.r,
354                                                            buf->priv.mask.g,
355                                                            buf->priv.mask.b, PAL_MODE_NONE,
356                                                            buf->rot);
357              }
358            buf->priv.x11.xlib.imdepth = evas_software_xlib_x_output_buffer_depth(xob);
359            evas_software_xlib_x_output_buffer_unref(xob, 1);
360            if (!conv_func)
361              {
362                 ERR("At depth: %i, RGB format mask: %08x %08x %08x, "
363                     "Palette mode: %i. "
364                     "Not supported by compiled in converters!",
365                     buf->priv.x11.xlib.depth,
366                     buf->priv.mask.r,
367                     buf->priv.mask.g,
368                     buf->priv.mask.b,
369                     buf->priv.pal ? (int)buf->priv.pal->colors : -1);
370              }
371         }
372       evas_software_xlib_outbuf_drawable_set(buf, draw);
373       evas_software_xlib_outbuf_mask_set(buf, mask);
374    }
375    eina_spinlock_new(&(buf->priv.lock));
376    SHMPOOL_LOCK();
377    shmmemlimit += ((buf->w * buf->h * (buf->depth / 8)) * 3) / 2;
378    SHMPOOL_UNLOCK();
379    return buf;
380 }
381 
382 void *
evas_software_xlib_outbuf_new_region_for_update(Outbuf * buf,int x,int y,int w,int h,int * cx,int * cy,int * cw,int * ch)383 evas_software_xlib_outbuf_new_region_for_update(Outbuf *buf, int x, int y, int w, int h, int *cx, int *cy, int *cw, int *ch)
384 {
385    RGBA_Image *im;
386    Outbuf_Region *obr;
387    int bpl = 0;
388    int use_shm = 1;
389    int alpha;
390 
391    eina_spinlock_take(&(buf->priv.lock));
392    if ((buf->onebuf) && (buf->priv.x11.xlib.shm))
393      {
394         Eina_Rectangle *rect;
395 
396         RECTS_CLIP_TO_RECT(x, y, w, h, 0, 0, buf->w, buf->h);
397 
398         rect = eina_rectangle_new(x, y, w, h);
399         if (!rect)
400           {
401              eina_spinlock_release(&(buf->priv.lock));
402              return NULL;
403           }
404 
405         if ((eina_array_push(&buf->priv.onebuf_regions, rect)) &&
406             (buf->priv.onebuf))
407           {
408              *cx = x;
409              *cy = y;
410              *cw = w;
411              *ch = h;
412              if (!buf->priv.synced)
413                {
414                   XSync(buf->priv.x11.xlib.disp, False);
415                   buf->priv.synced = 1;
416                }
417              eina_spinlock_release(&(buf->priv.lock));
418              return buf->priv.onebuf;
419           }
420 
421         if (rect) eina_rectangle_free(rect);
422 
423         obr = calloc(1, sizeof(Outbuf_Region));
424         if (!obr)
425           {
426              eina_spinlock_release(&(buf->priv.lock));
427              return NULL;
428           }
429 
430         obr->x = 0;
431         obr->y = 0;
432         obr->w = buf->w;
433         obr->h = buf->h;
434         *cx = x;
435         *cy = y;
436         *cw = w;
437         *ch = h;
438 
439         alpha = ((buf->priv.x11.xlib.mask) || (buf->priv.destination_alpha));
440 
441         use_shm = buf->priv.x11.xlib.shm;
442         if ((buf->rot == 0) &&
443             (buf->priv.x11.xlib.imdepth == 32) &&
444             (buf->priv.mask.r == 0xff0000) &&
445             (buf->priv.mask.g == 0x00ff00) &&
446             (buf->priv.mask.b == 0x0000ff))
447           {
448              obr->xob = evas_software_xlib_x_output_buffer_new(buf->priv.x11.xlib.disp,
449                                                                buf->priv.x11.xlib.vis,
450                                                                buf->priv.x11.xlib.depth,
451                                                                buf->w, buf->h,
452                                                                use_shm,
453                                                                NULL);
454              if (!obr->xob)
455                {
456                   free(obr);
457                   eina_spinlock_release(&(buf->priv.lock));
458                   return NULL;
459                }
460              im = (RGBA_Image *)evas_cache_image_data(evas_common_image_cache_get(),
461                                                       buf->w, buf->h,
462                                                       (DATA32 *)evas_software_xlib_x_output_buffer_data(obr->xob, &bpl),
463                                                       alpha, EVAS_COLORSPACE_ARGB8888);
464              if (!im)
465                {
466                   evas_software_xlib_x_output_buffer_unref(obr->xob, 0);
467                   free(obr);
468                   eina_spinlock_release(&(buf->priv.lock));
469                   return NULL;
470                }
471              im->extended_info = obr;
472              if (buf->priv.x11.xlib.mask)
473                obr->mxob = evas_software_xlib_x_output_buffer_new(buf->priv.x11.xlib.disp,
474                                                                   buf->priv.x11.xlib.vis,
475                                                                   1,
476                                                                   buf->w, buf->h,
477                                                                   use_shm,
478                                                                   NULL);
479           }
480         else
481           {
482              im = (RGBA_Image *)evas_cache_image_empty(evas_common_image_cache_get());
483              if (!im)
484                {
485                   free(obr);
486                   eina_spinlock_release(&(buf->priv.lock));
487                   return NULL;
488                }
489              im->cache_entry.flags.alpha |= alpha ? 1 : 0;
490              evas_cache_image_surface_alloc(&im->cache_entry, buf->w, buf->h);
491              im->extended_info = obr;
492              if ((buf->rot == 0) || (buf->rot == 180))
493                {
494                   obr->xob = evas_software_xlib_x_output_buffer_new(buf->priv.x11.xlib.disp,
495                                                                     buf->priv.x11.xlib.vis,
496                                                                     buf->priv.x11.xlib.depth,
497                                                                     buf->w, buf->h,
498                                                                     use_shm,
499                                                                     NULL);
500                   if (!obr->xob)
501                     {
502                        evas_cache_image_drop(&im->cache_entry);
503                        free(obr);
504                        eina_spinlock_release(&(buf->priv.lock));
505                        return NULL;
506                     }
507                   if (buf->priv.x11.xlib.mask)
508                     obr->mxob = evas_software_xlib_x_output_buffer_new(buf->priv.x11.xlib.disp,
509                                                                        buf->priv.x11.xlib.vis,
510                                                                        1, buf->w, buf->h,
511                                                                        use_shm,
512                                                                        NULL);
513                }
514              else if ((buf->rot == 90) || (buf->rot == 270))
515                {
516                   obr->xob = evas_software_xlib_x_output_buffer_new(buf->priv.x11.xlib.disp,
517                                                                     buf->priv.x11.xlib.vis,
518                                                                     buf->priv.x11.xlib.depth,
519                                                                     buf->h, buf->w,
520                                                                     use_shm,
521                                                                     NULL);
522                   if (!obr->xob)
523                     {
524                        evas_cache_image_drop(&im->cache_entry);
525                        free(obr);
526                        eina_spinlock_release(&(buf->priv.lock));
527                        return NULL;
528                     }
529                   if (buf->priv.x11.xlib.mask)
530                     obr->mxob = evas_software_xlib_x_output_buffer_new(buf->priv.x11.xlib.disp,
531                                                                        buf->priv.x11.xlib.vis,
532                                                                        1, buf->h, buf->w,
533                                                                        use_shm,
534                                                                        NULL);
535                }
536           }
537         /* FIXME: We should be able to remove this memset, but somewhere in the process
538            we copy too much to the destination surface and some area are not cleaned before copy. */
539         if ((alpha) && (im->image.data))
540           {
541              /* FIXME: faster memset! */
542 //             memset(im->image.data, 0, w * h * sizeof(DATA32));
543           }
544 
545         buf->priv.onebuf = im;
546         eina_spinlock_release(&(buf->priv.lock));
547         return im;
548      }
549 
550    obr = calloc(1, sizeof(Outbuf_Region));
551    if (!obr)
552      {
553         eina_spinlock_release(&(buf->priv.lock));
554         return NULL;
555      }
556    obr->x = x;
557    obr->y = y;
558    obr->w = w;
559    obr->h = h;
560    *cx = 0;
561    *cy = 0;
562    *cw = w;
563    *ch = h;
564 
565    use_shm = buf->priv.x11.xlib.shm;
566    /* FIXME: magic - i found if shm regions are smaller than 200x200 its
567     * faster to use ximages over unix sockets - trial and error
568     */
569 //   use_shm = 0; /* 630 -> 1006 fps */
570 //   if ((w * h) < (200 * 200)) use_shm = 0; /* 630 -> 962 fps */
571 
572    alpha = ((buf->priv.x11.xlib.mask) || (buf->priv.destination_alpha));
573 
574    if ((buf->rot == 0) &&
575        (buf->priv.x11.xlib.imdepth == 32) &&
576        (buf->priv.mask.r == 0xff0000) &&
577        (buf->priv.mask.g == 0x00ff00) &&
578        (buf->priv.mask.b == 0x0000ff))
579      {
580         obr->xob = _find_xob(buf->priv.x11.xlib.disp,
581                              buf->priv.x11.xlib.vis,
582                              buf->priv.x11.xlib.depth,
583                              w, h,
584                              use_shm,
585                              NULL);
586         if (!obr->xob)
587           {
588              free(obr);
589              eina_spinlock_release(&(buf->priv.lock));
590              return NULL;
591           }
592         im = (RGBA_Image *)evas_cache_image_data(evas_common_image_cache_get(),
593                                                  w, h,
594                                                  (DATA32 *)evas_software_xlib_x_output_buffer_data(obr->xob, &bpl),
595                                                  alpha, EVAS_COLORSPACE_ARGB8888);
596         if (!im)
597           {
598              _unfind_xob(obr->xob, 0);
599              free(obr);
600              eina_spinlock_release(&(buf->priv.lock));
601              return NULL;
602           }
603         im->extended_info = obr;
604         if (buf->priv.x11.xlib.mask)
605           obr->mxob = _find_xob(buf->priv.x11.xlib.disp,
606                                 buf->priv.x11.xlib.vis,
607                                 1, w, h,
608                                 use_shm,
609                                 NULL);
610      }
611    else
612      {
613         im = (RGBA_Image *)evas_cache_image_empty(evas_common_image_cache_get());
614         if (!im)
615           {
616              free(obr);
617              eina_spinlock_release(&(buf->priv.lock));
618              return NULL;
619           }
620         im->cache_entry.w = w;
621         im->cache_entry.h = h;
622         im->cache_entry.flags.alpha |= alpha ? 1 : 0;
623         evas_cache_image_surface_alloc(&im->cache_entry, w, h);
624         im->extended_info = obr;
625         if ((buf->rot == 0) || (buf->rot == 180))
626           {
627              obr->xob = _find_xob(buf->priv.x11.xlib.disp,
628                                   buf->priv.x11.xlib.vis,
629                                   buf->priv.x11.xlib.depth,
630                                   w, h,
631                                   use_shm,
632                                   NULL);
633              if (!obr->xob)
634                {
635                   evas_cache_image_drop(&im->cache_entry);
636                   free(obr);
637                   eina_spinlock_release(&(buf->priv.lock));
638                   return NULL;
639                }
640              if (buf->priv.x11.xlib.mask)
641                obr->mxob = _find_xob(buf->priv.x11.xlib.disp,
642                                      buf->priv.x11.xlib.vis,
643                                      1, w, h,
644                                      use_shm,
645                                      NULL);
646           }
647         else if ((buf->rot == 90) || (buf->rot == 270))
648           {
649              obr->xob = _find_xob(buf->priv.x11.xlib.disp,
650                                   buf->priv.x11.xlib.vis,
651                                   buf->priv.x11.xlib.depth,
652                                   h, w,
653                                   use_shm,
654                                   NULL);
655              if (!obr->xob)
656                {
657                   evas_cache_image_drop(&im->cache_entry);
658                   free(obr);
659                   eina_spinlock_release(&(buf->priv.lock));
660                   return NULL;
661                }
662              if (buf->priv.x11.xlib.mask)
663                obr->mxob = _find_xob(buf->priv.x11.xlib.disp,
664                                      buf->priv.x11.xlib.vis,
665                                      1, h, w,
666                                      use_shm,
667                                      NULL);
668           }
669      }
670    /* FIXME: We should be able to remove this memset, but somewhere in the process
671       we copy too much to the destination surface and some area are not cleaned before copy. */
672    if (((buf->priv.x11.xlib.mask) || (buf->priv.destination_alpha)) &&
673        (im->image.data))
674      {
675         /* FIXME: faster memset! */
676 //        memset(im->image.data, 0, w * h * sizeof(DATA32));
677      }
678 
679    buf->priv.pending_writes = eina_list_append(buf->priv.pending_writes, im);
680    eina_spinlock_release(&(buf->priv.lock));
681    return im;
682 }
683 
684 void
evas_software_xlib_outbuf_flush(Outbuf * buf,Tilebuf_Rect * surface_damage EINA_UNUSED,Tilebuf_Rect * buffer_damage EINA_UNUSED,Evas_Render_Mode render_mode EINA_UNUSED)685 evas_software_xlib_outbuf_flush(Outbuf *buf, Tilebuf_Rect *surface_damage EINA_UNUSED, Tilebuf_Rect *buffer_damage EINA_UNUSED, Evas_Render_Mode render_mode EINA_UNUSED)
686 {
687    Eina_List *l;
688    RGBA_Image *im;
689    Outbuf_Region *obr;
690 
691    eina_spinlock_take(&(buf->priv.lock));
692    if ((buf->priv.onebuf) && eina_array_count(&buf->priv.onebuf_regions))
693      {
694         Eina_Rectangle *rect;
695         Eina_Array_Iterator it;
696         unsigned int i;
697         Region tmpr;
698 
699         im = buf->priv.onebuf;
700         obr = im->extended_info;
701         tmpr = XCreateRegion();
702         EINA_ARRAY_ITER_NEXT(&buf->priv.onebuf_regions, i, rect, it)
703         {
704            XRectangle xr;
705 
706            if (buf->rot == 0)
707              {
708                 xr.x = rect->x;
709                 xr.y = rect->y;
710                 xr.width = rect->w;
711                 xr.height = rect->h;
712              }
713            else if (buf->rot == 90)
714              {
715                 xr.x = rect->y;
716                 xr.y = buf->w - rect->x - rect->w;
717                 xr.width = rect->h;
718                 xr.height = rect->w;
719              }
720            else if (buf->rot == 180)
721              {
722                 xr.x = buf->w - rect->x - rect->w;
723                 xr.y = buf->h - rect->y - rect->h;
724                 xr.width = rect->w;
725                 xr.height = rect->h;
726              }
727            else if (buf->rot == 270)
728              {
729                 xr.x = buf->h - rect->y - rect->h;
730                 xr.y = rect->x;
731                 xr.width = rect->h;
732                 xr.height = rect->w;
733              }
734            XUnionRectWithRegion(&xr, tmpr, tmpr);
735            if (buf->priv.debug)
736              evas_software_xlib_outbuf_debug_show(buf, buf->priv.x11.xlib.win,
737                                                   xr.x, xr.y, xr.width, xr.height);
738            eina_rectangle_free(rect);
739         }
740         eina_array_clean(&buf->priv.onebuf_regions);
741         XSetRegion(buf->priv.x11.xlib.disp, buf->priv.x11.xlib.gc, tmpr);
742         if (obr->xob)
743           {
744              evas_software_xlib_x_output_buffer_paste(obr->xob, buf->priv.x11.xlib.win,
745                                                       buf->priv.x11.xlib.gc,
746                                                       0, 0, 0);
747           }
748         if (obr->mxob)
749           {
750              XSetRegion(buf->priv.x11.xlib.disp, buf->priv.x11.xlib.gcm, tmpr);
751              evas_software_xlib_x_output_buffer_paste(obr->mxob,
752                                                       buf->priv.x11.xlib.mask,
753                                                       buf->priv.x11.xlib.gcm,
754                                                       0, 0, 0);
755           }
756         XDestroyRegion(tmpr);
757         buf->priv.synced = 0;
758      }
759    else
760      {
761 #if 1
762         XSync(buf->priv.x11.xlib.disp, False);
763         EINA_LIST_FOREACH(buf->priv.pending_writes, l, im)
764           {
765              obr = im->extended_info;
766              if (buf->priv.debug)
767                evas_software_xlib_outbuf_debug_show(buf, buf->priv.x11.xlib.win,
768                                                     obr->x, obr->y, obr->w, obr->h);
769              if (obr->xob)
770                {
771                   evas_software_xlib_x_output_buffer_paste(obr->xob, buf->priv.x11.xlib.win,
772                                                            buf->priv.x11.xlib.gc,
773                                                            obr->x, obr->y, 0);
774                }
775              if (obr->mxob)
776                evas_software_xlib_x_output_buffer_paste(obr->mxob,
777                                                         buf->priv.x11.xlib.mask,
778                                                         buf->priv.x11.xlib.gcm,
779                                                         obr->x, obr->y, 0);
780           }
781         while (buf->priv.prev_pending_writes)
782           {
783              im = buf->priv.prev_pending_writes->data;
784              buf->priv.prev_pending_writes =
785                eina_list_remove_list(buf->priv.prev_pending_writes,
786                                      buf->priv.prev_pending_writes);
787              obr = im->extended_info;
788              evas_cache_image_drop(&im->cache_entry);
789              if (obr->xob) _unfind_xob(obr->xob, 0);
790              if (obr->mxob) _unfind_xob(obr->mxob, 0);
791              free(obr);
792           }
793         buf->priv.prev_pending_writes = buf->priv.pending_writes;
794         buf->priv.pending_writes = NULL;
795         XFlush(buf->priv.x11.xlib.disp);
796 #else
797         /* XX async push - disable */
798         /*
799            EINA_LIST_FOREACH(buf->priv.pending_writes, l, im)
800            {
801              obr = im->extended_info;
802              if (buf->priv.debug)
803                evas_software_xlib_outbuf_debug_show(buf, buf->priv.x11.xlib.win,
804                                                    obr->x, obr->y, obr->w, obr->h);
805              evas_software_xlib_x_output_buffer_paste(obr->xob, buf->priv.x11.xlib.win,
806                                                      buf->priv.x11.xlib.gc,
807                                                      obr->x, obr->y, 0);
808              if (obr->mxob)
809                evas_software_xlib_x_output_buffer_paste(obr->mxob,
810                                                        buf->priv.x11.xlib.mask,
811                                                        buf->priv.x11.xlib.gcm,
812                                                        obr->x, obr->y, 0);
813            }
814          */
815         XSync(buf->priv.x11.xlib.disp, False);
816 
817         while (buf->priv.pending_writes)
818           {
819              RGBA_Image *im;
820              Outbuf_Region *obr;
821 
822              im = eina_list_data_get(buf->priv.pending_writes);
823              buf->priv.pending_writes = eina_list_remove_list(buf->priv.pending_writes, buf->priv.pending_writes);
824              obr = im->extended_info;
825              evas_cache_image_drop(&im->cache_entry);
826              if (obr->xob) _unfind_xob(obr->xob, 0);
827              if (obr->mxob) _unfind_xob(obr->mxob, 0);
828              free(obr);
829              evas_cache_image_drop(&im->cache_entry);
830           }
831 #endif
832      }
833    eina_spinlock_release(&(buf->priv.lock));
834    evas_common_cpu_end_opt();
835 }
836 
837 void
evas_software_xlib_outbuf_idle_flush(Outbuf * buf)838 evas_software_xlib_outbuf_idle_flush(Outbuf *buf)
839 {
840    eina_spinlock_take(&(buf->priv.lock));
841    if (buf->priv.onebuf)
842      {
843         RGBA_Image *im;
844         Outbuf_Region *obr;
845 
846         im = buf->priv.onebuf;
847         buf->priv.onebuf = NULL;
848         obr = im->extended_info;
849         if (obr->xob)
850           {
851              SHMPOOL_LOCK();
852              evas_software_xlib_x_output_buffer_unref(obr->xob, 0);
853              SHMPOOL_UNLOCK();
854           }
855         if (obr->mxob)
856           {
857              SHMPOOL_LOCK();
858              evas_software_xlib_x_output_buffer_unref(obr->mxob, 0);
859              SHMPOOL_UNLOCK();
860           }
861         free(obr);
862         evas_cache_image_drop(&im->cache_entry);
863      }
864    else
865      {
866         if (buf->priv.prev_pending_writes) XSync(buf->priv.x11.xlib.disp, False);
867         while (buf->priv.prev_pending_writes)
868           {
869              RGBA_Image *im;
870              Outbuf_Region *obr;
871 
872              im = buf->priv.prev_pending_writes->data;
873              buf->priv.prev_pending_writes =
874                eina_list_remove_list(buf->priv.prev_pending_writes,
875                                      buf->priv.prev_pending_writes);
876              obr = im->extended_info;
877              evas_cache_image_drop(&im->cache_entry);
878              if (obr->xob) _unfind_xob(obr->xob, 0);
879              if (obr->mxob) _unfind_xob(obr->mxob, 0);
880              free(obr);
881           }
882         _clear_xob(0);
883      }
884    eina_spinlock_release(&(buf->priv.lock));
885 }
886 
887 void
evas_software_xlib_outbuf_push_updated_region(Outbuf * buf,RGBA_Image * update,int x,int y,int w,int h)888 evas_software_xlib_outbuf_push_updated_region(Outbuf *buf, RGBA_Image *update, int x, int y, int w, int h)
889 {
890    Gfx_Func_Convert conv_func = NULL;
891    Outbuf_Region *obr;
892    DATA32 *src_data;
893    unsigned char *data;
894    int bpl = 0, yy;
895 
896    eina_spinlock_take(&(buf->priv.lock));
897    obr = update->extended_info;
898    if (buf->priv.pal)
899      {
900         if ((buf->rot == 0) || (buf->rot == 180))
901           conv_func = evas_common_convert_func_get(0, w, h,
902                                                    evas_software_xlib_x_output_buffer_depth
903                                                      (obr->xob), buf->priv.mask.r,
904                                                    buf->priv.mask.g, buf->priv.mask.b,
905                                                    buf->priv.pal->colors, buf->rot);
906         else if ((buf->rot == 90) || (buf->rot == 270))
907           conv_func = evas_common_convert_func_get(0, h, w,
908                                                    evas_software_xlib_x_output_buffer_depth
909                                                      (obr->xob), buf->priv.mask.r,
910                                                    buf->priv.mask.g, buf->priv.mask.b,
911                                                    buf->priv.pal->colors, buf->rot);
912      }
913    else
914      {
915         if ((buf->rot == 0) || (buf->rot == 180))
916           conv_func = evas_common_convert_func_get(0, w, h,
917                                                    evas_software_xlib_x_output_buffer_depth
918                                                      (obr->xob), buf->priv.mask.r,
919                                                    buf->priv.mask.g, buf->priv.mask.b,
920                                                    PAL_MODE_NONE, buf->rot);
921         else if ((buf->rot == 90) || (buf->rot == 270))
922           conv_func = evas_common_convert_func_get(0, h, w,
923                                                    evas_software_xlib_x_output_buffer_depth
924                                                      (obr->xob), buf->priv.mask.r,
925                                                    buf->priv.mask.g, buf->priv.mask.b,
926                                                    PAL_MODE_NONE, buf->rot);
927      }
928    if (!conv_func)
929      {
930         eina_spinlock_release(&(buf->priv.lock));
931         return;
932      }
933 
934    if (!obr->xob)
935      {
936         eina_spinlock_release(&(buf->priv.lock));
937         return;
938      }
939    data = evas_software_xlib_x_output_buffer_data(obr->xob, &bpl);
940    if (!data)
941      {
942         eina_spinlock_release(&(buf->priv.lock));
943         return;
944      }
945    src_data = update->image.data;
946    if (!src_data)
947      {
948         eina_spinlock_release(&(buf->priv.lock));
949         return;
950      }
951    if (buf->rot == 0)
952      {
953         obr->x = x;
954         obr->y = y;
955      }
956    else if (buf->rot == 90)
957      {
958         obr->x = y;
959         obr->y = buf->w - x - w;
960      }
961    else if (buf->rot == 180)
962      {
963         obr->x = buf->w - x - w;
964         obr->y = buf->h - y - h;
965      }
966    else if (buf->rot == 270)
967      {
968         obr->x = buf->h - y - h;
969         obr->y = x;
970      }
971    if ((buf->rot == 0) || (buf->rot == 180))
972      {
973         obr->w = w;
974         obr->h = h;
975      }
976    else if ((buf->rot == 90) || (buf->rot == 270))
977      {
978         obr->w = h;
979         obr->h = w;
980      }
981    if (buf->onebuf)
982      {
983         src_data += x + (y * update->cache_entry.w);
984         data += (bpl * obr->y) +
985           (obr->x * (evas_software_xlib_x_output_buffer_depth(obr->xob) / 8));
986      }
987    if (buf->priv.pal)
988      {
989         if (data != (unsigned char *)src_data)
990           conv_func(src_data, data, update->cache_entry.w - w,
991                     bpl - obr->w, obr->w, obr->h, x, y,
992                     buf->priv.pal->lookup);
993      }
994    else
995      {
996         int pixelb = evas_software_xlib_x_output_buffer_depth(obr->xob) / 8;
997         int run;
998         int dstjump;
999 
1000         if (pixelb == 3)
1001           {
1002              run = obr->w * pixelb;
1003              dstjump = bpl - run;
1004           }
1005         else if ((pixelb == 2) || (pixelb == 4))
1006           {
1007              run = obr->w;
1008              dstjump = (bpl / pixelb) - run;
1009           }
1010         else
1011           {
1012              run = obr->w;
1013              dstjump = bpl - run;
1014           }
1015         if (data != (unsigned char *)src_data)
1016           conv_func(src_data, data, update->cache_entry.w - w, dstjump,
1017                     obr->w, obr->h, x, y, NULL);
1018      }
1019 #if 1
1020 #else
1021    /* XX async push */
1022    if (!((buf->priv.onebuf) && eina_array_count(&buf->priv.onebuf_regions)))
1023      {
1024         if (buf->priv.debug)
1025           evas_software_xlib_outbuf_debug_show(buf, buf->priv.x11.xlib.win,
1026                                                obr->x, obr->y, obr->w, obr->h);
1027         if (obr->xob)
1028           {
1029              evas_software_xlib_x_output_buffer_paste(obr->xob, buf->priv.x11.xlib.win,
1030                                                       buf->priv.x11.xlib.gc,
1031                                                       obr->x, obr->y, 0);
1032           }
1033      }
1034 #endif
1035    if (obr->mxob)
1036      {
1037         if (buf->rot == 0)
1038           {
1039              for (yy = 0; yy < obr->h; yy++)
1040                evas_software_xlib_x_write_mask_line(buf, obr->mxob,
1041                                                     src_data +
1042                                                     (yy * obr->w), obr->w, yy);
1043           }
1044         else if (buf->rot == 90)
1045           {
1046              for (yy = 0; yy < obr->h; yy++)
1047                evas_software_xlib_x_write_mask_line_vert(buf, obr->mxob,
1048                                                          src_data + yy,
1049                                                          h,  // h
1050                                                          obr->h - yy - 1, // ym
1051                                                          w);  // w
1052           }
1053         else if (buf->rot == 180)
1054           {
1055              for (yy = 0; yy < obr->h; yy++)
1056                {
1057                   evas_software_xlib_x_write_mask_line_rev(buf, obr->mxob,
1058                                                            src_data +
1059                                                            (yy * obr->w),
1060                                                            obr->w, obr->h - yy - 1);
1061                }
1062           }
1063         else if (buf->rot == 270)
1064           {
1065              for (yy = 0; yy < obr->h; yy++)
1066                evas_software_xlib_x_write_mask_line_vert_rev(buf, obr->mxob,
1067                                                              src_data + yy,
1068                                                              h,  // h
1069                                                              yy, // ym
1070                                                              w);  // w
1071           }
1072 #if 1
1073 #else
1074         /* XX async push */
1075         if (!((buf->priv.onebuf) && eina_array_count(&buf->priv.onebuf_regions)))
1076           evas_software_xlib_x_output_buffer_paste(obr->mxob,
1077                                                    buf->priv.x11.xlib.mask,
1078                                                    buf->priv.x11.xlib.gcm,
1079                                                    obr->x, obr->y, 0);
1080 #endif
1081      }
1082 #if 1
1083 #else
1084    XFlush(buf->priv.x11.xlib.disp);
1085 #endif
1086    eina_spinlock_release(&(buf->priv.lock));
1087 }
1088 
1089 void
evas_software_xlib_outbuf_reconfigure(Outbuf * buf,int w,int h,int rot,Outbuf_Depth depth)1090 evas_software_xlib_outbuf_reconfigure(Outbuf *buf, int w, int h, int rot,
1091                                       Outbuf_Depth depth)
1092 {
1093    if ((w == buf->w) &&
1094        (h == buf->h) &&
1095        (rot == buf->rot) &&
1096        (depth == buf->depth)) return;
1097    SHMPOOL_LOCK();
1098    shmmemlimit -= ((buf->w * buf->h * (buf->depth / 8)) * 3) / 2;
1099    buf->w = w;
1100    buf->h = h;
1101    buf->rot = rot;
1102    shmmemlimit += ((buf->w * buf->h * (buf->depth / 8)) * 3) / 2;
1103    SHMPOOL_UNLOCK();
1104    evas_software_xlib_outbuf_idle_flush(buf);
1105 }
1106 
1107 int
evas_software_xlib_outbuf_get_width(Outbuf * buf)1108 evas_software_xlib_outbuf_get_width(Outbuf *buf)
1109 {
1110    return buf->w;
1111 }
1112 
1113 int
evas_software_xlib_outbuf_get_height(Outbuf * buf)1114 evas_software_xlib_outbuf_get_height(Outbuf *buf)
1115 {
1116    return buf->h;
1117 }
1118 
1119 Outbuf_Depth
evas_software_xlib_outbuf_get_depth(Outbuf * buf)1120 evas_software_xlib_outbuf_get_depth(Outbuf *buf)
1121 {
1122    return buf->depth;
1123 }
1124 
1125 int
evas_software_xlib_outbuf_get_rot(Outbuf * buf)1126 evas_software_xlib_outbuf_get_rot(Outbuf *buf)
1127 {
1128    return buf->rot;
1129 }
1130 
1131 void
evas_software_xlib_outbuf_drawable_set(Outbuf * buf,Drawable draw)1132 evas_software_xlib_outbuf_drawable_set(Outbuf *buf, Drawable draw)
1133 {
1134    XGCValues gcv;
1135 
1136    if (buf->priv.x11.xlib.win == draw) return;
1137    if (buf->priv.x11.xlib.gc)
1138      {
1139         XFreeGC(buf->priv.x11.xlib.disp, buf->priv.x11.xlib.gc);
1140         buf->priv.x11.xlib.gc = NULL;
1141      }
1142    buf->priv.x11.xlib.win = draw;
1143    buf->priv.x11.xlib.gc = XCreateGC(buf->priv.x11.xlib.disp, buf->priv.x11.xlib.win, 0, &gcv);
1144 }
1145 
1146 void
evas_software_xlib_outbuf_mask_set(Outbuf * buf,Pixmap mask)1147 evas_software_xlib_outbuf_mask_set(Outbuf *buf, Pixmap mask)
1148 {
1149    XGCValues gcv;
1150 
1151    if (buf->priv.x11.xlib.mask == mask) return;
1152    if (buf->priv.x11.xlib.gcm)
1153      {
1154         XFreeGC(buf->priv.x11.xlib.disp, buf->priv.x11.xlib.gcm);
1155         buf->priv.x11.xlib.gcm = NULL;
1156      }
1157    buf->priv.x11.xlib.mask = mask;
1158    if (buf->priv.x11.xlib.mask)
1159      buf->priv.x11.xlib.gcm = XCreateGC(buf->priv.x11.xlib.disp, buf->priv.x11.xlib.mask, 0, &gcv);
1160 }
1161 
1162 void
evas_software_xlib_outbuf_debug_set(Outbuf * buf,int debug)1163 evas_software_xlib_outbuf_debug_set(Outbuf *buf, int debug)
1164 {
1165    buf->priv.debug = debug;
1166 }
1167 
1168 void
evas_software_xlib_outbuf_debug_show(Outbuf * buf,Drawable draw,int x,int y,int w,int h)1169 evas_software_xlib_outbuf_debug_show(Outbuf *buf, Drawable draw, int x, int y, int w,
1170                                      int h)
1171 {
1172    int i;
1173    int screen_num = 0;
1174 
1175    {
1176       int wx, wy;
1177       unsigned int ww, wh, bd, dp;
1178       Window wdum, root;
1179       XWindowAttributes wattr;
1180 
1181       XGetGeometry(buf->priv.x11.xlib.disp, draw, &root, &wx, &wy, &ww, &wh, &bd, &dp);
1182       XGetGeometry(buf->priv.x11.xlib.disp, root, &wdum, &wx, &wy, &ww, &wh, &bd, &dp);
1183       XGetWindowAttributes(buf->priv.x11.xlib.disp, root, &wattr);
1184       screen_num = XScreenNumberOfScreen(wattr.screen);
1185    }
1186    for (i = 0; i < 20; i++)
1187      {
1188         XSetForeground(buf->priv.x11.xlib.disp, buf->priv.x11.xlib.gc,
1189                        BlackPixel(buf->priv.x11.xlib.disp, screen_num));
1190         XFillRectangle(buf->priv.x11.xlib.disp, draw, buf->priv.x11.xlib.gc, x, y, w, h);
1191         XSync(buf->priv.x11.xlib.disp, False);
1192         XSync(buf->priv.x11.xlib.disp, False);
1193         XSetForeground(buf->priv.x11.xlib.disp, buf->priv.x11.xlib.gc,
1194                        WhitePixel(buf->priv.x11.xlib.disp, screen_num));
1195         XFillRectangle(buf->priv.x11.xlib.disp, draw, buf->priv.x11.xlib.gc, x, y, w, h);
1196         XSync(buf->priv.x11.xlib.disp, False);
1197         XSync(buf->priv.x11.xlib.disp, False);
1198      }
1199 }
1200 
1201 Eina_Bool
evas_software_xlib_outbuf_alpha_get(Outbuf * buf)1202 evas_software_xlib_outbuf_alpha_get(Outbuf *buf)
1203 {
1204    return buf->priv.x11.xlib.mask;
1205 }
1206 
1207