devilhorns pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=b42af265bee3f8ffd8c113a585c3d6a8f0460ca0

commit b42af265bee3f8ffd8c113a585c3d6a8f0460ca0
Author: Chris Michael <[email protected]>
Date:   Tue Feb 11 07:09:39 2014 +0000

    evas-drm: Add Evas Drm Engine (software only currently)
    
    @feature: Add working Evas_Drm Engine (software only currently)
    
    Signed-off-by: Chris Michael <[email protected]>
---
 src/modules/evas/engines/drm/Evas_Engine_Drm.h |  11 +
 src/modules/evas/engines/drm/evas_drm.c        | 630 +++++++++++++++++++++++++
 src/modules/evas/engines/drm/evas_engine.c     | 312 +++++++++++-
 src/modules/evas/engines/drm/evas_engine.h     |  74 ++-
 src/modules/evas/engines/drm/evas_outbuf.c     | 553 +++++++++++++++++++++-
 5 files changed, 1550 insertions(+), 30 deletions(-)

diff --git a/src/modules/evas/engines/drm/Evas_Engine_Drm.h 
b/src/modules/evas/engines/drm/Evas_Engine_Drm.h
index d149e60..6b1a663 100644
--- a/src/modules/evas/engines/drm/Evas_Engine_Drm.h
+++ b/src/modules/evas/engines/drm/Evas_Engine_Drm.h
@@ -11,8 +11,19 @@ struct _Evas_Engine_Info_Drm
 
    struct 
      {
+        Evas *evas;
+
         unsigned int rotation, depth;
         Eina_Bool destination_alpha : 1;
+
+        int fd;
+        Eina_Bool own_fd : 1;
+
+        int tty;
+        Eina_Bool own_tty : 1;
+
+        int output;
+        int plane;
      } info;
 
    /* non-blocking or blocking mode */
