#include "evas_common_private.h" #include "evas_private.h" #ifdef EVAS_CSERVE2 # include "evas_cs2_private.h" #endif #include "evas_engine.h" #define RED_MASK 0xff0000 #define GREEN_MASK 0x00ff00 #define BLUE_MASK 0x0000ff Outbuf * _evas_outbuf_setup(int w, int h, int rot, Outbuf_Depth depth, Eina_Bool alpha, struct wl_shm *shm, struct wl_surface *surface) { Outbuf *ob = NULL; char *num; LOGFN(__FILE__, __LINE__, __FUNCTION__); /* try to allocate space for new Outbuf */ if (!(ob = calloc(1, sizeof(Outbuf)))) return NULL; /* set outbuf properties */ ob->w = w; ob->h = h; ob->rotation = rot; ob->depth = depth; ob->priv.destination_alpha = alpha; /* default to double buffer */ ob->num_buff = 2; /* check for any 'number of buffers' override in the environment */ if ((num = getenv("EVAS_WAYLAND_SHM_BUFFERS"))) { int n = 0; n = atoi(num); if (n <= 0) n = 1; if (n > MAX_BUFFERS) n = MAX_BUFFERS; ob->num_buff = n; } /* try to create the outbuf surface */ if (!(ob->surface = _evas_shm_surface_create(shm, surface, w, h, ob->num_buff, alpha))) goto surf_err; eina_array_step_set(&ob->priv.onebuf_regions, sizeof(Eina_Array), 8); return ob; surf_err: free(ob); return NULL; } void _evas_outbuf_free(Outbuf *ob) { LOGFN(__FILE__, __LINE__, __FUNCTION__); while (ob->priv.pending_writes) { RGBA_Image *img; Eina_Rectangle *rect; img = ob->priv.pending_writes->data; ob->priv.pending_writes = eina_list_remove_list(ob->priv.pending_writes, ob->priv.pending_writes); rect = img->extended_info; #ifdef EVAS_CSERVE2 if (evas_cserve2_use_get()) evas_cache2_image_close(&img->cache_entry); else #endif evas_cache_image_drop(&img->cache_entry); eina_rectangle_free(rect); } _evas_outbuf_flush(ob, NULL, MODE_FULL); _evas_outbuf_idle_flush(ob); if (ob->surface) _evas_shm_surface_destroy(ob->surface); eina_array_flush(&ob->priv.onebuf_regions); free(ob); } void _evas_outbuf_idle_flush(Outbuf *ob) { RGBA_Image *img; Eina_Rectangle *rect; if (ob->priv.onebuf) { img = ob->priv.onebuf; ob->priv.onebuf = NULL; rect = img->extended_info; eina_rectangle_free(rect); #ifdef EVAS_CSERVE2 if (evas_cserve2_use_get()) evas_cache2_image_close(&img->cache_entry); else #endif evas_cache_image_drop(&img->cache_entry); } else { while (ob->priv.prev_pending_writes) { img = ob->priv.prev_pending_writes->data; ob->priv.prev_pending_writes = eina_list_remove_list(ob->priv.prev_pending_writes, ob->priv.prev_pending_writes); rect = img->extended_info; #ifdef EVAS_CSERVE2 if (evas_cserve2_use_get()) evas_cache2_image_close(&img->cache_entry); else #endif evas_cache_image_drop(&img->cache_entry); eina_rectangle_free(rect); } } } void _evas_outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects EINA_UNUSED, Evas_Render_Mode render_mode) { Eina_Rectangle *result; RGBA_Image *img; unsigned int n = 0, i = 0; LOGFN(__FILE__, __LINE__, __FUNCTION__); if (render_mode == EVAS_RENDER_MODE_ASYNC_INIT) return; /* check for pending writes */ if (!ob->priv.pending_writes) { Eina_Rectangle *rect; Eina_Array_Iterator it; /* get number of buffer regions */ n = eina_array_count_get(&ob->priv.onebuf_regions); if (n == 0) return; /* allocate rectangles */ if (!(result = alloca(n * sizeof(Eina_Rectangle)))) return; /* loop the buffer regions and assign to result */ EINA_ARRAY_ITER_NEXT(&ob->priv.onebuf_regions, i, rect, it) result[i] = *rect; _evas_shm_surface_post(ob->surface, result, n); /* clean array */ eina_array_clean(&ob->priv.onebuf_regions); img = ob->priv.onebuf; ob->priv.onebuf = NULL; if (img) { #ifdef EVAS_CSERVE2 if (evas_cserve2_use_get()) evas_cache2_image_close(&img->cache_entry); else #endif evas_cache_image_drop(&img->cache_entry); } } else { /* get number of pending writes */ n = eina_list_count(ob->priv.pending_writes); if (n == 0) return; /* allocate rectangles */ if (!(result = alloca(n * sizeof(Eina_Rectangle)))) return; /* loop the pending writes */ EINA_LIST_FREE(ob->priv.pending_writes, img) { Eina_Rectangle *rect; int x = 0, y = 0, w = 0, h = 0; if (!(rect = img->extended_info)) continue; x = rect->x; y = rect->y; w = rect->w; h = rect->h; /* based on rotation, set rectangle position */ if (ob->rotation == 0) { result[i].x = x; result[i].y = y; } else if (ob->rotation == 90) { result[i].x = y; result[i].y = (ob->w - x - w); } else if (ob->rotation == 180) { result[i].x = (ob->w - x - w); result[i].y = (ob->h - y - h); } else if (ob->rotation == 270) { result[i].x = (ob->h - y - h); result[i].y = x; } /* based on rotation, set rectangle size */ if ((ob->rotation == 0) || (ob->rotation == 180)) { result[i].w = w; result[i].h = h; } else if ((ob->rotation == 90) || (ob->rotation == 270)) { result[i].w = h; result[i].h = w; } eina_rectangle_free(rect); #ifdef EVAS_CSERVE2 if (evas_cserve2_use_get()) evas_cache2_image_close(&img->cache_entry); else #endif evas_cache_image_drop(&img->cache_entry); i++; } _evas_shm_surface_post(ob->surface, result, n); } } Render_Engine_Swap_Mode _evas_outbuf_swap_mode_get(Outbuf *ob) { int count = 0, ret = 0; LOGFN(__FILE__, __LINE__, __FUNCTION__); /* This was broken, for now we just do full redraws */ return MODE_FULL; if (count == ob->surface->num_buff) ret = MODE_FULL; else if (count == 0) ret = MODE_COPY; else if (count == 1) ret = MODE_DOUBLE; else if (count == 2) ret = MODE_TRIPLE; else if (count == 3) ret = MODE_QUADRUPLE; else ret = MODE_FULL; /* DBG("SWAPMODE: %d (0=FULL, 1=COPY, 2=DOUBLE, 3=TRIPLE, 4=QUAD", ret); */ /* DBG("\tBusy: %d", count); */ return ret; } int _evas_outbuf_rotation_get(Outbuf *ob) { LOGFN(__FILE__, __LINE__, __FUNCTION__); return ob->rotation; } void _evas_outbuf_reconfigure(Outbuf *ob, int x, int y, int w, int h, int rot, Outbuf_Depth depth, Eina_Bool alpha, Eina_Bool resize) { LOGFN(__FILE__, __LINE__, __FUNCTION__); if (depth == OUTBUF_DEPTH_INHERIT) depth = ob->depth; if ((ob->w == w) && (ob->h == h) && (ob->rotation == rot) && (ob->depth == depth) && (ob->priv.destination_alpha == alpha)) return; ob->w = w; ob->h = h; ob->rotation = rot; ob->depth = depth; ob->priv.destination_alpha = alpha; if (resize) ob->surface->flags = SURFACE_HINT_RESIZING; else ob->surface->flags = 0; _evas_shm_surface_reconfigure(ob->surface, x, y, w, h, ob->num_buff, ob->surface->flags); _evas_outbuf_idle_flush(ob); } void * _evas_outbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int *cx, int *cy, int *cw, int *ch) { RGBA_Image *img; Eina_Rectangle *rect; LOGFN(__FILE__, __LINE__, __FUNCTION__); RECTS_CLIP_TO_RECT(x, y, w, h, 0, 0, ob->w, ob->h); if ((w <= 0) || (h <= 0)) return NULL; if (ob->rotation == 0) { if (!(img = ob->priv.onebuf)) { int bw = 0, bh = 0; void *data; if (!(data = _evas_shm_surface_data_get(ob->surface, &bw, &bh))) { /* ERR("Could not get surface data"); */ return NULL; } #ifdef EVAS_CSERVE2 if (evas_cserve2_use_get()) { img = (RGBA_Image *) evas_cache2_image_data(evas_common_image_cache2_get(), bw, bh, data, ob->priv.destination_alpha, EVAS_COLORSPACE_ARGB8888); } else #endif { img = (RGBA_Image *) evas_cache_image_data(evas_common_image_cache_get(), bw, bh, data, ob->priv.destination_alpha, EVAS_COLORSPACE_ARGB8888); } ob->priv.onebuf = img; if (!img) return NULL; } if (!(rect = eina_rectangle_new(x, y, w, h))) return NULL; if (!eina_array_push(&ob->priv.onebuf_regions, rect)) { #ifdef EVAS_CSERVE2 if (evas_cserve2_use_get()) evas_cache2_image_close(&img->cache_entry); else #endif evas_cache_image_drop(&img->cache_entry); eina_rectangle_free(rect); return NULL; } if (cx) *cx = x; if (cy) *cy = y; if (cw) *cw = w; if (ch) *ch = h; img->extended_info = rect; return img; } else { if (!(rect = eina_rectangle_new(x, y, w, h))) return NULL; #ifdef EVAS_CSERVE2 if (evas_cserve2_use_get()) img = (RGBA_Image *)evas_cache2_image_empty(evas_common_image_cache2_get()); else #endif img = (RGBA_Image *)evas_cache_image_empty(evas_common_image_cache_get()); if (!img) { eina_rectangle_free(rect); return NULL; } img->cache_entry.w = w; img->cache_entry.h = h; img->cache_entry.flags.alpha |= ob->priv.destination_alpha ? 1 : 0; #ifdef EVAS_CSERVE2 if (evas_cserve2_use_get()) evas_cache2_image_surface_alloc(&img->cache_entry, w, h); else #endif evas_cache_image_surface_alloc(&img->cache_entry, w, h); img->extended_info = rect; ob->priv.pending_writes = eina_list_append(ob->priv.pending_writes, img); if (cx) *cx = 0; if (cy) *cy = 0; if (cw) *cw = w; if (ch) *ch = h; return img; } return NULL; } void _evas_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int w, int h) { Gfx_Func_Convert func = NULL; Eina_Rectangle rect = {0, 0, 0, 0}, pr; DATA32 *src; DATA8 *dst; int depth = 32, bpp = 0, bpl = 0, wid = 0; int ww = 0, hh = 0; int rx = 0, ry = 0; LOGFN(__FILE__, __LINE__, __FUNCTION__); /* check for valid output buffer */ if (!ob) return; /* check for pending writes */ if (!ob->priv.pending_writes) return; if ((ob->rotation == 0) || (ob->rotation == 180)) { func = evas_common_convert_func_get(0, w, h, depth, RED_MASK, GREEN_MASK, BLUE_MASK, PAL_MODE_NONE, ob->rotation); } else if ((ob->rotation == 90) || (ob->rotation == 270)) { func = evas_common_convert_func_get(0, h, w, depth, RED_MASK, GREEN_MASK, BLUE_MASK, PAL_MODE_NONE, ob->rotation); } /* make sure we have a valid convert function */ if (!func) return; /* based on rotation, set rectangle position */ if (ob->rotation == 0) { rect.x = x; rect.y = y; } else if (ob->rotation == 90) { rect.x = y; rect.y = (ob->w - x - w); } else if (ob->rotation == 180) { rect.x = (ob->w - x - w); rect.y = (ob->h - y - h); } else if (ob->rotation == 270) { rect.x = (ob->h - y - h); rect.y = x; } /* based on rotation, set rectangle size */ if ((ob->rotation == 0) || (ob->rotation == 180)) { rect.w = w; rect.h = h; } else if ((ob->rotation == 90) || (ob->rotation == 270)) { rect.w = h; rect.h = w; } /* check for valid update image data */ if (!(src = update->image.data)) return; bpp = depth / 8; if (bpp <= 0) return; /* check for valid desination data */ if (!(dst = _evas_shm_surface_data_get(ob->surface, &ww, &hh))) { /* ERR("Could not get surface data"); */ return; } bpl = (ww * sizeof(int)); if (ob->rotation == 0) { RECTS_CLIP_TO_RECT(rect.x, rect.y, rect.w, rect.h, 0, 0, ww, hh); dst += (bpl * rect.y) + (rect.x * bpp); w -= rx; } else if (ob->rotation == 180) { pr = rect; RECTS_CLIP_TO_RECT(rect.x, rect.y, rect.w, rect.h, 0, 0, ww, hh); rx = pr.w - rect.w; ry = pr.h - rect.h; src += (update->cache_entry.w * ry) + rx; w -= rx; } else if (ob->rotation == 90) { pr = rect; RECTS_CLIP_TO_RECT(rect.x, rect.y, rect.w, rect.h, 0, 0, ww, hh); rx = pr.w - rect.w; ry = pr.h - rect.h; src += ry; w -= ry; } else if (ob->rotation == 270) { pr = rect; RECTS_CLIP_TO_RECT(rect.x, rect.y, rect.w, rect.h, 0, 0, ww, hh); rx = pr.w - rect.w; ry = pr.h - rect.h; src += (update->cache_entry.w * rx); w -= ry; } if ((rect.w <= 0) || (rect.h <= 0)) return; wid = bpl / bpp; dst += (bpl * rect.y) + (rect.x * bpp); func(src, dst, (update->cache_entry.w - w), (wid - rect.w), rect.w, rect.h, x + rx, y + ry, NULL); } void _evas_outbuf_update_region_free(Outbuf *ob EINA_UNUSED, RGBA_Image *update EINA_UNUSED) { LOGFN(__FILE__, __LINE__, __FUNCTION__); }