evas-drm: Add vsync/non-vsync support to evas_drm code
authorChris Michael <cp.michael@samsung.com>
Fri, 28 Feb 2014 12:36:11 +0000 (12:36 +0000)
committerChris Michael <cp.michael@samsung.com>
Fri, 28 Feb 2014 13:13:17 +0000 (13:13 +0000)
@feature: Add ability to render software buffers using vsync or not
@bugfix: Fix drmModeAddFB to use proper depth & bpp when adding FB
@bugfix: Fix mmap to use NULL (not 0) so that kernel assigns memory
address.

Signed-off-by: Chris Michael <cp.michael@samsung.com>
src/modules/evas/engines/drm/evas_drm.c

index 7e1134b..42d64f7 100644 (file)
@@ -190,6 +190,18 @@ _evas_drm_crtc_find(int fd, drmModeRes *res, drmModeConnector *conn)
    return crtc;
 }
 
+static unsigned int 
+_evas_drm_crtc_buffer_get(int fd, int crtc_id)
+{
+   drmModeCrtc *crtc;
+   unsigned int id;
+
+   if (!(crtc = drmModeGetCrtc(fd, crtc_id))) return 0;
+   id = crtc->buffer_id;
+   drmModeFreeCrtc(crtc);
+   return id;
+}
+
 static void 
 _evas_drm_tty_sigusr1(int x EINA_UNUSED, siginfo_t *info, void *data EINA_UNUSED)
 {
@@ -525,6 +537,9 @@ evas_drm_outbuf_setup(Outbuf *ob)
         /* record the crtc id */
         ob->priv.crtc = crtc;
 
+        /* record the current framebuffer */
+        ob->priv.fb = _evas_drm_crtc_buffer_get(ob->priv.fd, crtc);
+
         /* spew out connector properties for testing */
         /* drmModePropertyPtr props; */
         /* for (m = 0; m < conn->count_props; m++) */
@@ -536,14 +551,12 @@ evas_drm_outbuf_setup(Outbuf *ob)
 
         /* 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); */
+             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) && 
@@ -555,6 +568,17 @@ evas_drm_outbuf_setup(Outbuf *ob)
                }
           }
 
+        DBG("Output Current Mode: %d: %d %d", ob->priv.conn, 
+            ob->priv.mode.hdisplay, ob->priv.mode.vdisplay);
+
+        if ((ob->priv.mode.hdisplay != conn->modes[0].hdisplay) || 
+            (ob->priv.mode.vdisplay != conn->modes[0].vdisplay))
+          {
+             /* set new crtc mode */
+             drmModeSetCrtc(ob->priv.fd, ob->priv.crtc, ob->priv.fb, 0, 0, 
+                            &ob->priv.conn, 1, &ob->priv.mode);
+          }
+
         /* free connector resources */
         drmModeFreeConnector(conn);
 
@@ -588,6 +612,8 @@ evas_drm_outbuf_framebuffer_set(Outbuf *ob, Buffer *buffer)
    /* validate params */
    if ((!ob) || (!buffer)) return;
 
+   /* DBG("Drm Framebuffer Set: %d", buffer->fb); */
+
    buffer->valid = EINA_FALSE;
    ret = drmModeSetCrtc(ob->priv.fd, ob->priv.crtc, buffer->fb, 0, 0, 
                         &ob->priv.conn, 1, &ob->priv.mode);
@@ -611,6 +637,7 @@ evas_drm_framebuffer_create(int fd, Buffer *buffer, int depth)
    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");
@@ -621,13 +648,13 @@ evas_drm_framebuffer_create(int fd, Buffer *buffer, int depth)
    buffer->size = carg.size;
    buffer->handle = carg.handle;
 
-   /* DBG("Buffer: %d %d", buffer->w, buffer->h); */
-   /* DBG("Buffer Stride: %d", buffer->stride); */
-   /* DBG("Buffer Size: %d", buffer->size); */
+   DBG("Buffer: %d %d", buffer->w, buffer->h);
+   DBG("Buffer Stride: %d", buffer->stride);
+   DBG("Buffer Size: %d", buffer->size);
 
    /* try to create a framebuffer object */
    /* FIXME: Hardcoded bpp */
-   if (drmModeAddFB(fd, buffer->w, buffer->h, 32, depth, buffer->stride, 
+   if (drmModeAddFB(fd, buffer->w, buffer->h, 24, depth, buffer->stride, 
                     buffer->handle, &buffer->fb))
      {
         ERR("Could not create framebuffer object: %m");
@@ -648,7 +675,7 @@ evas_drm_framebuffer_create(int fd, Buffer *buffer, int depth)
 
    /* do actual mmap of memory */
    buffer->data = 
-     mmap(0, buffer->size, (PROT_READ | PROT_WRITE), 
+     mmap(NULL, buffer->size, (PROT_READ | PROT_WRITE), 
           MAP_SHARED, fd, marg.offset);
    if (buffer->data == MAP_FAILED)
      {
@@ -695,56 +722,50 @@ evas_drm_framebuffer_destroy(int fd, Buffer *buffer)
 }
 
 Eina_Bool 
-evas_drm_framebuffer_send(Outbuf *ob, Buffer *buffer, Eina_Rectangle *rects, unsigned int count)
+evas_drm_framebuffer_send(Outbuf *ob, Buffer *buffer)
 {
    int ret;
-   unsigned int flags = 0;
 
    /* 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;
+   if (!buffer) return EINA_FALSE;
 
-#ifdef DRM_MODE_FEATURE_DIRTYFB
-   drmModeClip *clip;
-   unsigned int i = 0;
+   if (ob->vsync)
+     {
+        unsigned int flags = 0;
 
-   /* WRN("drmModeDirtyFB is experimental"); */
+        if (!buffer->valid) evas_drm_outbuf_framebuffer_set(ob, buffer);
 
-   /* 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;
-     }
+        flags = DRM_MODE_PAGE_FLIP_EVENT;
+        if (ob->priv.use_async_page_flip) flags |= DRM_MODE_PAGE_FLIP_ASYNC;
 
-   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, flags, ob);
+        if (ret)
+          {
+             ERR("Cannot flip crtc for connector %u: %m", ob->priv.conn);
+             return EINA_FALSE;
+          }
 
-   flags = DRM_MODE_PAGE_FLIP_EVENT;
-   if (ob->priv.use_async_page_flip) flags |= DRM_MODE_PAGE_FLIP_ASYNC;
+        ob->priv.pending_flip = EINA_TRUE;
 
-   ret = drmModePageFlip(ob->priv.fd, ob->priv.crtc, buffer->fb, flags, ob);
-   if (ret)
-     {
-        ERR("Cannot flip crtc for connector %u: %m", ob->priv.conn);
-        return EINA_FALSE;
+        while (ob->priv.pending_flip)
+          drmHandleEvent(ob->priv.fd, &ob->priv.ctx);
      }
+   else
+     {
+        /* NB: We don't actually need to do this if we are not vsync
+         * because we are drawing directly to the buffer anyway.
+         * If we enable the sending of buffer to crtc, it causes vsync */
 
-   /* ob->priv.sent = buffer; */
-   ob->priv.pending_flip = EINA_TRUE;
+        /* send this buffer to the crtc */
+        /* evas_drm_outbuf_framebuffer_set(ob, buffer); */
 
-   /* while (ob->priv.pending_flip) */
-   /*   drmHandleEvent(ob->priv.fd, &ob->priv.ctx); */
+        /* increment buffer we are using */
+        ob->priv.curr = (ob->priv.curr + 1) % ob->priv.num;
+     }
 
    return EINA_TRUE;
 }