diff --git a/src/modules/evas/engines/drm/evas_drm.c 
b/src/modules/evas/engines/drm/evas_drm.c
new file mode 100644
index 0000000..77ca0f6
--- /dev/null
+++ b/src/modules/evas/engines/drm/evas_drm.c
@@ -0,0 +1,630 @@
+#include "evas_engine.h"
+#include <linux/vt.h>
+#include <linux/kd.h>
+#include <sys/mman.h>
+
+/* NB: REALLY hate to store this here, but sigaction signal handlers cannot 
+ * pass any 'user data' to the signal handlers :( */
+static Evas_Engine_Info_Drm *siginfo;
+
+static int 
+_evas_drm_card_open(int card)
+{
+   char dev[32];
+   int fd = -1;
+   uint64_t dumb;
+
+   sprintf(dev, DRM_DEV_NAME, DRM_DIR_NAME, card);
+
+   if ((fd = open(dev, (O_RDWR | O_CLOEXEC))) < 0)
+     {
+        CRI("Could not open drm device %s: %m", dev);
+        return -1;
+     }
+
+   drmVersionPtr ver;
+   if ((ver = drmGetVersion(fd)))
+     {
+        DBG("Drm Driver Name: %s", ver->name);
+        drmFreeVersion(ver);
+     }
+
+   /* check for dumb buffer support
+    * 
+    * NB: This checks that we can at least support software rendering */
+   if ((drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &dumb) < 0) || (!dumb))
+     {
+        CRI("Drm Device %s does not support software rendering", dev);
+
+        /* close the card */
+        close(fd);
+
+        /* return failure */
+        return -1;
+     }
+
+   DBG("Opened Drm Card %s: %d", dev, fd);
+
+   /* return opened card */
+   return fd;
+}
+
+static int 
+_evas_drm_tty_open(Evas_Engine_Info_Drm *info)
+{
+   int tty = STDIN_FILENO;
+
+   /* check if the current stdin is a valid tty */
+   if (!isatty(tty))
+     {
+        /* if not, try to open the curren tty */
+        if ((tty = open("/dev/tty", (O_RDWR | O_CLOEXEC))) < 0)
+          {
+             int tty0 = -1, num = -1;
+             char name[16];
+
+             /* if that fails, try tty0 */
+             if ((tty0 = open("/dev/tty0", (O_WRONLY | O_CLOEXEC))) < 0)
+               {
+                  CRI("Could not open tty0: %m");
+                  return -1;
+               }
+
+             /* try to find a non-opened tty */
+             if ((ioctl(tty0, VT_OPENQRY, &num) < 0) || (num < 0))
+               {
+                  CRI("Could not find a non-opened tty");
+                  close(tty0);
+                  return -1;
+               }
+
+             snprintf(name, sizeof(name), "/dev/tty%d", num);
+
+             /* try to open this tty */
+             if ((tty = open(name, (O_RDWR | O_CLOEXEC))) < 0)
+               {
+                  CRI("Could not open tty: %s", name);
+                  close(tty0);
+                  return -1;
+               }
+
+             /* set flag that evas should close this tty */
+             info->info.own_tty = EINA_TRUE;
+
+             /* close /dev/tty0 */
+             close(tty0);
+          }
+     }
+   else
+     {
+        /* set flag that evas should close this tty */
+        info->info.own_tty = EINA_TRUE;
+     }
+
+   DBG("Opened Tty %d", tty);
+
+   return tty;
+}
+
+static int 
+_evas_drm_crtc_find(int fd, drmModeRes *res, drmModeConnector *conn)
+{
+   int crtc = -1;
+   drmModeEncoder *enc = NULL;
+
+   /* if this connector already has an encoder, get it */
+   if (conn->encoder_id) enc = drmModeGetEncoder(fd, conn->encoder_id);
+
+   /* if this encoder already has a crtc, lets try to use that */
+   if ((enc) && (enc->crtc_id)) crtc = enc->crtc_id;
+
+   if (crtc < 0)
+     {
+        int i = 0, c = 0;
+
+        /* if this connector has no encoder, we need to find one */
+        for (; i < conn->count_encoders; ++i)
+          {
+             /* try to get this encoder */
+             if (!(enc = drmModeGetEncoder(fd, conn->encoders[i])))
+               continue;
+
+             /* loop global crtcs */
+             for (; c < res->count_crtcs; ++c)
+               {
+                  /* does this crtc work with this encoder ? */
+                  if (!(enc->possible_crtcs & (1 << c))) continue;
+
+                  /* FIXME: We could be more proactive here and check that 
+                   * nobody else is using this crtc */
+
+                  /* if it works, let's use it */
+                  crtc = res->crtcs[c];
+                  break;
+               }
+
+             if (crtc >= 0) break;
+          }
+     }
+
+   /* free the encoder */
+   if (enc) drmModeFreeEncoder(enc);
+
+   return crtc;
+}
+
+static void 
+_evas_drm_tty_sigusr1(int x EINA_UNUSED, siginfo_t *info, void *data 
EINA_UNUSED)
+{
+   Evas_Engine_Info_Drm *einfo;
+
+   DBG("Caught SIGUSR1");
+
+   if (!(einfo = siginfo)) return;
+
+   /* TODO: set canvas to not render */
+
+   DBG("\tDrop Master & Release VT");
+
+   /* drop drm master */
+   if (einfo->info.own_fd)
+     {
+        if (drmDropMaster(einfo->info.fd) != 0)
+          WRN("Could not drop drm master: %m");
+     }
+
+   /* release vt */
+   if (einfo->info.own_tty)
+     {
+        if (ioctl(einfo->info.tty, VT_RELDISP, 1) < 0)
+          WRN("Could not release vt: %m");
+     }
+}
+
+static void 
+_evas_drm_tty_sigusr2(int x EINA_UNUSED, siginfo_t *info, void *data 
EINA_UNUSED)
+{
+   Evas_Engine_Info_Drm *einfo;
+
+   DBG("Caught SIGUSR2");
+
+   if (!(einfo = siginfo)) return;
+
+   /* TODO: set canvas to render again */
+
+   DBG("\tAcquire VT & Set Master");
+
+   /* acquire vt */
+   if (einfo->info.own_tty)
+     {
+        if (ioctl(einfo->info.tty, VT_RELDISP, VT_ACKACQ) < 0)
+          WRN("Could not acquire vt: %m");
+     }
+
+   /* set master */
+   if (einfo->info.own_fd)
+     {
+        if (drmSetMaster(einfo->info.fd) != 0)
+          WRN("Could not set drm master: %m");
+     }
+}
+
+static Eina_Bool 
+_evas_drm_tty_setup(Evas_Engine_Info_Drm *info)
+{
+   struct vt_mode vtmode = { 0 };
+   struct sigaction sig;
+
+   /* check for valid tty */
+   if (info->info.tty < 0) return EINA_FALSE;
+
+#if 0
+   /* set vt to graphics mode */
+   if (ioctl(info->info.tty, KDSETMODE, KD_GRAPHICS) < 0)
+     {
+        CRI("Could not set tty to graphics mode: %m");
+        return EINA_FALSE;
+     }
+#endif
+
+   /* setup tty rel/acq signals */
+   vtmode.mode = VT_PROCESS;
+   vtmode.waitv = 0;
+   vtmode.relsig = SIGUSR1;
+   vtmode.acqsig = SIGUSR2;
+   if (ioctl(info->info.tty, VT_SETMODE, &vtmode) < 0)
+     {
+        CRI("Could not set tty mode: %m");
+        return EINA_FALSE;
+     }
+
+   /* store info struct 
+    * 
+    * NB: REALLY hate to store this here, but sigaction signal handlers cannot 
+    * pass any 'user data' to the signal handlers :(
+    */
+   siginfo = info;
+
+   /* setup signal handlers for above signals */
+   sig.sa_sigaction = _evas_drm_tty_sigusr1;
+   sig.sa_flags = (SA_NODEFER | SA_SIGINFO | SA_RESTART);
+   sigemptyset(&sig.sa_mask);
+   sigaction(SIGUSR1, &sig, NULL);
+
+   sig.sa_sigaction = _evas_drm_tty_sigusr2;
+   sig.sa_flags = (SA_NODEFER | SA_SIGINFO | SA_RESTART);
+   sigemptyset(&sig.sa_mask);
+   sigaction(SIGUSR2, &sig, NULL);
+
+   return EINA_TRUE;
+}
+
+static void 
+_evas_drm_outbuf_page_flip(int fd EINA_UNUSED, unsigned int seq EINA_UNUSED, 
unsigned int tv_sec EINA_UNUSED, unsigned int tv_usec EINA_UNUSED, void *data)
+{
+   Outbuf *ob;
+
+   /* get the output buffer from data */
+   if (!(ob = data)) return;
+
+   /* DBG("Page Flip Event"); */
+
+   ob->priv.pending_flip = EINA_FALSE;
+   ob->priv.curr = (ob->priv.curr + 1) % ob->priv.num;
+}
+
+static void 
+_evas_drm_outbuf_vblank(int fd EINA_UNUSED, unsigned int frame EINA_UNUSED, 
unsigned int sec EINA_UNUSED, unsigned int usec EINA_UNUSED, void *data)
+{
+   Outbuf *ob;
+
+   /* get the output buffer from data */
+   if (!(ob = data)) return;
+
+   DBG("VBlank Event");
+}
+
+Eina_Bool 
+evas_drm_init(Evas_Engine_Info_Drm *info, int card)
+{
+   /* check for valid engine info */
+   if (!info) return EINA_FALSE;
+
+   setvbuf(stdout, NULL, _IONBF, 0);
+
+   /* check if we already opened the card */
+   if (info->info.fd < 0)
+     {
+        /* try to open the drm card */
+        if ((info->info.fd = _evas_drm_card_open(card)) < 0) 
+          return EINA_FALSE;
+
+        /* set flag to indicate that evas opened the card and we should 
+         * be the one to close it */
+        info->info.own_fd = EINA_TRUE;
+     }
+
+   /* check if we already opened the tty */
+   if (info->info.tty < 0)
+     {
+        /* try to open the current tty */
+        if ((info->info.tty = _evas_drm_tty_open(info)) < 0) 
+          {
+             /* check if we already opened the card. if so, close it */
+             if ((info->info.fd >= 0) && (info->info.own_fd))
+               {
+                  close(info->info.fd);
+                  info->info.fd = -1;
+               }
+
+             return EINA_FALSE;
+          }
+     }
+
+   /* with the tty opened, we need to set it up */
+   if (!_evas_drm_tty_setup(info))
+     {
+        /* setup of tty failed, close it */
+        if ((info->info.tty >= 0) && (info->info.own_tty))
+          close(info->info.tty);
+
+        /* FIXME: Close card also ?? */
+
+        return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+Eina_Bool 
+evas_drm_shutdown(Evas_Engine_Info_Drm *info)
+{
+   /* check for valid engine info */
+   if (!info) return EINA_TRUE;
+
+   /* check if we already opened the tty. if so, close it */
+   if ((info->info.tty >= 0) && (info->info.own_tty))
+     {
+        close(info->info.tty);
+        info->info.tty = -1;
+     }
+
+   /* check if we already opened the card. if so, close it */
+   if ((info->info.fd >= 0) && (info->info.own_fd))
+     {
+        close(info->info.fd);
+        info->info.fd = -1;
+     }
+
+   return EINA_TRUE;
+}
+
+Eina_Bool 
+evas_drm_outbuf_setup(Outbuf *ob)
+{
+   drmModeRes *res;
+   drmModeConnector *conn;
+   int i = 0;
+
+   /* check for valid Output buffer */
+   if ((!ob) || (ob->priv.fd < 0)) return EINA_FALSE;
+
+   /* setup drmHandleEvent context */
+   memset(&ob->priv.ctx, 0, sizeof(ob->priv.ctx));
+   ob->priv.ctx.version = DRM_EVENT_CONTEXT_VERSION;
+   ob->priv.ctx.page_flip_handler = _evas_drm_outbuf_page_flip;
+   ob->priv.ctx.vblank_handler = _evas_drm_outbuf_vblank;
+
+   /* try to get drm resources */
+   if (!(res = drmModeGetResources(ob->priv.fd)))
+     {
+        CRI("Could not get drm resources: %m");
+        return EINA_FALSE;
+     }
+
+   /* loop the connectors */
+   for (; i < res->count_connectors; ++i)
+     {
+        int crtc = -1;
+        int m = 0;
+
+        /* try to get this connector */
+        if (!(conn = drmModeGetConnector(ob->priv.fd, res->connectors[i])))
+          {
+             WRN("Could not get drm connector %d: %m", i);
+             continue;
+          }
+
+        /* make sure this connector is actually connected */
+        if (conn->connection != DRM_MODE_CONNECTED) 
+          {
+             /* free connector resources */
+             drmModeFreeConnector(conn);
+             continue;
+          }
+
+        /* make sure it has modes */
+        if (conn->count_modes == 0)
+          {
+             /* free connector resources */
+             drmModeFreeConnector(conn);
+             continue;
+          }
+
+        /* try to find a crtc for this connector */
+        if ((crtc = _evas_drm_crtc_find(ob->priv.fd, res, conn)) < 0) 
+          {
+             /* free connector resources */
+             drmModeFreeConnector(conn);
+             continue;
+          }
+
+        /* record the connector id */
+        ob->priv.conn = conn->connector_id;
+
+        /* record the crtc id */
+        ob->priv.crtc = crtc;
+
+        /* spew out connector properties for testing */
+        /* drmModePropertyPtr props; */
+        /* for (m = 0; m < conn->count_props; m++) */
+        /*   { */
+        /*      props = drmModeGetProperty(ob->priv.fd, conn->props[m]); */
+        /*      if (!props) continue; */
+        /*      DBG("Property Name: %s", props->name); */
+        /*   } */
+
+        /* record the current mode */
+        memcpy(&ob->priv.mode, &conn->modes[0], sizeof(ob->priv.mode));
+        DBG("Output Current Mode: %d: %d %d", ob->priv.conn, 
+            conn->modes[0].hdisplay, conn->modes[0].vdisplay);
+
+        for (m = 0; m < conn->count_modes; m++)
+          {
+             DBG("Output Available Mode: %d: %d %d %d", ob->priv.conn, 
+                 conn->modes[m].hdisplay, conn->modes[m].vdisplay, 
+                 conn->modes[m].vrefresh);
+
+             /* try to find a mode which matches the requested size */
+             if ((conn->modes[m].hdisplay == ob->w) && 
+                 (conn->modes[m].vdisplay == ob->h) && 
+                 (conn->modes[m].vrefresh == 60))
+               {
+                  memcpy(&ob->priv.mode, &conn->modes[m], 
+                         sizeof(ob->priv.mode));
+               }
+          }
+
+        /* free connector resources */
+        drmModeFreeConnector(conn);
+
+        break;
+     }
+
+   /* free drm resources */
+   drmModeFreeResources(res);
+
+   return EINA_TRUE;
+}
+
+void 
+evas_drm_outbuf_framebuffer_set(Outbuf *ob, Buffer *buffer)
+{
+   int ret;
+
+   /* validate params */
+   if ((!ob) || (!buffer)) return;
+
+   ret = drmModeSetCrtc(ob->priv.fd, ob->priv.crtc, buffer->fb, 0, 0, 
+                        &ob->priv.conn, 1, &ob->priv.mode);
+
+   if (ret) ERR("Failed to set crtc: %m");
+   else buffer->valid = EINA_TRUE;
+}
+
+Eina_Bool 
+evas_drm_framebuffer_create(int fd, Buffer *buffer, int depth)
+{
+   struct drm_mode_create_dumb carg;
+   struct drm_mode_destroy_dumb darg;
+   struct drm_mode_map_dumb marg;
+
+   /* check for valid info */
+   if (fd < 0) return EINA_FALSE;
+
+   /* try to create a dumb buffer */
+   memset(&carg, 0, sizeof(carg));
+   carg.width = buffer->w;
+   carg.height = buffer->h;
+   carg.bpp = depth;
+   if (drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &carg) < 0)
+     {
+        ERR("Could not create dumb buffer: %m");
+        return EINA_FALSE;
+     }
+
+   buffer->stride = carg.pitch;
+   buffer->size = carg.size;
+   buffer->handle = carg.handle;
+
+   /* try to create a framebuffer object */
+   /* FIXME: Hardcoded bpp */
+   if (drmModeAddFB(fd, buffer->w, buffer->h, 24, depth, buffer->stride, 
+                    buffer->handle, &buffer->fb))
+     {
+        ERR("Could not create framebuffer object: %m");
+        goto add_err;
+     }
+
+   DBG("Creating dumb buffer: %d %d %d %d", buffer->fb, 
+       buffer->w, buffer->h, depth);
+
+   /* try to mmap the buffer */
+   memset(&marg, 0, sizeof(marg));
+   marg.handle = buffer->handle;
+   if (drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &marg))
+     {
+        ERR("Could not map dumb buffer: %m");
+        goto map_err;
+     }
+
+   /* do actual mmap of memory */
+   buffer->data = 
+     mmap(0, buffer->size, (PROT_WRITE), 
+//     mmap(0, buffer->size, (PROT_READ | PROT_WRITE), 
+          MAP_SHARED, fd, marg.offset);
+   if (buffer->data == MAP_FAILED)
+     {
+        ERR("Could not mmap dumb buffer: %m");
+        goto map_err;
+     }
+
+   /* clear memory */
+   memset(buffer->data, 0, buffer->size);
+
+   return EINA_TRUE;
+
+map_err:
+   /* remove the framebuffer */
+   drmModeRmFB(fd, buffer->fb);
+
+add_err:
+   /* destroy buffer */
+   memset(&darg, 0, sizeof(darg));
+   darg.handle = buffer->handle;
+   drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &darg);
+
+   return EINA_FALSE;
+}
+
+void 
+evas_drm_framebuffer_destroy(int fd, Buffer *buffer)
+{
+   struct drm_mode_destroy_dumb darg;
+
+   /* check for valid info */
+   if (fd < 0) return;
+
+   /* unmap the buffer data */
+   if (buffer->data) munmap(buffer->data, buffer->size);
+
+   /* remove the framebuffer */
+   drmModeRmFB(fd, buffer->fb);
+
+   /* destroy buffer */
+   memset(&darg, 0, sizeof(darg));
+   darg.handle = buffer->handle;
+   drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &darg);
+}
+
+Eina_Bool 
+evas_drm_framebuffer_send(Outbuf *ob, Buffer *buffer, Eina_Rectangle *rects, 
unsigned int count)
+{
+   int ret;
+
+   /* check for valid Output buffer */
+   if ((!ob) || (ob->priv.fd < 0)) return EINA_FALSE;
+
+   /* check for valid buffer */
+   if ((!buffer) || (!buffer->valid)) return EINA_FALSE;
+
+#ifdef DRM_MODE_FEATURE_DIRTYFB
+   drmModeClip *clip;
+   unsigned int i = 0;
+
+   /* WRN("drmModeDirtyFB is experimental"); */
+
+   /* NB: alloca automatically frees memory */
+   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;
+     }
+
+   ret = drmModeDirtyFB(ob->priv.fd, buffer->fb, clip, count);
+   if (ret)
+     {
+        if (ret == -EINVAL)
+          ERR("Could not set FB Dirty: %m");
+     }
+#endif
+
+   ret = drmModePageFlip(ob->priv.fd, ob->priv.crtc, buffer->fb, 
+                         DRM_MODE_PAGE_FLIP_EVENT, ob);
+   if (ret)
+     {
+        ERR("Cannot flip crtc for connector %u: %m", ob->priv.conn);
+        return EINA_FALSE;
+     }
+
+   ob->priv.sent = buffer;
+   ob->priv.pending_flip = EINA_TRUE;
+
+//   while (ob->priv.pending_flip)
+     drmHandleEvent(ob->priv.fd, &ob->priv.ctx);
+
+   return EINA_TRUE;
+}
diff --git a/src/modules/evas/engines/drm/evas_engine.c 
b/src/modules/evas/engines/drm/evas_engine.c
index cc5e86f..c3bdf34 100644
--- a/src/modules/evas/engines/drm/evas_engine.c
+++ b/src/modules/evas/engines/drm/evas_engine.c
@@ -1,6 +1,3 @@
-#include "evas_common_private.h"
-#include "evas_private.h"
-#include "Evas_Engine_Drm.h"
 #include "evas_engine.h"
 
 /* local structures */
