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.