This is an automated email from the git hooks/post-receive script.

git pushed a commit to branch devs/devilhorns/apos
in repository efl.

View the commit online.

commit 0d4e346463b2bee13aaed28eae7450962616989b
Author: Christopher Michael <devilho...@comcast.net>
AuthorDate: Tue Sep 20 08:40:16 2022 -0400

    ecore_drm2: Add code to fill atomic state in threads for Crtcs, Connectors,
    Displays, and Planes
---
 src/lib/ecore_drm2/ecore_drm2_connectors.c | 228 +++++++++++++++++++++
 src/lib/ecore_drm2/ecore_drm2_crtcs.c      | 211 +++++++++++++++++++
 src/lib/ecore_drm2/ecore_drm2_device.c     | 190 +++++++++++++----
 src/lib/ecore_drm2/ecore_drm2_displays.c   | 317 +++++++++++++++++++++++++++++
 src/lib/ecore_drm2/ecore_drm2_planes.c     | 263 ++++++++++++++++++++++++
 src/lib/ecore_drm2/meson.build             |   5 +-
 6 files changed, 1169 insertions(+), 45 deletions(-)

diff --git a/src/lib/ecore_drm2/ecore_drm2_connectors.c b/src/lib/ecore_drm2/ecore_drm2_connectors.c
new file mode 100644
index 0000000000..219c5ac46d
--- /dev/null
+++ b/src/lib/ecore_drm2/ecore_drm2_connectors.c
@@ -0,0 +1,228 @@
+#include "ecore_drm2_private.h"
+
+#ifndef DRM_MODE_CONNECTOR_WRITEBACK
+# define DRM_MODE_CONNECTOR_WRITEBACK 18
+#endif
+
+static void
+_ecore_drm2_connector_state_debug(Ecore_Drm2_Connector *conn)
+{
+   DBG("Connector Atomic State Fill Complete");
+   DBG("\tConnector: %d", conn->state->obj_id);
+   DBG("\t\tCrtc Id: %lu", (long)conn->state->crtc.value);
+   DBG("\t\tDPMS: %lu", (long)conn->state->dpms.value);
+   DBG("\t\tAspect Ratio: %lu", (long)conn->state->aspect.value);
+   DBG("\t\tScaling Mode: %lu", (long)conn->state->scaling.value);
+}
+
+static void
+_ecore_drm2_connector_state_fill(Ecore_Drm2_Connector *conn)
+{
+   Ecore_Drm2_Connector_State *cstate;
+   drmModeObjectPropertiesPtr oprops;
+   unsigned int i = 0;
+
+   /* try to allocate space for connector Atomic state */
+   conn->state = calloc(1, sizeof(Ecore_Drm2_Connector_State));
+   if (!conn->state)
+     {
+        ERR("Could not allocate space for Connector state");
+        return;
+     }
+
+   cstate = conn->state;
+   cstate->obj_id = conn->id;
+
+   /* get the properties of this connector from drm */
+   oprops =
+     sym_drmModeObjectGetProperties(conn->fd, cstate->obj_id,
+                                    DRM_MODE_OBJECT_CONNECTOR);
+   if (!oprops)
+     {
+        free(conn->state);
+        return;
+     }
+
+   for (; i < oprops->count_props; i++)
+     {
+        drmModePropertyPtr prop;
+
+        /* try to get this individual property */
+        prop = sym_drmModeGetProperty(conn->fd, oprops->props[i]);
+        if (!prop) continue;
+
+        /* check for the properties we are interested in */
+        if (!strcmp(prop->name, "CRTC_ID"))
+          {
+             cstate->crtc.id = prop->prop_id;
+             cstate->crtc.value = oprops->prop_values[i];
+          }
+        else if (!strcmp(prop->name, "DPMS"))
+          {
+             cstate->dpms.id = prop->prop_id;
+             cstate->dpms.value = oprops->prop_values[i];
+          }
+        else if (!strcmp(prop->name, "EDID"))
+          {
+             drmModePropertyBlobPtr bp;
+
+             cstate->edid.id = oprops->prop_values[i];
+             if (!cstate->edid.id)
+               {
+                  cstate->edid.len = 0;
+                  goto cont;
+               }
+
+             bp = sym_drmModeGetPropertyBlob(conn->fd, cstate->edid.id);
+             if (!bp) goto cont;
+
+             if ((!cstate->edid.data) ||
+                 memcmp(cstate->edid.data, bp->data, bp->length) != 0)
+               {
+                  cstate->edid.data = "" bp->length, 1);
+               }
+
+             cstate->edid.len = bp->length;
+
+             if (cstate->edid.id != 0)
+               sym_drmModeCreatePropertyBlob(conn->fd, bp->data, bp->length,
+                                             &cstate->edid.id);
+
+             sym_drmModeFreePropertyBlob(bp);
+          }
+        else if (!strcmp(prop->name, "aspect ratio"))
+          {
+             cstate->aspect.id = prop->prop_id;
+             cstate->aspect.value = oprops->prop_values[i];
+          }
+        else if (!strcmp(prop->name, "scaling mode"))
+          {
+             cstate->scaling.id = prop->prop_id;
+             cstate->scaling.value = oprops->prop_values[i];
+          }
+
+cont:
+        sym_drmModeFreeProperty(prop);
+     }
+
+   sym_drmModeFreeObjectProperties(oprops);
+}
+
+static void
+_ecore_drm2_connector_state_thread(void *data, Ecore_Thread *thread EINA_UNUSED)
+{
+   Ecore_Drm2_Connector *conn;
+
+   conn = data;
+   if (!conn->state)
+     _ecore_drm2_connector_state_fill(conn);
+   else
+     {
+        /* TODO: update atomic state for commit */
+     }
+}
+
+static void
+_ecore_drm2_connector_state_thread_end(void *data, Ecore_Thread *thread EINA_UNUSED)
+{
+   Ecore_Drm2_Connector *conn;
+
+   conn = data;
+   /* conn->thread = NULL; */
+   _ecore_drm2_connector_state_debug(conn);
+}
+
+static void
+_ecore_drm2_connector_state_thread_cancel(void *data, Ecore_Thread *thread EINA_UNUSED)
+{
+   Ecore_Drm2_Connector *conn;
+
+   conn = data;
+   conn->thread = NULL;
+}
+
+static Ecore_Drm2_Connector *
+_ecore_drm2_connector_create(Ecore_Drm2_Device *dev, drmModeConnector *conn, uint32_t id)
+{
+   Ecore_Drm2_Connector *c;
+
+   /* try to allocate space for new connector */
+   c = calloc(1, sizeof(Ecore_Drm2_Connector));
+   if (!c) return NULL;
+
+   c->id = id;
+   c->fd = dev->fd;
+   c->conn = conn;
+   c->type = conn->connector_type;
+
+   /* check if this connector is a writeback */
+   if (conn->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
+     c->writeback = EINA_TRUE;
+
+   /* append this connector to list */
+   dev->conns = eina_list_append(dev->conns, c);
+
+   return c;
+}
+
+Eina_Bool
+_ecore_drm2_connectors_create(Ecore_Drm2_Device *dev)
+{
+   Ecore_Drm2_Connector *c;
+   drmModeConnector *conn;
+   drmModeRes *res;
+   int i = 0;
+
+   /* try to get drm resources */
+   res = sym_drmModeGetResources(dev->fd);
+   if (!res) return EINA_FALSE;
+
+   /* TOOD: set dev->min/max width & height ? */
+
+   for (; i < res->count_connectors; i++)
+     {
+        uint32_t conn_id;
+
+        conn_id = res->connectors[i];
+
+        /* try to get this connector from drm */
+        conn = sym_drmModeGetConnector(dev->fd, conn_id);
+        if (!conn) continue;
+
+        /* try to create a new connector */
+        c = _ecore_drm2_connector_create(dev, conn, conn_id);
+        if (!c) goto err;
+
+        /* NB: Use an explicit thread to fill crtc atomic state */
+        c->thread =
+          ecore_thread_feedback_run(_ecore_drm2_connector_state_thread,
+                                    NULL, //_ecore_drm2_connector_state_thread_notify,
+                                    _ecore_drm2_connector_state_thread_end,
+                                    _ecore_drm2_connector_state_thread_cancel,
+                                    c, EINA_TRUE);
+
+     }
+
+   sym_drmModeFreeResources(res);
+   return EINA_TRUE;
+
+err:
+   _ecore_drm2_connectors_destroy(dev);
+   sym_drmModeFreeConnector(conn);
+   sym_drmModeFreeResources(res);
+   return EINA_FALSE;
+}
+
+void
+_ecore_drm2_connectors_destroy(Ecore_Drm2_Device *dev)
+{
+   Ecore_Drm2_Connector *conn;
+
+   EINA_LIST_FREE(dev->conns, conn)
+     {
+        if (conn->thread) ecore_thread_cancel(conn->thread);
+        if (conn->conn) sym_drmModeFreeConnector(conn->conn);
+        free(conn->state);
+        free(conn);
+     }
+}
diff --git a/src/lib/ecore_drm2/ecore_drm2_crtcs.c b/src/lib/ecore_drm2/ecore_drm2_crtcs.c
new file mode 100644
index 0000000000..6829437a09
--- /dev/null
+++ b/src/lib/ecore_drm2/ecore_drm2_crtcs.c
@@ -0,0 +1,211 @@
+#include "ecore_drm2_private.h"
+
+static void
+_ecore_drm2_crtc_state_debug(Ecore_Drm2_Crtc *crtc)
+{
+   DBG("CRTC Atomic State Fill Complete");
+   DBG("\tCrtc: %d", crtc->state->obj_id);
+   DBG("\t\tMode: %d", crtc->state->mode.value);
+   DBG("\t\tActive: %lu", (long)crtc->state->active.value);
+}
+
+static void
+_ecore_drm2_crtc_state_fill(Ecore_Drm2_Crtc *crtc)
+{
+   Ecore_Drm2_Crtc_State *cstate;
+   drmModeObjectPropertiesPtr oprops;
+   unsigned int i = 0;
+
+   /* try to allocate space for CRTC Atomic state */
+   crtc->state = calloc(1, sizeof(Ecore_Drm2_Crtc_State));
+   if (!crtc->state)
+     {
+        ERR("Could not allocate space for CRTC state");
+        return;
+     }
+
+   cstate = crtc->state;
+   cstate->obj_id = crtc->dcrtc->crtc_id;
+
+   /* get the properties of this crtc from drm */
+   oprops =
+     sym_drmModeObjectGetProperties(crtc->fd, cstate->obj_id,
+                                    DRM_MODE_OBJECT_CRTC);
+   if (!oprops)
+     {
+        free(crtc->state);
+        return;
+     }
+
+   for (; i < oprops->count_props; i++)
+     {
+        drmModePropertyPtr prop;
+
+        /* try to get this individual property */
+        prop = sym_drmModeGetProperty(crtc->fd, oprops->props[i]);
+        if (!prop) continue;
+
+        /* check for the properties we are interested in */
+        if (!strcmp(prop->name, "MODE_ID"))
+          {
+             drmModePropertyBlobPtr bp;
+
+             cstate->mode.id = prop->prop_id;
+             cstate->mode.value = oprops->prop_values[i];
+
+             if (!cstate->mode.value)
+               {
+                  cstate->mode.len = 0;
+                  goto cont;
+               }
+
+             bp = sym_drmModeGetPropertyBlob(crtc->fd, cstate->mode.value);
+             if (!bp) goto cont;
+
+             if ((!cstate->mode.data) ||
+                 memcmp(cstate->mode.data, bp->data, bp->length) != 0)
+               {
+                  cstate->mode.data = "" bp->length, 1);
+               }
+
+             cstate->mode.len = bp->length;
+
+             if (cstate->mode.value != 0)
+               sym_drmModeCreatePropertyBlob(crtc->fd, bp->data, bp->length,
+                                             &cstate->mode.value);
+
+             sym_drmModeFreePropertyBlob(bp);
+          }
+        else if (!strcmp(prop->name, "ACTIVE"))
+          {
+             cstate->active.id = prop->prop_id;
+             cstate->active.value = oprops->prop_values[i];
+          }
+        /* TODO: We don't actually use this value yet */
+        /* else if (!strcmp(prop->name, "BACKGROUND_COLOR")) */
+        /*   { */
+        /*      cstate->background.id = prop->prop_id; */
+        /*      cstate->background.value = oprops->prop_values[i]; */
+        /*   } */
+
+cont:
+        sym_drmModeFreeProperty(prop);
+     }
+
+   sym_drmModeFreeObjectProperties(oprops);
+}
+
+static void
+_ecore_drm2_crtc_state_thread(void *data, Ecore_Thread *thread EINA_UNUSED)
+{
+   Ecore_Drm2_Crtc *crtc;
+
+   crtc = data;
+   if (!crtc->state)
+     _ecore_drm2_crtc_state_fill(crtc);
+   else
+     {
+        /* TODO: update atomic state for commit */
+     }
+}
+
+static void
+_ecore_drm2_crtc_state_thread_end(void *data, Ecore_Thread *thread EINA_UNUSED)
+{
+   Ecore_Drm2_Crtc *crtc;
+
+   crtc = data;
+   /* crtc->thread = NULL; */
+   _ecore_drm2_crtc_state_debug(crtc);
+}
+
+static void
+_ecore_drm2_crtc_state_thread_cancel(void *data, Ecore_Thread *thread EINA_UNUSED)
+{
+   Ecore_Drm2_Crtc *crtc;
+
+   crtc = data;
+   crtc->thread = NULL;
+}
+
+static Ecore_Drm2_Crtc *
+_ecore_drm2_crtc_create(Ecore_Drm2_Device *dev, drmModeCrtcPtr dcrtc, uint32_t pipe)
+{
+   Ecore_Drm2_Crtc *crtc;
+
+   /* try to allocate space for a crtc */
+   crtc = calloc(1, sizeof(Ecore_Drm2_Crtc));
+   if (!crtc)
+     {
+        ERR("Could not allocate space for CRTC");
+        goto err;
+     }
+
+   crtc->id = dcrtc->crtc_id;
+   crtc->fd = dev->fd;
+   crtc->pipe = pipe;
+   crtc->dcrtc = dcrtc;
+
+   /* add this crtc to the list */
+   dev->crtcs = eina_list_append(dev->crtcs, crtc);
+
+   return crtc;
+
+err:
+   free(crtc);
+   return NULL;
+}
+
+Eina_Bool
+_ecore_drm2_crtcs_create(Ecore_Drm2_Device *dev)
+{
+   Ecore_Drm2_Crtc *crtc;
+   drmModeCrtcPtr c;
+   drmModeRes *res;
+   int i = 0;
+
+   /* try to get drm resources */
+   res = sym_drmModeGetResources(dev->fd);
+   if (!res) return EINA_FALSE;
+
+   for (; i < res->count_crtcs; i++)
+     {
+        /* try to get this crtc from drm */
+        c = sym_drmModeGetCrtc(dev->fd, res->crtcs[i]);
+
+        /* try to create a crtc */
+        crtc = _ecore_drm2_crtc_create(dev, c, i);
+        if (!crtc) goto err;
+
+        /* NB: Use an explicit thread to fill crtc atomic state */
+        crtc->thread =
+          ecore_thread_feedback_run(_ecore_drm2_crtc_state_thread,
+                                    NULL, //_ecore_drm2_crtc_state_thread_notify,
+                                    _ecore_drm2_crtc_state_thread_end,
+                                    _ecore_drm2_crtc_state_thread_cancel,
+                                    crtc, EINA_TRUE);
+     }
+
+   sym_drmModeFreeResources(res);
+   return EINA_TRUE;
+
+err:
+   _ecore_drm2_crtcs_destroy(dev);
+   sym_drmModeFreeCrtc(c);
+   sym_drmModeFreeResources(res);
+   return EINA_FALSE;
+}
+
+void
+_ecore_drm2_crtcs_destroy(Ecore_Drm2_Device *dev)
+{
+   Ecore_Drm2_Crtc *crtc;
+
+   EINA_LIST_FREE(dev->crtcs, crtc)
+     {
+        if (crtc->thread) ecore_thread_cancel(crtc->thread);
+        if (crtc->dcrtc) sym_drmModeFreeCrtc(crtc->dcrtc);
+        free(crtc->state);
+        free(crtc);
+     }
+}
diff --git a/src/lib/ecore_drm2/ecore_drm2_device.c b/src/lib/ecore_drm2/ecore_drm2_device.c
index ec280cbf7e..fc538f4351 100644
--- a/src/lib/ecore_drm2/ecore_drm2_device.c
+++ b/src/lib/ecore_drm2/ecore_drm2_device.c
@@ -1,23 +1,36 @@
 #include "ecore_drm2_private.h"
 
