ecore_drm2: Add code to fill atomic state in threads for Crtcs, Connectors,
Displays, and Planes
This commit is contained in:
parent
2958c10c93
commit
5dffb60708
|
@ -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 = eina_memdup(bp->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);
|
||||
}
|
||||
}
|
|
@ -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 = eina_memdup(bp->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);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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'
|
||||
|
|
Loading…
Reference in New Issue