@@ -25,7 +22,7 @@ struct _Render_Engine
 };
 
 /* local function prototypes */
-static void *_output_setup(int w, int h, unsigned int rotation, unsigned int 
depth, Eina_Bool alpha, int swap);
+static void *_output_setup(Evas_Engine_Info_Drm *info, int w, int h, int swap);
 
 /* function tables - filled in later (func and parent func) */
 static Evas_Func func, pfunc;
@@ -35,7 +32,7 @@ int _evas_engine_drm_log_dom;
 
 /* local functions */
 static void *
-_output_setup(int w, int h, unsigned int rotation, unsigned int depth, 
Eina_Bool alpha, int swap)
+_output_setup(Evas_Engine_Info_Drm *info, int w, int h, int swap)
 {
    Render_Engine *re;
 
@@ -53,15 +50,31 @@ _output_setup(int w, int h, unsigned int rotation, unsigned 
int depth, Eina_Bool
    /* set tilesize */
    evas_common_tilebuf_set_tile_size(re->tb, TILESIZE, TILESIZE);
 
+   /* if we have no drm device, get one */
+   if (info->info.fd < 0)
+     {
+        /* try to init drm (this includes openening the card & tty) */
+        if (!evas_drm_init(info, 0))
+          {
+             if (re->tb) evas_common_tilebuf_free(re->tb);
+             free(re);
+             return NULL;
+          }
+     }
+
    if (swap)
      {
         /* free any existing outbuf */
         if (re->ob) evas_outbuf_free(re->ob);
 
         /* try to create new outbuf */
-        if (!(re->ob = evas_outbuf_setup(w, h, rotation, depth, alpha)))
+        if (!(re->ob = evas_outbuf_setup(info, w, h)))
           {
              if (re->tb) evas_common_tilebuf_free(re->tb);
+
+             /* shutdown drm card & tty */
+             evas_drm_shutdown(info);
+
              free(re);
              return NULL;
           }
@@ -111,6 +124,12 @@ eng_setup(Evas *evas, void *einfo)
    /* try to get the evas public data */
    if (!(epd = eo_data_scope_get(evas, EVAS_CLASS))) return 0;
 
+   /* set canvas reference
+    * 
+    * NB: We do this here so that on a vt switch, we can disable 
+    * rendering (or re-enable) for this canvas */
+   info->info.evas = evas;
+
    /* check for valid engine output */
    if (!(re = epd->engine.data.output))
      {
@@ -138,9 +157,7 @@ eng_setup(Evas *evas, void *einfo)
           }
 
         /* try to create a new render_engine */
-        if (!(re = _output_setup(epd->output.w, epd->output.h, 
-                                 info->info.rotation, info->info.depth, 
-                                 info->info.destination_alpha, swap)))
+        if (!(re = _output_setup(info, epd->output.w, epd->output.h, swap)))
           return 0;
      }
    else
@@ -149,10 +166,7 @@ eng_setup(Evas *evas, void *einfo)
         if (re->ob) evas_outbuf_free(re->ob);
 
         /* try to create a new outbuf */
-        if (!(re->ob = 
-              evas_outbuf_setup(epd->output.w, epd->output.h, 
-                                info->info.rotation, info->info.depth, 
-                                info->info.destination_alpha)))
+        if (!(re->ob = evas_outbuf_setup(info, epd->output.w, epd->output.h)))
           return 0;
      }
 
@@ -190,6 +204,9 @@ eng_output_free(void *data)
           evas_common_tilebuf_free_render_rects(re->prev_rects[1]);
         if (re->prev_rects[2])
           evas_common_tilebuf_free_render_rects(re->prev_rects[2]);
+
+        evas_drm_shutdown(re->info);
+
         free(re);
      }
 