-/* external variable for using atomic */
-Eina_Bool _ecore_drm2_atomic_use = EINA_FALSE;
+#ifndef DRM_CLIENT_CAP_ASPECT_RATIO
+# define DRM_CLIENT_CAP_ASPECT_RATIO 4
+#endif
+#ifndef DRM_CLIENT_CAP_WRITEBACK_CONNECTORS
+# define DRM_CLIENT_CAP_WRITEBACK_CONNECTORS 5
+#endif
 
 /* local functions */
 static Eina_Bool
-_ecore_drm2_device_atomic_capable_get(int fd)
+_ecore_drm2_device_cb_session_active(void *data, int type EINA_UNUSED, void *event)
 {
-   Eina_Bool ret = EINA_TRUE;
+   Ecore_Drm2_Device *dev;
+   Elput_Event_Session_Active *ev;
 
-   if (sym_drmSetClientCap(fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) < 0)
-     ret = EINA_FALSE;
+   dev = data;
+   ev = event;
+
+   if (ev->active)
+     {
+        /* TODO: wake compositor, compositor damage all, set state_invalid = true */
+        /* NB: Input enable is already done inside elput */
+     }
    else
      {
-        if (sym_drmSetClientCap(fd, DRM_CLIENT_CAP_ATOMIC, 1) < 0)
-          ret = EINA_FALSE;
+        /* TODO: compositor offscreen, output->repaint_needed = false */
+        /* NB: Input disable is already done inside elput */
      }
 
-   return ret;
+   /* TODO: raise ecore_drm2_event_active ?? */
+
+   return ECORE_CALLBACK_RENEW;
 }
 
 static Eina_Bool
