#include "evas_engine.h" #ifdef EVAS_CSERVE2 # include "evas_cs2_private.h" #endif /* FIXME: We NEED to get the color map from the VT and use that for the mask */ #define RED_MASK 0xff0000 #define GREEN_MASK 0x00ff00 #define BLUE_MASK 0x0000ff static Eina_Bool _evas_outbuf_buffer_new(Outbuf *ob, Buffer *buff) { buff->w = ob->w; buff->h = ob->h; /* create a dumb framebuffer */ if (!evas_drm_framebuffer_create(ob->priv.fd, buff, ob->depth)) return EINA_FALSE; return EINA_TRUE; } static void _evas_outbuf_buffer_put(Outbuf *ob, Buffer *buffer, Eina_Rectangle *rects, unsigned int count) { /* validate input params */ if ((!ob) || (!buffer)) return; #ifdef DRM_MODE_FEATURE_DIRTYFB drmModeClip *clip; unsigned int i = 0; int ret; clip = alloca(count * sizeof(drmModeClip)); for (i = 0; i < count; i++) { clip[i].x1 = rects[i].x; clip[i].y1 = rects[i].y; clip[i].x2 = rects[i].w; clip[i].y2 = rects[i].h; } /* DBG("Marking FB Dirty: %d", buffer->fb); */ ret = drmModeDirtyFB(ob->priv.fd, buffer->fb, clip, count); if (ret) { if (ret == -EINVAL) ERR("Could not set FB Dirty: %m"); } #endif } static void _evas_outbuf_buffer_swap(Outbuf *ob, Eina_Rectangle *rects, unsigned int count) { Buffer *buff; buff = &(ob->priv.buffer[ob->priv.curr]); /* if this buffer is not valid, we need to set it */ if (!buff->valid) evas_drm_outbuf_framebuffer_set(ob, buff); /* mark the fb as dirty */ _evas_outbuf_buffer_put(ob, buff, rects, count); /* send this buffer to the crtc */ evas_drm_framebuffer_send(ob, buff); } Outbuf * evas_outbuf_setup(Evas_Engine_Info_Drm *info, int w, int h) { Outbuf *ob; char *num; int i = 0; /* try to allocate space for outbuf */ if (!(ob = calloc(1, sizeof(Outbuf)))) return NULL; /* set properties of outbuf */ ob->w = w; ob->h = h; ob->depth = info->info.depth; ob->rotation = info->info.rotation; ob->destination_alpha = info->info.destination_alpha; ob->vsync = info->info.vsync; /* set drm card fd */ ob->priv.fd = info->info.fd; /* try to setup the drm card for this outbuf */ if (!evas_drm_outbuf_setup(ob)) { ERR("Could not setup output"); free(ob); return NULL; } ob->priv.num = NUM_BUFFERS; /* check for buffer override */ if ((num = getenv("EVAS_DRM_BUFFERS"))) { ob->priv.num = atoi(num); /* cap maximum # of buffers */ if (ob->priv.num <= 0) ob->priv.num = 1; else if (ob->priv.num > 3) ob->priv.num = 3; } /* check for vsync override */ if ((num = getenv("EVAS_DRM_VSYNC"))) ob->vsync = atoi(num); /* try to create buffers */ for (; i < ob->priv.num; i++) { if (!_evas_outbuf_buffer_new(ob, &(ob->priv.buffer[i]))) break; } /* set the front buffer to be the one on the crtc */ evas_drm_outbuf_framebuffer_set(ob, &(ob->priv.buffer[0])); /* set back buffer as first one to draw into */ /* ob->priv.curr = (ob->priv.num - 1); */ return ob; } void evas_outbuf_free(Outbuf *ob) { int i = 0; /* destroy the old buffers */ for (; i < ob->priv.num; i++) evas_drm_framebuffer_destroy(ob->priv.fd, &(ob->priv.buffer[i])); /* free allocate space for outbuf */ free(ob); } void evas_outbuf_reconfigure(Evas_Engine_Info_Drm *info, Outbuf *ob, int w, int h) { int i = 0; /* check for changes */ if ((ob->w == w) && (ob->h == h) && (ob->destination_alpha == info->info.destination_alpha) && (ob->rotation == info->info.rotation) && (ob->depth == info->info.depth)) return; /* set new outbuf properties */ ob->rotation =info->info. rotation; ob->depth = info->info.depth; ob->destination_alpha = info->info.destination_alpha; /* handle rotation */ if ((ob->rotation == 0) || (ob->rotation == 180)) { ob->w = w; ob->h = h; } else { ob->w = h; ob->h = w; } /* destroy the old buffers */ for (; i < ob->priv.num; i++) evas_drm_framebuffer_destroy(ob->priv.fd, &(ob->priv.buffer[i])); for (i = 0; i < ob->priv.num; i++) { if (!_evas_outbuf_buffer_new(ob, &(ob->priv.buffer[i]))) { CRI("Failed to create buffer"); break; } } } int evas_outbuf_buffer_state_get(Outbuf *ob) { int i = 0, n = 0, count = 0; /* check for valid output buffer */ if (!ob) return MODE_FULL; for (; i < ob->priv.num; i++) { n = (ob->priv.num + ob->priv.curr - i) % ob->priv.num; if (ob->priv.buffer[n].valid) count++; else break; } if (count == ob->priv.num) { if (count == 1) return MODE_COPY; else if (count == 2) return MODE_DOUBLE; else if (count == 3) return MODE_TRIPLE; } return MODE_FULL; } RGBA_Image * 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 = NULL; if ((w <= 0) || (h <= 0)) return NULL; /* DBG("Outbuf Region New: %d %d %d %d", x, y, w, h); */ RECTS_CLIP_TO_RECT(x, y, w, h, 0, 0, ob->w, ob->h); if ((ob->rotation == 0) && (ob->depth == 32)) { Eina_Rectangle *rect; 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.flags.alpha |= ob->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; if (cx) *cx = 0; if (cy) *cy = 0; if (cw) *cw = w; if (ch) *ch = h; /* add this cached image data to pending writes */ ob->priv.pending_writes = eina_list_append(ob->priv.pending_writes, img); } return img; } 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; Buffer *buff; int bpp = 0, bpl = 0; int rx = 0, ry = 0; /* check for valid output buffer */ if (!ob) return; /* check for pending writes */ if (!ob->priv.pending_writes) return; /* check for valid source data */ if (!(src = update->image.data)) return; /* check for valid desination data */ buff = &(ob->priv.buffer[ob->priv.curr]); if (!(dst = buff->data)) return; if ((ob->rotation == 0) || (ob->rotation == 180)) { func = evas_common_convert_func_get(0, w, h, ob->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, ob->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; } bpp = (ob->depth / 8); if (bpp <= 0) return; bpl = buff->stride; if (ob->rotation == 0) { RECTS_CLIP_TO_RECT(rect.x, rect.y, rect.w, rect.h, 0, 0, buff->w, buff->h); 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, buff->w, buff->h); 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, buff->w, buff->h); 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, buff->w, buff->h); 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; func(src, dst, (update->cache_entry.w - w), ((bpl / bpp) - rect.w), rect.w, rect.h, x + rx, y + ry, NULL); } void evas_outbuf_update_region_free(Outbuf *ob EINA_UNUSED, RGBA_Image *update) { evas_cache_image_drop(&update->cache_entry); } void evas_outbuf_flush(Outbuf *ob) { Eina_Rectangle *rects; RGBA_Image *img; unsigned int n = 0, i = 0; /* get number of pending writes */ n = eina_list_count(ob->priv.pending_writes); if (n == 0) return; /* allocate rectangles */ if (!(rects = 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) { rects[i].x = x; rects[i].y = y; } else if (ob->rotation == 90) { rects[i].x = y; rects[i].y = (ob->w - x - w); } else if (ob->rotation == 180) { rects[i].x = (ob->w - x - w); rects[i].y = (ob->h - y - h); } else if (ob->rotation == 270) { rects[i].x = (ob->h - y - h); rects[i].y = x; } /* based on rotation, set rectangle size */ if ((ob->rotation == 0) || (ob->rotation == 180)) { rects[i].w = w; rects[i].h = h; } else if ((ob->rotation == 90) || (ob->rotation == 270)) { rects[i].w = h; rects[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++; } /* force a buffer swap */ _evas_outbuf_buffer_swap(ob, rects, n); }