@@ -197,6 +214,266 @@ eng_output_free(void *data)
    evas_common_image_shutdown();
 }
 
+static void 
+eng_output_resize(void *data, int w, int h)
+{
+   Render_Engine *re;
+
+   /* try to get the render_engine */
+   if (!(re = (Render_Engine *)data)) return;
+
+   evas_outbuf_reconfigure(re->info, re->ob, w, h);
+
+   if (re->tb) evas_common_tilebuf_free(re->tb);
+   if ((re->tb = evas_common_tilebuf_new(w, h)))
+     evas_common_tilebuf_set_tile_size(re->tb, TILESIZE, TILESIZE);
+}
+
+static void 
+eng_output_tile_size_set(void *data, int w, int h)
+{
+   Render_Engine *re;
+
+   /* try to get the render_engine */
+   if (!(re = (Render_Engine *)data)) return;
+   if (re->tb) evas_common_tilebuf_set_tile_size(re->tb, w, h);
+}
+
+static void 
+eng_output_redraws_rect_add(void *data, int x, int y, int w, int h)
+{
+   Render_Engine *re;
+
+   /* try to get the render_engine */
+   if (!(re = (Render_Engine *)data)) return;
+   if (re->tb) evas_common_tilebuf_add_redraw(re->tb, x, y, w, h);
+}
+
+static void 
+eng_output_redraws_rect_del(void *data, int x, int y, int w, int h)
+{
+   Render_Engine *re;
+
+   /* try to get the render_engine */
+   if (!(re = (Render_Engine *)data)) return;
+   if (re->tb) evas_common_tilebuf_del_redraw(re->tb, x, y, w, h);
+}
+
+static void 
+eng_output_redraws_clear(void *data)
+{
+   Render_Engine *re;
+
+   /* try to get the render_engine */
+   if (!(re = (Render_Engine *)data)) return;
+   if (re->tb) evas_common_tilebuf_clear(re->tb);
+}
+
+static Tilebuf_Rect *
+_merge_rects(Tilebuf *tb, Tilebuf_Rect *r1, Tilebuf_Rect *r2, Tilebuf_Rect *r3)
+{
+   Tilebuf_Rect *r, *rects;
+   
+   if (r1)
+     {
+        EINA_INLIST_FOREACH(EINA_INLIST_GET(r1), r)
+          evas_common_tilebuf_add_redraw(tb, r->x, r->y, r->w, r->h);
+     }
+   if (r2)
+     {
+        EINA_INLIST_FOREACH(EINA_INLIST_GET(r2), r)
+          evas_common_tilebuf_add_redraw(tb, r->x, r->y, r->w, r->h);
+     }
+   if (r3)
+     {
+        EINA_INLIST_FOREACH(EINA_INLIST_GET(r3), r)
+          evas_common_tilebuf_add_redraw(tb, r->x, r->y, r->w, r->h);
+     }
+   rects = evas_common_tilebuf_get_render_rects(tb);
+
+/*   
+   // bounding box -> make a bounding box single region update of all regions.
+   // yes we could try and be smart and figure out size of regions, how far
+   // apart etc. etc. to try and figure out an optimal "set". this is a 
tradeoff
+   // between multiple update regions to render and total pixels to render.
+   if (rects)
+     {
+        px1 = rects->x; py1 = rects->y;
+        px2 = rects->x + rects->w; py2 = rects->y + rects->h;
+        EINA_INLIST_FOREACH(EINA_INLIST_GET(rects), r)
+          {
+             if (r->x < x1) px1 = r->x;
+             if (r->y < y1) py1 = r->y;
+             if ((r->x + r->w) > x2) px2 = r->x + r->w;
+             if ((r->y + r->h) > y2) py2 = r->y + r->h;
+          }
+        evas_common_tilebuf_free_render_rects(rects);
+        rects = calloc(1, sizeof(Tilebuf_Rect));
+        if (rects)
+          {
+             rects->x = px1;
+             rects->y = py1;
+             rects->w = px2 - px1;
+             rects->h = py2 - py1;
+          }
+     }
+ */
+   evas_common_tilebuf_clear(tb);
+   return rects;
+}
+
+static void *
+eng_output_redraws_next_update_get(void *data, int *x, int *y, int *w, int *h, 
int *cx, int *cy, int *cw, int *ch)
+{
+   Render_Engine *re;
+   RGBA_Image *img;
+   Tilebuf_Rect *rect;
+
+   /* try to get the render_engine */
+   if (!(re = (Render_Engine *)data)) return NULL;
+
+#define CLEAR_PREV_RECTS(x) \
+   do { \
+      if (re->prev_rects[x]) \
+        evas_common_tilebuf_free_render_rects(re->prev_rects[x]); \
+      re->prev_rects[x] = NULL; \
+   } while (0)
+
+   if (re->end)
+     {
+        re->end = EINA_FALSE;
+        return NULL;
+     }
+
+   if (!re->rects)
+     {
+        re->mode = evas_outbuf_buffer_state_get(re->ob);
+        if ((re->rects = evas_common_tilebuf_get_render_rects(re->tb)))
+          {
+             if ((re->lost_back) || (re->mode == MODE_FULL))
+               {
+                  re->lost_back = EINA_FALSE;
+                  evas_common_tilebuf_add_redraw(re->tb, 
+                                                 0, 0, re->ob->w, re->ob->h);
+                  evas_common_tilebuf_free_render_rects(re->rects);
+                  re->rects = evas_common_tilebuf_get_render_rects(re->tb);
+               }
+
+             evas_common_tilebuf_clear(re->tb);
+             CLEAR_PREV_RECTS(2);
+             re->prev_rects[2] = re->prev_rects[1];
+             re->prev_rects[1] = re->prev_rects[0];
+             re->prev_rects[0] = re->rects;
+             re->rects = NULL;
+
+             switch (re->mode)
+               {
+                case MODE_FULL:
+                case MODE_COPY:
+                  re->rects = 
+                    _merge_rects(re->tb, re->prev_rects[0], NULL, NULL);
+                  break;
+                case MODE_DOUBLE:
+                  re->rects = 
+                    _merge_rects(re->tb, re->prev_rects[0], re->prev_rects[1], 
NULL);
+                  break;
+                case MODE_TRIPLE:
+                  re->rects = 
+                    _merge_rects(re->tb, re->prev_rects[0], re->prev_rects[1], 
re->prev_rects[2]);
+                  break;
+                default:
+                  break;
+               }
+          }
+
+        /* NB: Not sure this is entirely needed here as it's already done 
+         * inside _merge_rects */
+        /* evas_common_tilebuf_clear(re->tb); */
+        re->cur_rect = EINA_INLIST_GET(re->rects);
+     }
+
+   if (!re->cur_rect) return NULL;
+   rect = (Tilebuf_Rect *)re->cur_rect;
+   if (re->rects)
+     {
+        switch (re->mode)
+          {
+           case MODE_COPY:
+           case MODE_DOUBLE:
+           case MODE_TRIPLE:
+             rect = (Tilebuf_Rect *)re->cur_rect;
+             *x = rect->x;
+             *y = rect->y;
+             *w = rect->w;
+             *h = rect->h;
+             *cx = rect->x;
+             *cy = rect->y;
+             *cw = rect->w;
+             *ch = rect->h;
+             re->cur_rect = re->cur_rect->next;
+             break;
+           case MODE_FULL:
+             re->cur_rect = NULL;
+             if (x) *x = 0;
+             if (y) *y = 0;
+             if (w) *w = re->ob->w;
+             if (h) *h = re->ob->h;
+             if (cx) *cx = 0;
+             if (cy) *cy = 0;
+             if (cw) *cw = re->ob->w;
+             if (ch) *ch = re->ob->h;
+             break;
+           default:
+             break;
+          }
+        img = 
+          evas_outbuf_update_region_new(re->ob, *x, *y, *w, *h, 
+                                        cx, cy, cw, ch);
+        if (!re->cur_rect) 
+          {
+             evas_common_tilebuf_free_render_rects(re->rects);
+             re->rects = NULL;
+             re->end = EINA_TRUE;
+          }
+
+        return img;
+     }
+
+   return NULL;
+}
+
+static void 
+eng_output_redraws_next_update_push(void *data, void *img, int x, int y, int 
w, int h, Evas_Render_Mode render_mode)
+{
+   Render_Engine *re;
+
+   if (render_mode == EVAS_RENDER_MODE_ASYNC_INIT) return;
+
+   if (!(re = (Render_Engine *)data)) return;
+#if defined(BUILD_PIPE_RENDER)
+   evas_common_pipe_map_begin(img);
+#endif
+   evas_outbuf_update_region_push(re->ob, img, x, y, w, h);
+
+   /* NB: No reason to free region here. That is done on flush anyway */
+   /* re->outbuf_update_region_free(re->ob, img); */
+
+   evas_common_cpu_end_opt();
+}
+
+static void 
+eng_output_flush(void *data, Evas_Render_Mode render_mode)
+{
+   Render_Engine *re;
+
+   if (render_mode == EVAS_RENDER_MODE_ASYNC_INIT) return;
+
+   if (!(re = (Render_Engine *)data)) return;
+   evas_outbuf_flush(re->ob);
+   if (re->rects) evas_common_tilebuf_free_render_rects(re->rects);
+   re->rects = NULL;
+}
+
 /* module api functions */
 static int
 module_open(Evas_Module *em)