@@ -108,6 +121,60 @@ cont:
    return ret;
 }
 
+static Eina_Bool
+_ecore_drm2_device_kms_caps_get(Ecore_Drm2_Device *dev)
+{
+   uint64_t cap;
+   int ret = 0;
+
+   /* get drm presentation clock */
+   ret = sym_drmGetCap(dev->fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
+   if ((ret == 0) && (cap == 1))
+     dev->clock_id = CLOCK_MONOTONIC;
+   else
+     dev->clock_id = CLOCK_REALTIME;
+
+   /* get drm cursor width & height */
+   dev->cursor.width = 64;
+   dev->cursor.height = 64;
+   ret = sym_drmGetCap(dev->fd, DRM_CAP_CURSOR_WIDTH, &cap);
+   if (ret == 0) dev->cursor.width = cap;
+   ret = sym_drmGetCap(dev->fd, DRM_CAP_CURSOR_HEIGHT, &cap);
+   if (ret == 0) dev->cursor.height = cap;
+
+   /* try to enable universal planes ... without This, not even Atomic works */
+   ret = sym_drmSetClientCap(dev->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
+   if (ret)
+     {
+        ERR("Drm card does not support universal planes");
+        return EINA_FALSE;
+     }
+
+   /* test if crtc_in_vblank_event is supported */
+   /* NB: our callbacks do not check for this yet, but it's new.
+    * Very useful tho. tells us when crtc is vblank */
+   /* NB: This is NOT necessarily needed for ATOMIC support */
+   ret = sym_drmGetCap(dev->fd, DRM_CAP_CRTC_IN_VBLANK_EVENT, &cap);
+   if (ret != 0) cap = 0;
+
+   /* try to enable atomic modesetting support */
+   ret = sym_drmSetClientCap(dev->fd, DRM_CLIENT_CAP_ATOMIC, 1);
+   dev->atomic = ((ret == 0) && (cap == 1));
+
+   /* test if gbm can do modifiers */
+   /* ret = sym_drmGetCap(dev->fd, DRM_CAP_ADDFB2_MODIFIERS, &cap); */
+   /* if (ret == 0) dev->gbm_mods = cap; */
+
+   /* set writeback connector support */
+   sym_drmSetClientCap(dev->fd, DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
+
+   /* test to see if aspect ratio is supported */
+   ret = sym_drmSetClientCap(dev->fd, DRM_CLIENT_CAP_ASPECT_RATIO, 1);
+   dev->aspect_ratio = (ret == 0);
+
+   return EINA_TRUE;
+}
+
 /* API functions */
 EAPI Ecore_Drm2_Device *
 ecore_drm2_device_open(const char *seat, unsigned int tty)
@@ -152,39 +219,81 @@ ecore_drm2_device_open(const char *seat, unsigned int tty)
         goto input_err;
      }
 
-   /* test if this device can do Atomic Modesetting */
-   _ecore_drm2_atomic_use = _ecore_drm2_device_atomic_capable_get(dev->fd);
-   if (!_ecore_drm2_atomic_use)
+   /* try to get the kms capabilities of this device */
+   if (!_ecore_drm2_device_kms_caps_get(dev))
      {
-        WRN("Could not enable Atomic Modesetting support");
-        goto atomic_err;
+        ERR("Could not get kms capabilities for device");
+        goto caps_err;
      }
 
-   /* try to allocate space for Atomic State */
-   dev->atomic_state = calloc(1, sizeof(Ecore_Drm2_Atomic_State));
-   if (!dev->atomic_state)
+   /* try to create crtcs */
+   if (!_ecore_drm2_crtcs_create(dev))
      {
-        ERR("Failed to allocate device atomic state");
-        goto atomic_err;
+        ERR("Could not create crtcs");
+        goto caps_err;
      }
 
-   /* try to fill atomic state */
-   if (!_ecore_drm2_atomic_state_fill(dev->atomic_state, dev->fd))
+   /* try to create planes */
+   if (!_ecore_drm2_planes_create(dev))
      {
-        ERR("Failed to fill Atomic State");
-        goto atomic_fill_err;
+        ERR("Could not create planes");
+        goto plane_err;
      }
 
-   /* TODO: event handlers for session_active & device_change */
+   /* try to create connectors */
+   if (!_ecore_drm2_connectors_create(dev))
+     {
+        ERR("Could not create connectors");
+        goto conn_err;
+     }
+
+   /* try to create displays */
+   if (!_ecore_drm2_displays_create(dev))
+     {
+        ERR("Could not create displays");
+        goto disp_err;
+     }
+
+   /* TODO: check dmabuf import capable ?
+    *
+    * NB: This will require EGL extension: EGL_EXT_image_dma_buf_import
+    * so will likely need to be done in the compositor
+    */
+
+   /* TODO: check explicit sync support
+    *
+    * NB: requires native_fence_sync & wait_sync
+    * NB: native_fence_sync requires EGL_KHR_fence_sync
+    * NB: wait_sync requires EGL_KHR_wait_sync
+    *
+    * NB: These need to be done in the compositor
+    */
+
+   /* TODO: enable content protection if atomic ?
+    *
+    * NB: This should be done in the compositor
+    */
+
+   dev->session_hdlr =
+     ecore_event_handler_add(ELPUT_EVENT_SESSION_ACTIVE,
+                             _ecore_drm2_device_cb_session_active, dev);
+
+   /* TODO: event handler for device_change */
 
    /* cleanup path variable */
    eina_stringshare_del(path);
 
    return dev;
 
-atomic_fill_err:
-   free(dev->atomic_state);
-atomic_err:
+/* atomic_fill_err: */
+/*    free(dev->atomic_state); */
+disp_err:
+   _ecore_drm2_connectors_destroy(dev);
+plane_err:
+   _ecore_drm2_crtcs_destroy(dev);
+conn_err:
+   _ecore_drm2_planes_destroy(dev);
+caps_err:
    elput_input_shutdown(dev->em);
 input_err:
    elput_manager_close(dev->em, dev->fd);
@@ -202,7 +311,14 @@ ecore_drm2_device_close(Ecore_Drm2_Device *dev)
 {
    EINA_SAFETY_ON_NULL_RETURN(dev);
 
-   _ecore_drm2_atomic_state_free(dev->atomic_state);
+   /* _ecore_drm2_atomic_state_free(dev->atomic_state); */
+
+   _ecore_drm2_displays_destroy(dev);
+   _ecore_drm2_connectors_destroy(dev);
+   _ecore_drm2_planes_destroy(dev);
+   _ecore_drm2_crtcs_destroy(dev);
+
+   ecore_event_handler_del(dev->session_hdlr);
 
    elput_input_shutdown(dev->em);
    elput_manager_close(dev->em, dev->fd);
@@ -214,24 +330,10 @@ ecore_drm2_device_close(Ecore_Drm2_Device *dev)
 EAPI void
 ecore_drm2_device_cursor_size_get(Ecore_Drm2_Device *dev, int *width, int *height)
 {
-   uint64_t caps;
-   int ret = -1;
-
    EINA_SAFETY_ON_NULL_RETURN(dev);
 
-   if (width)
-     {
-        *width = 64;
-        ret = sym_drmGetCap(dev->fd, DRM_CAP_CURSOR_WIDTH, &caps);
-        if (ret == 0) *width = caps;
-     }
-
-   if (height)
-     {
-        *height = 64;
-        ret = sym_drmGetCap(dev->fd, DRM_CAP_CURSOR_HEIGHT, &caps);
-        if (ret == 0) *height = caps;
-     }
+   if (width) *width = dev->cursor.width;
+   if (height) *height = dev->cursor.height;
 }
 
 EAPI void
diff --git a/src/lib/ecore_drm2/ecore_drm2_displays.c b/src/lib/ecore_drm2/ecore_drm2_displays.c
new file mode 100644
index 0000000000..2086c805bc
--- /dev/null
+++ b/src/lib/ecore_drm2/ecore_drm2_displays.c
@@ -0,0 +1,317 @@
+#include "ecore_drm2_private.h"
+
+#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
+#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
+#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
+#define EDID_OFFSET_DATA_BLOCKS 0x36
+#define EDID_OFFSET_LAST_BLOCK 0x6c
+#define EDID_OFFSET_PNPID 0x08
+#define EDID_OFFSET_SERIAL 0x0c
+
+static const char *conn_types[] =
+{
+   "None", "VGA", "DVI-I", "DVI-D", "DVI-A",
+   "Composite", "S-Video", "LVDS", "Component", "DIN",
+   "DisplayPort", "HDMI-A", "HDMI-B", "TV", "eDP", "Virtual", "DSI",
+};
+
+static char *
+_ecore_drm2_display_name_get(Ecore_Drm2_Connector *conn)
+{
+   char name[DRM_CONNECTOR_NAME_LEN];
+   const char *type = NULL;
+
+   if (conn->type < EINA_C_ARRAY_LENGTH(conn_types))
+     type = conn_types[conn->type];
+   else
+     type = "UNKNOWN";
+
+   snprintf(name, sizeof(name), "%s-%d", type, conn->conn->connector_type_id);
+   return strdup(name);
+}
+
+static void
+_ecore_drm2_display_edid_parse_string(const uint8_t *data, char text[])
+{
+   int i = 0, rep = 0;
+
+   strncpy(text, (const char *)data, 12);
+
+   for (; text[i] != '\0'; i++)
+     {
+        if ((text[i] == '\n') || (text[i] == '\r'))
+          {
+             text[i] = '\0';
+             break;
+          }
+     }
+
+   for (i = 0; text[i] != '\0'; i++)
+     {
+        if (!isprint(text[i]))
+          {
+             text[i] = '-';
+             rep++;
+          }
+     }
+
+   if (rep > 4) text[0] = '\0';
+}
+
+static int
+_ecore_drm2_display_edid_parse(Ecore_Drm2_Display *disp, const uint8_t *data, size_t len)
+{
+   int i = 0;
+   uint32_t serial;
+
+   if (len < 128) return -1;
+   if ((data[0] != 0x00) || (data[1] != 0xff)) return -1;
+
+   disp->edid.pnp[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
+   disp->edid.pnp[1] =
+     'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) +
+     ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
+   disp->edid.pnp[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
+   disp->edid.pnp[3] = '\0';
+
+   serial = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
+   serial += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
+   serial += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
+   serial += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
+   if (serial > 0)
+     sprintf(disp->edid.serial, "%lu", (unsigned long)serial);
+
+   for (i = EDID_OFFSET_DATA_BLOCKS; i <= EDID_OFFSET_LAST_BLOCK; i += 18)
+     {
+        if (data[i] != 0) continue;
+        if (data[i + 2] != 0) continue;
+
+        if (data[i + 3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME)
+          _ecore_drm2_display_edid_parse_string(&data[i + 5], disp->edid.monitor);
+        else if (data[i + 3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER)
+          _ecore_drm2_display_edid_parse_string(&data[i + 5], disp->edid.serial);
+        else if (data[i + 3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING)
+          _ecore_drm2_display_edid_parse_string(&data[i + 5], disp->edid.eisa);
+     }
+
+   return 0;
+}
+
+static void
+_ecore_drm2_display_edid_get(Ecore_Drm2_Display *disp)
+{
+   Ecore_Drm2_Connector_State *cstate;
+   int ret = 0;
+
+   cstate = disp->conn->state;
+
+   ret = _ecore_drm2_display_edid_parse(disp, cstate->edid.data, cstate->edid.len);
+   if (!ret)
+     {
+        if (disp->edid.pnp[0] != '\0')
+          eina_stringshare_replace(&disp->make, disp->edid.pnp);
+        if (disp->edid.monitor[0] != '\0')
+          eina_stringshare_replace(&disp->model, disp->edid.monitor);
+        if (disp->edid.serial[0] != '\0')
+          eina_stringshare_replace(&disp->serial, disp->edid.serial);
+     }
+}
+
+static void
+_ecore_drm2_display_state_debug(Ecore_Drm2_Display *disp)
+{
+   DBG("Display Atomic State Fill Complete");
+
+   DBG("\tName: %s", disp->name);
+   DBG("\tMake: %s", disp->make);
+   DBG("\tModel: %s", disp->model);
+   DBG("\tSerial: %s", disp->serial);
+
+   DBG("\tCrtc: %d", disp->crtc->id);
+   DBG("\tCrtc Pos: %d %d", disp->crtc->dcrtc->x, disp->crtc->dcrtc->y);
+   DBG("\tConnector: %d", disp->conn->id);
+
+   /* DBG("\tCloned: %d", disp->cloned); */
+   DBG("\tPrimary: %d", disp->primary);
+   DBG("\tEnabled: %d", disp->enabled);
+   DBG("\tConnected: %d", disp->connected);
+
+   if (disp->backlight.path)
+     {
+        DBG("\tBacklight");
+        switch (disp->backlight.type)
+          {
+           case ECORE_DRM2_BACKLIGHT_RAW:
+             DBG("\t\tType: Raw");
+             break;
+           case ECORE_DRM2_BACKLIGHT_PLATFORM:
+             DBG("\t\tType: Platform");
+             break;
+           case ECORE_DRM2_BACKLIGHT_FIRMWARE:
+             DBG("\t\tType: Firmware");
+             break;
+          }
+        DBG("\t\tPath: %s", disp->backlight.path);
+     }
+}
+
+static void
+_ecore_drm2_display_state_fill(Ecore_Drm2_Display *disp)
+{
+   char *name = NULL;
+
+   /* get display name */
+   name = _ecore_drm2_display_name_get(disp->conn);
+   disp->name = eina_stringshare_add(name);
+   free(name);
+
+   disp->make = eina_stringshare_add("unknown");
+   disp->model = eina_stringshare_add("unknown");
+   disp->serial = eina_stringshare_add("unknown");
+
+   /* get edid and parse */
+   _ecore_drm2_display_edid_get(disp);
+
+   /* get physical dimensions */
+   disp->pw = disp->conn->conn->mmWidth;
+   disp->ph = disp->conn->conn->mmHeight;
+
+   /* get subpixel */
+   switch (disp->conn->conn->subpixel)
+     {
+      case DRM_MODE_SUBPIXEL_NONE:
+        disp->subpixel = 1;
+        break;
+      case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
+        disp->subpixel = 2;
+        break;
+      case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
+        disp->subpixel = 3;
+        break;
+      case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
+        disp->subpixel = 4;
+        break;
+      case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
+        disp->subpixel = 5;
+        break;
+      case DRM_MODE_SUBPIXEL_UNKNOWN:
+      default:
+          disp->subpixel = 0;
+        break;
+     }
+
+   /* get connected state */
+   disp->connected = (disp->conn->conn->connection == DRM_MODE_CONNECTED);
+}
+
+static void
+_ecore_drm2_display_state_thread(void *data, Ecore_Thread *thread EINA_UNUSED)
+{
+   Ecore_Drm2_Display *disp;
+
+   disp = data;
+   /* TODO: FIXME: Should this check for disp->state ? */
+   if (!disp->name)
+     _ecore_drm2_display_state_fill(disp);
+   else
+     {
+        /* TODO: update atomic state for commit */
+     }
+}
+
+static void
+_ecore_drm2_display_state_thread_end(void *data EINA_UNUSED, Ecore_Thread *thread EINA_UNUSED)
+{
+   Ecore_Drm2_Display *disp;
+
+   disp = data;
+   /* disp->thread = NULL; */
+   _ecore_drm2_display_state_debug(disp);
+}
+
+static void
+_ecore_drm2_display_state_thread_cancel(void *data, Ecore_Thread *thread EINA_UNUSED)
+{
+   Ecore_Drm2_Display *disp;
+
+   disp = data;
+   disp->thread = NULL;
+}
+
+Eina_Bool
+_ecore_drm2_displays_create(Ecore_Drm2_Device *dev)
+{
+   Ecore_Drm2_Display *disp;
+   Ecore_Drm2_Connector *c;
+   Ecore_Drm2_Crtc *crtc;
+   Eina_List *l = NULL, *ll = NULL;
+
+   /* go through list of connectors and create displays */
+   EINA_LIST_FOREACH(dev->conns, l, c)
+     {
+        drmModeEncoder *encoder;
+        drmModeCrtc *dcrtc;
+
+        /* try to get the encoder from drm */
+        encoder = sym_drmModeGetEncoder(dev->fd, c->conn->encoder_id);
+        if (!encoder) continue;
+
+        /* try to get the crtc from drm */
+        dcrtc = sym_drmModeGetCrtc(dev->fd, encoder->crtc_id);
+        if (!dcrtc) goto cont;
+
+        /* try to allocate space for new display */
+        disp = calloc(1, sizeof(Ecore_Drm2_Display));
+        if (!disp)
+          {
+             WRN("Could not allocate space for Display");
+             sym_drmModeFreeCrtc(dcrtc);
+             goto cont;
+          }
+
+        /* try to find crtc matching dcrtc->crtc_id and assign to display */
+        EINA_LIST_FOREACH(dev->crtcs, ll, crtc)
+          {
+             if (crtc->id == dcrtc->crtc_id)
+               {
+                  disp->crtc = crtc;
+                  break;
+               }
+          }
+
+        sym_drmModeFreeCrtc(dcrtc);
+
+        disp->fd = dev->fd;
+        disp->conn = c;
+
+        /* append this display to the list */
+        dev->displays = eina_list_append(dev->displays, disp);
+
+        disp->thread =
+          ecore_thread_feedback_run(_ecore_drm2_display_state_thread,
+                                    NULL, // _ecore_drm2_display_state_thread_notify
+                                    _ecore_drm2_display_state_thread_end,
+                                    _ecore_drm2_display_state_thread_cancel,
+                                    disp, EINA_TRUE);
+
+cont:
+        sym_drmModeFreeEncoder(encoder);
+     }
+
+   return EINA_TRUE;
+}
+
+void
+_ecore_drm2_displays_destroy(Ecore_Drm2_Device *dev)
+{
+   Ecore_Drm2_Display *disp;
+
+   EINA_LIST_FREE(dev->displays, disp)
+     {
+        eina_stringshare_del(disp->serial);
+        eina_stringshare_del(disp->model);
+        eina_stringshare_del(disp->make);
+        eina_stringshare_del(disp->name);
+        free(disp);
+     }
+}
diff --git a/src/lib/ecore_drm2/ecore_drm2_planes.c b/src/lib/ecore_drm2/ecore_drm2_planes.c
new file mode 100644
index 0000000000..d412ba0d7f
--- /dev/null
+++ b/src/lib/ecore_drm2/ecore_drm2_planes.c
@@ -0,0 +1,263 @@
+#include "ecore_drm2_private.h"
+
+static void
+_ecore_drm2_plane_state_debug(Ecore_Drm2_Plane *plane)
+{
+   DBG("Plane Atomic State Fill Complete");
+   DBG("\tPlane: %d", plane->state->obj_id);
+   DBG("\t\tCrtc: %lu", (long)plane->state->cid.value);
+   DBG("\t\tFB: %lu", (long)plane->state->fid.value);
+   switch (plane->state->type.value)
+     {
+      case DRM_PLANE_TYPE_OVERLAY:
+        DBG("\t\tType: Overlay Plane");
+        break;
+      case DRM_PLANE_TYPE_PRIMARY:
+        DBG("\t\tType: Primary Plane");
+        break;
+      case DRM_PLANE_TYPE_CURSOR:
+        DBG("\t\tType: Cursor Plane");
+        break;
+      default:
+        break;
+     }
+}
+
+static void
+_ecore_drm2_plane_state_fill(Ecore_Drm2_Plane *plane)
+{
+   Ecore_Drm2_Plane_State *pstate;
+   drmModeObjectPropertiesPtr oprops;
+   drmModePlanePtr p;
+   unsigned int i = 0;
+
+   plane->state = calloc(1, sizeof(Ecore_Drm2_Plane_State));
+   if (!plane->state)
+     {
+        ERR("Could not allocate space for plane state");
+        return;
+     }
+
+   p = plane->dplane;
+   pstate = plane->state;
+
+   pstate->obj_id = plane->id;
+   pstate->mask = p->possible_crtcs;
+   pstate->num_formats = p->count_formats;
+
+   pstate->formats = calloc(p->count_formats, sizeof(uint32_t));
+   for (; i < p->count_formats; i++)
+     pstate->formats[i] = p->formats[i];
+
+   /* try to fill get drm properties of this plane */
+   oprops =
+     sym_drmModeObjectGetProperties(plane->fd, pstate->obj_id,
+                                    DRM_MODE_OBJECT_PLANE);
+   if (!oprops) return;
+
+   /* fill atomic state */
+   for (i = 0; i < oprops->count_props; i++)
+     {
+        drmModePropertyPtr prop;
+
+        prop = sym_drmModeGetProperty(plane->fd, oprops->props[i]);
+        if (!prop) continue;
+
+        if (!strcmp(prop->name, "CRTC_ID"))
+          {
+             pstate->cid.id = prop->prop_id;
+             pstate->cid.value = oprops->prop_values[i];
+          }
+        else if (!strcmp(prop->name, "FB_ID"))
+          {
+             pstate->fid.id = prop->prop_id;
+             pstate->fid.value = oprops->prop_values[i];
+         }
+        else if (!strcmp(prop->name, "CRTC_X"))
+          {
+             pstate->cx.id = prop->prop_id;
+             pstate->cx.value = oprops->prop_values[i];
+          }
+        else if (!strcmp(prop->name, "CRTC_Y"))
+          {
+             pstate->cy.id = prop->prop_id;
+             pstate->cy.value = oprops->prop_values[i];
+          }
+        else if (!strcmp(prop->name, "CRTC_W"))
+          {
+             pstate->cw.id = prop->prop_id;
+             pstate->cw.value = oprops->prop_values[i];
+          }
+        else if (!strcmp(prop->name, "CRTC_H"))
+          {
+             pstate->ch.id = prop->prop_id;
+             pstate->ch.value = oprops->prop_values[i];
+          }
+        else if (!strcmp(prop->name, "SRC_X"))
+          {
+             pstate->sx.id = prop->prop_id;
+             pstate->sx.value = oprops->prop_values[i];
+          }
+        else if (!strcmp(prop->name, "SRC_Y"))
+          {
+             pstate->sy.id = prop->prop_id;
+             pstate->sy.value = oprops->prop_values[i];
+          }
+        else if (!strcmp(prop->name, "SRC_W"))
+          {
+             pstate->sw.id = prop->prop_id;
+             pstate->sw.value = oprops->prop_values[i];
+          }
+        else if (!strcmp(prop->name, "SRC_H"))
+          {
+             pstate->sh.id = prop->prop_id;
+             pstate->sh.value = oprops->prop_values[i];
+          }
+        else if (!strcmp(prop->name, "type"))
+          {
+             pstate->type.id = prop->prop_id;
+             pstate->type.value = oprops->prop_values[i];
+          }
+        else if (!strcmp(prop->name, "rotation"))
+          {
+             int k = 0;
+
+             pstate->rotation.id = prop->prop_id;
+             pstate->rotation.value = oprops->prop_values[i];
+
+             for (k = 0; k < prop->count_enums; k++)
+               {
+                  int r = -1;
+
+                  /* DBG("\t\t\tRotation: %s", prop->enums[k].name); */
+                  if (!strcmp(prop->enums[k].name, "rotate-0"))
+                    r = ECORE_DRM2_ROTATION_NORMAL;
+                  else if (!strcmp(prop->enums[k].name, "rotate-90"))
+                    r = ECORE_DRM2_ROTATION_90;
+                  else if (!strcmp(prop->enums[k].name, "rotate-180"))
+                    r = ECORE_DRM2_ROTATION_180;
+                  else if (!strcmp(prop->enums[k].name, "rotate-270"))
+                    r = ECORE_DRM2_ROTATION_270;
+                  else if (!strcmp(prop->enums[k].name, "reflect-x"))
+                    r = ECORE_DRM2_ROTATION_REFLECT_X;
+                  else if (!strcmp(prop->enums[k].name, "reflect-y"))
+                    r = ECORE_DRM2_ROTATION_REFLECT_Y;
+
+                  if (r != -1)
+                    {
+                       pstate->supported_rotations |= r;
+                       pstate->rotation_map[ffs(r)] =
+                         1ULL << prop->enums[k].value;
+                    }
+               }
+          }
+
+        sym_drmModeFreeProperty(prop);
+     }
+
+   sym_drmModeFreeObjectProperties(oprops);
+}
+
+static void
+_ecore_drm2_plane_state_thread(void *data, Ecore_Thread *thread EINA_UNUSED)
+{
+   Ecore_Drm2_Plane *plane;
+
+   plane = data;
+   if (!plane->state)
+     _ecore_drm2_plane_state_fill(plane);
+   else
+     {
+        /* TODO: update atomic state for commit */
+     }
+}
+
+static void
+_ecore_drm2_plane_state_thread_end(void *data, Ecore_Thread *thread EINA_UNUSED)
+{
+   Ecore_Drm2_Plane *plane;
+
+   plane = data;
+   _ecore_drm2_plane_state_debug(plane);
+}
+
+static void
+_ecore_drm2_plane_state_thread_cancel(void *data, Ecore_Thread *thread EINA_UNUSED)
+{
+   Ecore_Drm2_Plane *plane;
+
+   plane = data;
+   plane->thread = NULL;
+}
+
+static Ecore_Drm2_Plane *
+_ecore_drm2_plane_create(Ecore_Drm2_Device *dev, drmModePlanePtr p, uint32_t index)
+{
+   Ecore_Drm2_Plane *plane;
+
+   /* try to allocate space for a new plane */
+   plane = calloc(1, sizeof(Ecore_Drm2_Plane));
+   if (!plane)
+     {
+        ERR("Could not allocate space for plane");
+        return EINA_FALSE;
+     }
+
+   plane->fd = dev->fd;
+   plane->id = index;
+   plane->dplane = p;
+
+   /* append this plane to the list */
+   dev->planes = eina_list_append(dev->planes, plane);
+
+   return plane;
+}
+
+Eina_Bool
+_ecore_drm2_planes_create(Ecore_Drm2_Device *dev)
+{
+   Ecore_Drm2_Plane *plane;
+   drmModePlaneResPtr pres;
+   uint32_t i = 0;
+
+   /* try to get plane resources from drm */
+   pres = sym_drmModeGetPlaneResources(dev->fd);
+   if (!pres) return EINA_FALSE;
+
+   for (; i < pres->count_planes; i++)
+     {
+        drmModePlanePtr p;
+
+        /* try to get this plane from drm */
+        p = sym_drmModeGetPlane(dev->fd, pres->planes[i]);
+        if (!p) continue;
+
+        /* try to create a plane */
+        plane = _ecore_drm2_plane_create(dev, p, pres->planes[i]);
+        if (!plane) continue;
+
+        /* NB: Use an explicit thread to fill plane atomic state */
+        plane->thread =
+          ecore_thread_feedback_run(_ecore_drm2_plane_state_thread,
+                                    NULL, // _ecore_drm2_plane_state_thread_notify
+                                    _ecore_drm2_plane_state_thread_end,
+                                    _ecore_drm2_plane_state_thread_cancel,
+                                    plane, EINA_TRUE);
+     }
+
+   sym_drmModeFreePlaneResources(pres);
+   return EINA_TRUE;
+}
+
+void
+_ecore_drm2_planes_destroy(Ecore_Drm2_Device *dev)
+{
+   Ecore_Drm2_Plane *plane;
+
+   EINA_LIST_FREE(dev->planes, plane)
+     {
+        if (plane->dplane) sym_drmModeFreePlane(plane->dplane);
+        free(plane->state);
+        free(plane);
+     }
+}
diff --git a/src/lib/ecore_drm2/meson.build b/src/lib/ecore_drm2/meson.build
index dc672dc4ba..eb775fac60 100644
--- a/src/lib/ecore_drm2/meson.build
+++ b/src/lib/ecore_drm2/meson.build
@@ -7,7 +7,10 @@ ecore_drm2_header_src = [
 ]
 
 ecore_drm2_src = files([
-  'ecore_drm2_atomic.c',
+  'ecore_drm2_planes.c',
+  'ecore_drm2_displays.c',
+  'ecore_drm2_connectors.c',
+  'ecore_drm2_crtcs.c',
   'ecore_drm2_device.c',
   'ecore_drm2.c',
   'ecore_drm2_private.h'

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.

Reply via email to