@@ -226,6 +503,15 @@ module_open(Evas_Module *em)
    EVAS_API_OVERRIDE(info_free, &func, eng_);
    EVAS_API_OVERRIDE(setup, &func, eng_);
    EVAS_API_OVERRIDE(output_free, &func, eng_);
+   EVAS_API_OVERRIDE(output_resize, &func, eng_);
+   EVAS_API_OVERRIDE(output_tile_size_set, &func, eng_);
+   EVAS_API_OVERRIDE(output_redraws_rect_add, &func, eng_);
+   EVAS_API_OVERRIDE(output_redraws_rect_del, &func, eng_);
+   EVAS_API_OVERRIDE(output_redraws_clear, &func, eng_);
+   EVAS_API_OVERRIDE(output_redraws_next_update_get, &func, eng_);
+   EVAS_API_OVERRIDE(output_redraws_next_update_push, &func, eng_);
+   EVAS_API_OVERRIDE(output_flush, &func, eng_);
+   /* EVAS_API_OVERRIDE(output_idle_flush, &func, eng_); */
 
    /* advertise our engine functions */
    em->functions = (void *)(&func);
diff --git a/src/modules/evas/engines/drm/evas_engine.h 
b/src/modules/evas/engines/drm/evas_engine.h
index 3cfbbee..5abfcd8 100644
--- a/src/modules/evas/engines/drm/evas_engine.h
+++ b/src/modules/evas/engines/drm/evas_engine.h
@@ -1,6 +1,22 @@
 #ifndef EVAS_ENGINE_H
 # define EVAS_ENGINE_H
 
+#include "evas_common_private.h"
+#include "evas_macros.h"
+#include "evas_private.h"
+#include "Evas.h"
+#include "Evas_Engine_Drm.h"
+
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <drm_fourcc.h>
+
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+
 extern int _evas_engine_drm_log_dom;
 
 # ifdef ERR
@@ -28,6 +44,10 @@ extern int _evas_engine_drm_log_dom;
 # endif
 # define CRI(...) EINA_LOG_DOM_CRIT(_evas_engine_drm_log_dom, __VA_ARGS__)
 
+/* define a maximum number of 'buffers' (double-buff, triple-buff, etc) */
+# define NUM_BUFFERS 2
+
+typedef struct _Buffer Buffer;
 typedef struct _Outbuf Outbuf;
 
 enum
@@ -38,15 +58,65 @@ enum
    MODE_TRIPLE
 };
 
+enum
+{
+   OUTBUF_DEPTH_NONE,
+   OUTBUF_DEPTH_ARGB_32BPP_8888_8888,
+   OUTBUF_DEPTH_RGB_32BPP_8888_8888,
+   OUTBUF_DEPTH_LAST
+};
+
+struct _Buffer
+{
+   int w, h;
+   int stride, size;
+   int handle;
+   unsigned int fb;
+   void *data;
+
+   Eina_Bool valid : 1;
+};
+
 struct _Outbuf
 {
    int w, h;
    unsigned int rotation, depth;
    Eina_Bool destination_alpha : 1;
+
+   struct 
+     {
+        RGBA_Image *onebuf;
+        Eina_Array onebuf_regions;
+
+        Buffer buffer[NUM_BUFFERS], *sent;
+        int curr, num;
+
+        int fd;
+        unsigned int conn, crtc;
+        drmModeModeInfo mode;
+        drmEventContext ctx;
+        Eina_Bool pending_flip : 1;
+
+        Eina_List *pending_writes;
+        Eina_List *prev_pending_writes;
+     } priv;
 };
 
-Outbuf *evas_outbuf_setup(int w, int h, unsigned int rotation, unsigned int 
depth, Eina_Bool alpha);
+Outbuf *evas_outbuf_setup(Evas_Engine_Info_Drm *info, int w, int h);
 void evas_outbuf_free(Outbuf *ob);
-void evas_outbuf_reconfigure(Outbuf *ob, int w, int h, unsigned int rotation, 
unsigned int depth, Eina_Bool alpha);
+void evas_outbuf_reconfigure(Evas_Engine_Info_Drm *info, Outbuf *ob, int w, 
int h);
+int evas_outbuf_buffer_state_get(Outbuf *ob);
+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);
+void evas_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int 
y, int w, int h);
+void evas_outbuf_flush(Outbuf *ob);
+
+Eina_Bool evas_drm_init(Evas_Engine_Info_Drm *info, int card);
+Eina_Bool evas_drm_shutdown(Evas_Engine_Info_Drm *info);
+
+Eina_Bool evas_drm_outbuf_setup(Outbuf *ob);
+void evas_drm_outbuf_framebuffer_set(Outbuf *ob, Buffer *buffer);
+Eina_Bool evas_drm_framebuffer_create(int fd, Buffer *buffer, int depth);
+void evas_drm_framebuffer_destroy(int fd, Buffer *buffer);
+Eina_Bool evas_drm_framebuffer_send(Outbuf *ob, Buffer *buffer, Eina_Rectangle 
*rects, unsigned int count);
 
 #endif
diff --git a/src/modules/evas/engines/drm/evas_outbuf.c 
b/src/modules/evas/engines/drm/evas_outbuf.c
index e6327b6..256f1b6 100644
--- a/src/modules/evas/engines/drm/evas_outbuf.c
+++ b/src/modules/evas/engines/drm/evas_outbuf.c
@@ -1,22 +1,135 @@
-#include "evas_common_private.h"
-#include "evas_private.h"
 #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 0x00ff0000
+#define GREEN_MASK 0x0000ff00
+#define BLUE_MASK 0x000000ff
+
+static Eina_Bool 
+_evas_outbuf_buffer_new(Outbuf *ob, Buffer *buffer)
+{
+   /* check for valid outbuf */
+   if (!ob) return EINA_FALSE;
+
+   buffer->w = ob->w;
+   buffer->h = ob->h;
+
+   /* sadly we cannot create buffers to be JUST the size of the canvas.
+    * drmModeSetCrtc will barf with ENOSPC if we try that :( so we have to 
+    * allocate framebuffer objects to be the whole size of the display mode */
+
+   /* if (ob->priv.mode.hdisplay > buffer->w) */
+   /*   buffer->w = ob->priv.mode.hdisplay; */
+   /* if (ob->priv.mode.vdisplay > buffer->h) */
+   /*   buffer->h = ob->priv.mode.vdisplay; */
+
+   /* create a drm fb for this buffer */
+   if (!evas_drm_framebuffer_create(ob->priv.fd, buffer, ob->depth))
+     {
+        CRI("Could not create drm framebuffer");
+        return EINA_FALSE;
+     }
+
+   /* evas_drm_outbuf_framebuffer_set(ob, buffer); */
+
+   return EINA_TRUE;
+}
+
+static void *
+_evas_outbuf_buffer_map(Outbuf *ob, int *w, int *h)
+{
+   if (w) *w = ob->w;
+   if (h) *h = ob->h;
+   return ob->priv.buffer[ob->priv.curr].data;
+}
+
+static void 
+_evas_outbuf_buffer_put(Outbuf *ob, Buffer *buffer, Eina_Rectangle *rects, 
unsigned int count)
+{
+   /* validate input params */
+   if ((!ob) || (!buffer)) return;
+
+   if (!buffer->data)
+     {
+        CRI("Current Buffer Has No Data !!");
+        /* TODO: call function to mmap buffer data */
+        /* if (!_evas_outbuf_buffer_new(ob, buffer)); */
+        return;
+     }
+
+   if (ob->priv.sent != buffer)
+     {
+        if (!buffer->valid) evas_drm_outbuf_framebuffer_set(ob, buffer);
+        if (!evas_drm_framebuffer_send(ob, buffer, rects, count))
+          ERR("Could not send buffer");
+     }
+}
+
+static void 
+_evas_outbuf_buffer_swap(Outbuf *ob, Eina_Rectangle *rects, unsigned int count)
+{
+   /* check for valid output buffer */
+   if (!ob) return;
+
+   _evas_outbuf_buffer_put(ob, &(ob->priv.buffer[ob->priv.curr]), 
+                           rects, count);
+}
 
 Outbuf *
-evas_outbuf_setup(int w, int h, unsigned int rotation, unsigned int depth, 
Eina_Bool alpha)
+evas_outbuf_setup(Evas_Engine_Info_Drm *info, int w, int h)
 {
    Outbuf *ob;
+   char *num;
+   int i = 0;
 
-   /* try to allocate space for out outbuf structure */
+   /* try to allocate space for our outbuf structure */
    if (!(ob = calloc(1, sizeof(Outbuf))))
      return NULL;
 
    /* set some default outbuf properties */
    ob->w = w;
    ob->h = h;
-   ob->rotation = rotation;
-   ob->depth = depth;
-   ob->destination_alpha = alpha;
+   ob->rotation = info->info.rotation;
+   ob->depth = info->info.depth;
+   ob->destination_alpha = info->info.destination_alpha;
+
+   /* set drm file descriptor */
+   ob->priv.fd = info->info.fd;
+
+   /* try to setup the drm card for this outbuf */
+   if (!evas_drm_outbuf_setup(ob))
+     {
+        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;
+     }
+
+   /* with the connector and crtc set, we can now create buffers !! :) */
+   for (; i < ob->priv.num; i++)
+     {
+        if (!_evas_outbuf_buffer_new(ob, &(ob->priv.buffer[i])))
+          {
+             CRI("Failed to create buffer");
+             break;
+          }
+     }
+
+   /* set array step size for regions */
+   eina_array_step_set(&ob->priv.onebuf_regions, sizeof(Eina_Array), 8);
 
    /* return the allocated outbuf structure */
    return ob;
@@ -25,21 +138,431 @@ evas_outbuf_setup(int w, int h, unsigned int rotation, 
unsigned int depth, Eina_
 void 
 evas_outbuf_free(Outbuf *ob)
 {
+   int i = 0;
+
+   /* destroy the buffers */
+   for (; i < ob->priv.num; i++)
+     evas_drm_framebuffer_destroy(ob->priv.fd, &(ob->priv.buffer[i]));
+
+   eina_array_flush(&ob->priv.onebuf_regions);
+
    /* free the allocated outbuf structure */
    free(ob);
 }
 
 void 
-evas_outbuf_reconfigure(Outbuf *ob, int w, int h, unsigned int rotation, 
unsigned int depth, Eina_Bool alpha)
+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 == alpha) && 
-       (ob->rotation == rotation) && (ob->depth == depth)) return;
+   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->w = w;
-   ob->h = h;
-   ob->rotation = rotation;
-   ob->depth = depth;
-   ob->destination_alpha = alpha;
+   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;
+   Eina_Rectangle *rect;
+
+   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 bpl = 0;
+             int bw = 0, bh = 0;
+             void *data;
+
+             data = _evas_outbuf_buffer_map(ob, &bw, &bh);
+             bpl = (bw * sizeof(int));
+
+#ifdef EVAS_CSERVE2
+             if (evas_cserve2_use_get())
+               img = (RGBA_Image 
*)evas_cache2_image_data(evas_common_image_cache2_get(),
+                                                          bpl / sizeof(int), 
bh, 
+                                                          data, 
+                                                          
ob->destination_alpha, 
+                                                          
EVAS_COLORSPACE_ARGB8888);
+             else
+#endif
+               img = (RGBA_Image 
*)evas_cache_image_data(evas_common_image_cache_get(),
+                                                         bpl / sizeof(int), 
bh, 
+                                                         data, 
+                                                         
ob->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;
+          }
+
+        /* clip the region to the onebuf region */
+        if (cx) *cx = x;
+        if (cy) *cy = y;
+        if (cw) *cw = w;
+        if (ch) *ch = h;
+
+        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.flags.alpha |= ob->destination_alpha;
+
+#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;
+
+   /* 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_outbuf_buffer_map(ob, &ww, &hh))) 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_flush(Outbuf *ob)
+{
+   Eina_Rectangle *rects;
+   RGBA_Image *img;
+   unsigned int n = 0, i = 0;
+
+   /* check for valid output buffer */
+   if (!ob) 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 (!(rects = alloca(n * sizeof(Eina_Rectangle)))) return;
+
+        /* loop the buffer regions and assign to rects */
+        EINA_ARRAY_ITER_NEXT(&ob->priv.onebuf_regions, i, rect, it)
+          rects[i] = *rect;
+
+        /* TODO: unmap the buffer ?? */
+        /* evas_swapper_buffer_unmap(ob->priv.swapper); */
+
+        /* force a buffer swap */
+        _evas_outbuf_buffer_swap(ob, rects, 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 (!(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++;
+          }
+
+        /* TODO: unmap the buffer ?? */
+        /* evas_swapper_buffer_unmap(ob->priv.swapper); */
+
+        /* force a buffer swap */
+        _evas_outbuf_buffer_swap(ob, rects, n);
+     }
 }

-- 


Reply via email to