Merge branch 'devs/devilhorns/atomic'

This merge adds initial support for Atomic Modesetting and Nuclear
Pageflipping. These features require a new kernel (>= 4.8) and have
only been testing on Intel i915 drivers. There are runtime checks in
the code to only enable these features when supported so this should
not break anything for "normal users". For those lucky enough to be
able to use these features, please enjoy the buttery smoothness ;)

@feature
This commit is contained in:
Chris Michael 2016-09-22 14:26:05 -04:00
commit a2605240ee
4 changed files with 856 additions and 41 deletions

View File

@ -8,6 +8,12 @@
# define DRM_CAP_CURSOR_HEIGHT 0x9
#endif
#ifdef HAVE_ATOMIC_DRM
# include <sys/utsname.h>
#endif
Eina_Bool _ecore_drm2_use_atomic = EINA_FALSE;
static Eina_Bool
_cb_session_active(void *data, int type EINA_UNUSED, void *event)
{
@ -143,6 +149,418 @@ out:
return ret;
}
#ifdef HAVE_ATOMIC_DRM
static Eina_Bool
_drm2_atomic_usable(int fd)
{
drmVersion *drmver;
Eina_Bool ret = EINA_FALSE;
drmver = drmGetVersion(fd);
if (!drmver) return EINA_FALSE;
/* detect driver */
if ((!strcmp(drmver->name, "i915")) &&
(!strcmp(drmver->desc, "Intel Graphics")))
{
FILE *fp;
/* detect kernel version
* NB: In order for atomic modesetting to work properly for Intel,
* we need to be using a kernel >= 4.8.0 */
fp = fopen("/proc/sys/kernel/osrelease", "rb");
if (fp)
{
char buff[512];
int maj = 0, min = 0;
if (fgets(buff, sizeof(buff), fp))
{
if (sscanf(buff, "%i.%i.%*s", &maj, &min) == 2)
{
if ((maj >= 4) && (min >= 8))
ret = EINA_TRUE;
}
}
fclose(fp);
}
}
drmFreeVersion(drmver);
return ret;
}
static void
_drm2_atomic_state_crtc_fill(Ecore_Drm2_Crtc_State *cstate, int fd)
{
drmModeObjectPropertiesPtr oprops;
unsigned int i = 0;
DBG("Atomic State Crtc Fill");
oprops =
drmModeObjectGetProperties(fd, cstate->obj_id, DRM_MODE_OBJECT_CRTC);
if (!oprops) return;
DBG("\tCrtc %d", cstate->obj_id);
for (i = 0; i < oprops->count_props; i++)
{
drmModePropertyPtr prop;
prop = drmModeGetProperty(fd, oprops->props[i]);
if (!prop) continue;
DBG("\t\tProperty: %s %d", prop->name, i);
if (!strcmp(prop->name, "MODE_ID"))
{
drmModePropertyBlobPtr bp;
cstate->mode.id = prop->prop_id;
cstate->mode.value = oprops->prop_values[i];
DBG("\t\t\tValue: %d", cstate->mode.value);
if (!cstate->mode.value)
{
cstate->mode.len = 0;
goto cont;
}
bp = drmModeGetPropertyBlob(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)
drmModeCreatePropertyBlob(fd, bp->data, bp->length,
&cstate->mode.value);
drmModeFreePropertyBlob(bp);
}
else if (!strcmp(prop->name, "ACTIVE"))
{
cstate->active.id = prop->prop_id;
cstate->active.value = oprops->prop_values[i];
DBG("\t\t\tValue: %d", cstate->active.value);
}
cont:
drmModeFreeProperty(prop);
}
drmModeFreeObjectProperties(oprops);
}
static void
_drm2_atomic_state_conn_fill(Ecore_Drm2_Connector_State *cstate, int fd)
{
drmModeObjectPropertiesPtr oprops;
unsigned int i = 0;
DBG("Atomic State Connector Fill");
oprops =
drmModeObjectGetProperties(fd, cstate->obj_id, DRM_MODE_OBJECT_CONNECTOR);
if (!oprops) return;
DBG("\tConnector: %d", cstate->obj_id);
for (i = 0; i < oprops->count_props; i++)
{
drmModePropertyPtr prop;
prop = drmModeGetProperty(fd, oprops->props[i]);
if (!prop) continue;
DBG("\t\tProperty: %s", prop->name);
if (!strcmp(prop->name, "CRTC_ID"))
{
cstate->crtc.id = prop->prop_id;
cstate->crtc.value = oprops->prop_values[i];
DBG("\t\t\tValue: %d", cstate->crtc.value);
}
else if (!strcmp(prop->name, "DPMS"))
{
cstate->dpms.id = prop->prop_id;
cstate->dpms.value = oprops->prop_values[i];
DBG("\t\t\tValue: %d", cstate->dpms.value);
}
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 = drmModeGetPropertyBlob(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)
drmModeCreatePropertyBlob(fd, bp->data, bp->length,
&cstate->edid.id);
drmModeFreePropertyBlob(bp);
}
else if (!strcmp(prop->name, "aspect ratio"))
{
cstate->aspect.id = prop->prop_id;
cstate->aspect.value = oprops->prop_values[i];
DBG("\t\t\tValue: %d", cstate->aspect.value);
}
else if (!strcmp(prop->name, "scaling mode"))
{
cstate->scaling.id = prop->prop_id;
cstate->scaling.value = oprops->prop_values[i];
DBG("\t\t\tValue: %d", cstate->scaling.value);
}
cont:
drmModeFreeProperty(prop);
}
drmModeFreeObjectProperties(oprops);
}
static void
_drm2_atomic_state_plane_fill(Ecore_Drm2_Plane_State *pstate, int fd)
{
drmModeObjectPropertiesPtr oprops;
unsigned int i = 0;
int k = 0;
DBG("Atomic State Plane Fill");
oprops =
drmModeObjectGetProperties(fd, pstate->obj_id, DRM_MODE_OBJECT_PLANE);
if (!oprops) return;
DBG("\tPlane: %d", pstate->obj_id);
for (i = 0; i < oprops->count_props; i++)
{
drmModePropertyPtr prop;
prop = drmModeGetProperty(fd, oprops->props[i]);
if (!prop) continue;
DBG("\t\tProperty: %s", prop->name);
if (!strcmp(prop->name, "CRTC_ID"))
{
pstate->cid.id = prop->prop_id;
pstate->cid.value = oprops->prop_values[i];
DBG("\t\t\tValue: %d", pstate->cid.value);
}
else if (!strcmp(prop->name, "FB_ID"))
{
pstate->fid.id = prop->prop_id;
pstate->fid.value = oprops->prop_values[i];
DBG("\t\t\tValue: %d", pstate->fid.value);
}
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];
switch (pstate->type.value)
{
case DRM_PLANE_TYPE_OVERLAY:
DBG("\t\t\tOverlay Plane");
break;
case DRM_PLANE_TYPE_PRIMARY:
DBG("\t\t\tPrimary Plane");
break;
case DRM_PLANE_TYPE_CURSOR:
DBG("\t\t\tCursor Plane");
break;
default:
DBG("\t\t\tValue: %d", pstate->type.value);
break;
}
}
else if (!strcmp(prop->name, "rotation"))
{
pstate->rotation.id = prop->prop_id;
pstate->rotation.value = oprops->prop_values[i];
for (k = 0; k < prop->count_enums; k++)
{
int r = -1;
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)] =
1 << prop->enums[k].value;
}
}
}
drmModeFreeProperty(prop);
}
drmModeFreeObjectProperties(oprops);
}
static void
_drm2_atomic_state_fill(Ecore_Drm2_Atomic_State *state, int fd)
{
int i = 0;
drmModeResPtr res;
drmModePlaneResPtr pres;
res = drmModeGetResources(fd);
if (!res) return;
pres = drmModeGetPlaneResources(fd);
if (!pres) goto err;
state->crtcs = res->count_crtcs;
state->crtc_states = calloc(state->crtcs, sizeof(Ecore_Drm2_Crtc_State));
if (state->crtc_states)
{
for (i = 0; i < state->crtcs; i++)
{
Ecore_Drm2_Crtc_State *cstate;
cstate = &state->crtc_states[i];
cstate->obj_id = res->crtcs[i];
cstate->index = i;
_drm2_atomic_state_crtc_fill(cstate, fd);
}
}
state->conns = res->count_connectors;
state->conn_states =
calloc(state->conns, sizeof(Ecore_Drm2_Connector_State));
if (state->conn_states)
{
for (i = 0; i < state->conns; i++)
{
Ecore_Drm2_Connector_State *cstate;
cstate = &state->conn_states[i];
cstate->obj_id = res->connectors[i];
_drm2_atomic_state_conn_fill(cstate, fd);
}
}
state->planes = pres->count_planes;
state->plane_states = calloc(state->planes, sizeof(Ecore_Drm2_Plane_State));
if (state->plane_states)
{
for (i = 0; i < state->planes; i++)
{
drmModePlanePtr plane;
Ecore_Drm2_Plane_State *pstate;
plane = drmModeGetPlane(fd, pres->planes[i]);
if (!plane) continue;
pstate = &state->plane_states[i];
pstate->obj_id = pres->planes[i];
pstate->mask = plane->possible_crtcs;
drmModeFreePlane(plane);
_drm2_atomic_state_plane_fill(pstate, fd);
}
}
drmModeFreePlaneResources(pres);
err:
drmModeFreeResources(res);
}
static void
_drm2_atomic_state_free(Ecore_Drm2_Atomic_State *state)
{
free(state->plane_states);
free(state->conn_states);
free(state->crtc_states);
free(state);
}
#endif
EAPI Ecore_Drm2_Device *
ecore_drm2_device_find(const char *seat, unsigned int tty)
{
@ -191,6 +609,32 @@ ecore_drm2_device_open(Ecore_Drm2_Device *device)
DBG("Device Path: %s", device->path);
DBG("Device Fd: %d", device->fd);
#ifdef HAVE_ATOMIC_DRM
/* check that this system can do atomic */
_ecore_drm2_use_atomic = _drm2_atomic_usable(device->fd);
if (_ecore_drm2_use_atomic)
{
if (drmSetClientCap(device->fd, DRM_CLIENT_CAP_ATOMIC, 1) < 0)
{
WRN("Could not enable Atomic Modesetting support");
_ecore_drm2_use_atomic = EINA_FALSE;
}
else
{
if (drmSetClientCap(device->fd,
DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) < 0)
WRN("Could not enable Universal Plane support");
else
{
/* atomic & planes are usable */
device->state = calloc(1, sizeof(Ecore_Drm2_Atomic_State));
if (device->state)
_drm2_atomic_state_fill(device->state, device->fd);
}
}
}
#endif
device->active_hdlr =
ecore_event_handler_add(ELPUT_EVENT_SESSION_ACTIVE,
_cb_session_active, device);
@ -199,10 +643,6 @@ ecore_drm2_device_open(Ecore_Drm2_Device *device)
ecore_event_handler_add(ELPUT_EVENT_DEVICE_CHANGE,
_cb_device_change, device);
/* NB: Not going to enable planes if we don't support atomic */
/* if (drmSetClientCap(device->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) < 0) */
/* ERR("Could not set Universal Plane support: %m"); */
return device->fd;
input_err:
@ -226,6 +666,11 @@ ecore_drm2_device_free(Ecore_Drm2_Device *device)
{
EINA_SAFETY_ON_NULL_RETURN(device);
#ifdef HAVE_ATOMIC_DRM
if (_ecore_drm2_use_atomic)
_drm2_atomic_state_free(device->state);
#endif
ecore_event_handler_del(device->active_hdlr);
ecore_event_handler_del(device->device_change_hdlr);
eina_stringshare_del(device->path);

View File

@ -31,6 +31,83 @@ _fb2_create(Ecore_Drm2_Fb *fb)
return EINA_TRUE;
}
#ifdef HAVE_ATOMIC_DRM
static int
_fb_atomic_flip(Ecore_Drm2_Output *output, Ecore_Drm2_Plane_State *pstate, uint32_t flags)
{
int ret = 0;
drmModeAtomicReq *req = NULL;
req = drmModeAtomicAlloc();
if (!req) return -1;
drmModeAtomicSetCursor(req, 0);
if (flags & DRM_MODE_ATOMIC_ALLOW_MODESET)
{
Ecore_Drm2_Crtc_State *cstate;
cstate = output->crtc_state;
ret = drmModeAtomicAddProperty(req, cstate->obj_id, cstate->mode.id,
cstate->mode.value);
if (ret < 0) goto err;
ret = drmModeAtomicAddProperty(req, cstate->obj_id, cstate->active.id,
cstate->active.value);
if (ret < 0) goto err;
}
ret = drmModeAtomicAddProperty(req, pstate->obj_id,
pstate->cid.id, pstate->cid.value);
if (ret < 0) goto err;
ret = drmModeAtomicAddProperty(req, pstate->obj_id,
pstate->fid.id, pstate->fid.value);
if (ret < 0) goto err;
ret = drmModeAtomicAddProperty(req, pstate->obj_id,
pstate->sx.id, pstate->sx.value);
if (ret < 0) goto err;
ret = drmModeAtomicAddProperty(req, pstate->obj_id,
pstate->sy.id, pstate->sy.value);
if (ret < 0) goto err;
ret = drmModeAtomicAddProperty(req, pstate->obj_id,
pstate->sw.id, pstate->sw.value);
if (ret < 0) goto err;
ret = drmModeAtomicAddProperty(req, pstate->obj_id,
pstate->sh.id, pstate->sh.value);
if (ret < 0) goto err;
ret = drmModeAtomicAddProperty(req, pstate->obj_id,
pstate->cx.id, pstate->cx.value);
if (ret < 0) goto err;
ret = drmModeAtomicAddProperty(req, pstate->obj_id,
pstate->cy.id, pstate->cy.value);
if (ret < 0) goto err;
ret = drmModeAtomicAddProperty(req, pstate->obj_id,
pstate->cw.id, pstate->cw.value);
if (ret < 0) goto err;
ret = drmModeAtomicAddProperty(req, pstate->obj_id,
pstate->ch.id, pstate->ch.value);
if (ret < 0) goto err;
ret = drmModeAtomicCommit(output->fd, req, flags, output->user_data);
if (ret < 0) ERR("Failed to commit Atomic FB Flip: %m");
else ret = 0;
err:
drmModeAtomicFree(req);
return ret;
}
#endif
EAPI Ecore_Drm2_Fb *
ecore_drm2_fb_create(int fd, int width, int height, int depth, int bpp, unsigned int format)
{
@ -275,48 +352,94 @@ ecore_drm2_fb_flip(Ecore_Drm2_Fb *fb, Ecore_Drm2_Output *output)
/* If we don't have an fb to set by now, BAIL! */
if (!fb) return -1;
if ((!output->current) ||
(output->current->stride != fb->stride))
#ifdef HAVE_ATOMIC_DRM
if (_ecore_drm2_use_atomic)
{
ret =
drmModeSetCrtc(fb->fd, output->crtc_id, fb->id,
output->x, output->y, &output->conn_id, 1,
&output->current_mode->info);
if (ret)
Ecore_Drm2_Plane_State *pstate;
uint32_t flags =
DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_PAGE_FLIP_EVENT |
DRM_MODE_ATOMIC_ALLOW_MODSET;
pstate = output->plane_state;
pstate->cid.value = output->crtc_id;
pstate->fid.value = fb->id;
pstate->sx.value = 0;
pstate->sy.value = 0;
pstate->sw.value = fb->w << 16;
pstate->sh.value = fb->h << 16;
pstate->cx.value = output->x;
pstate->cy.value = output->y;
pstate->cw.value = output->current_mode->width;
pstate->ch.value = output->current_mode->height;
ret = _fb_atomic_flip(output, pstate, flags);
if ((ret < 0) && (errno != EBUSY))
{
ERR("Failed to set Mode %dx%d for Output %s: %m",
output->current_mode->width, output->current_mode->height,
output->name);
ERR("Atomic Pageflip Failed for Crtc %u on Connector %u: %m",
output->crtc_id, output->conn_id);
return ret;
}
else if (ret < 0)
{
output->next = fb;
if (output->next) output->next->busy = EINA_TRUE;
if (output->current) _release_buffer(output, output->current);
output->current = fb;
output->current->busy = EINA_TRUE;
output->next = NULL;
return 0;
}
output->pending = fb;
output->pending->busy = EINA_TRUE;
return 0;
}
else
#endif
{
if ((!output->current) ||
(output->current->stride != fb->stride))
{
ret =
drmModeSetCrtc(fb->fd, output->crtc_id, fb->id,
output->x, output->y, &output->conn_id, 1,
&output->current_mode->info);
if (ret)
{
ERR("Failed to set Mode %dx%d for Output %s: %m",
output->current_mode->width, output->current_mode->height,
output->name);
return ret;
}
ret =
drmModePageFlip(fb->fd, output->crtc_id, fb->id,
DRM_MODE_PAGE_FLIP_EVENT, output->user_data);
if ((ret < 0) && (errno != EBUSY))
{
DBG("Pageflip Failed for Crtc %u on Connector %u: %m",
output->crtc_id, output->conn_id);
return ret;
}
else if (ret < 0)
{
output->next = fb;
output->next->busy = EINA_TRUE;
if (output->current) _release_buffer(output, output->current);
output->current = fb;
output->current->busy = EINA_TRUE;
output->next = NULL;
return 0;
}
ret =
drmModePageFlip(fb->fd, output->crtc_id, fb->id,
DRM_MODE_PAGE_FLIP_EVENT, output->user_data);
if ((ret < 0) && (errno != EBUSY))
{
DBG("Pageflip Failed for Crtc %u on Connector %u: %m",
output->crtc_id, output->conn_id);
return ret;
}
else if (ret < 0)
{
output->next = fb;
output->next->busy = EINA_TRUE;
return 0;
}
output->pending = fb;
output->pending->busy = EINA_TRUE;
return 0;
}
output->pending = fb;
output->pending->busy = EINA_TRUE;
return 0;
}
EAPI Eina_Bool

View File

@ -189,6 +189,28 @@ _output_edid_parse(Ecore_Drm2_Output *output, const uint8_t *data, size_t len)
return 0;
}
#ifdef HAVE_ATOMIC_DRM
static void
_output_edid_atomic_find(Ecore_Drm2_Output *output)
{
Ecore_Drm2_Connector_State *cstate;
int ret = 0;
cstate = output->conn_state;
ret = _output_edid_parse(output, cstate->edid.data, cstate->edid.len);
if (!ret)
{
if (output->edid.pnp[0] != '\0')
eina_stringshare_replace(&output->make, output->edid.pnp);
if (output->edid.monitor[0] != '\0')
eina_stringshare_replace(&output->model, output->edid.monitor);
if (output->edid.serial[0] != '\0')
eina_stringshare_replace(&output->serial, output->edid.serial);
}
}
#endif
static void
_output_edid_find(Ecore_Drm2_Output *output, const drmModeConnector *conn)
{
@ -386,6 +408,42 @@ _output_dpms_property_get(int fd, const drmModeConnector *conn)
return NULL;
}
#ifdef HAVE_ATOMIC_DRM
static Eina_Bool
_output_dpms_atomic_set(Ecore_Drm2_Output *output, int level)
{
Ecore_Drm2_Crtc_State *cstate;
drmModeAtomicReq *req = NULL;
Eina_Bool ret = EINA_TRUE;
req = drmModeAtomicAlloc();
if (!req) return EINA_FALSE;
drmModeAtomicSetCursor(req, 0);
cstate = output->crtc_state;
if (drmModeAtomicAddProperty(req, cstate->obj_id,
cstate->active.id, level) < 0)
{
ERR("Failed to add connector property DPMS");
ret = EINA_FALSE;
goto err;
}
if (drmModeAtomicCommit(output->fd, req, 0, NULL))
{
ERR("Could not set dpms property: %m");
ret = EINA_FALSE;
}
err:
drmModeAtomicFree(req);
return ret;
}
#endif
static void
_output_backlight_init(Ecore_Drm2_Output *output, unsigned int conn_type)
{
@ -525,6 +583,98 @@ _output_matrix_update(Ecore_Drm2_Output *output)
eina_matrix4_inverse(&output->inverse, &output->matrix);
}
#ifdef HAVE_ATOMIC_DRM
static Ecore_Drm2_Crtc_State *
_atomic_state_crtc_duplicate(Ecore_Drm2_Crtc_State *state)
{
Ecore_Drm2_Crtc_State *cstate;
cstate = calloc(1, sizeof(Ecore_Drm2_Crtc_State));
if (!cstate) return NULL;
memcpy(cstate, state, sizeof(Ecore_Drm2_Crtc_State));
return cstate;
}
static Ecore_Drm2_Crtc_State *
_output_crtc_state_get(Ecore_Drm2_Atomic_State *state, unsigned int id)
{
Ecore_Drm2_Crtc_State *cstate;
int i = 0;
for (; i < state->crtcs; i++)
{
cstate = &state->crtc_states[i];
if (cstate->obj_id != id) continue;
return _atomic_state_crtc_duplicate(cstate);
}
return NULL;
}
static Ecore_Drm2_Connector_State *
_atomic_state_conn_duplicate(Ecore_Drm2_Connector_State *state)
{
Ecore_Drm2_Connector_State *cstate;
cstate = calloc(1, sizeof(Ecore_Drm2_Connector_State));
if (!cstate) return NULL;
memcpy(cstate, state, sizeof(Ecore_Drm2_Connector_State));
return cstate;
}
static Ecore_Drm2_Connector_State *
_output_conn_state_get(Ecore_Drm2_Atomic_State *state, unsigned int id)
{
Ecore_Drm2_Connector_State *cstate;
int i = 0;
for (; i < state->conns; i++)
{
cstate = &state->conn_states[i];
if (cstate->obj_id != id) continue;
return _atomic_state_conn_duplicate(cstate);
}
return NULL;
}
static Ecore_Drm2_Plane_State *
_atomic_state_plane_duplicate(Ecore_Drm2_Plane_State *state)
{
Ecore_Drm2_Plane_State *pstate;
pstate = calloc(1, sizeof(Ecore_Drm2_Plane_State));
if (!pstate) return NULL;
memcpy(pstate, state, sizeof(Ecore_Drm2_Plane_State));
return pstate;
}
/* NB: For now, this function will only return primary planes.
* We may need to adjust this later to pass in a desired plane type */
static Ecore_Drm2_Plane_State *
_output_plane_state_get(Ecore_Drm2_Atomic_State *state, unsigned int id)
{
Ecore_Drm2_Plane_State *pstate;
int i = 0;
for (; i < state->planes; i++)
{
pstate = &state->plane_states[i];
if (pstate->type.value != DRM_PLANE_TYPE_PRIMARY) continue;
if (pstate->cid.value != id) continue;
return _atomic_state_plane_duplicate(pstate);
}
return NULL;
}
#endif
static Eina_Bool
_output_create(Ecore_Drm2_Device *dev, const drmModeRes *res, const drmModeConnector *conn, int x, int y, int *w, Eina_Bool cloned)
{
@ -588,7 +738,19 @@ _output_create(Ecore_Drm2_Device *dev, const drmModeRes *res, const drmModeConne
output->ocrtc = drmModeGetCrtc(dev->fd, output->crtc_id);
output->dpms = _output_dpms_property_get(dev->fd, conn);
#ifdef HAVE_ATOMIC_DRM
if (_ecore_drm2_use_atomic)
{
output->crtc_state =
_output_crtc_state_get(dev->state, output->crtc_id);
output->conn_state =
_output_conn_state_get(dev->state, output->conn_id);
output->plane_state =
_output_plane_state_get(dev->state, output->crtc_id);
}
else
#endif
output->dpms = _output_dpms_property_get(dev->fd, conn);
_output_backlight_init(output, conn->connector_type);
@ -596,7 +758,12 @@ _output_create(Ecore_Drm2_Device *dev, const drmModeRes *res, const drmModeConne
_output_modes_create(dev, output, conn);
_output_edid_find(output, conn);
#ifdef HAVE_ATOMIC_DRM
if (_ecore_drm2_use_atomic)
_output_edid_atomic_find(output);
else
#endif
_output_edid_find(output, conn);
if (output->connected) output->enabled = EINA_TRUE;
@ -845,8 +1012,13 @@ ecore_drm2_output_dpms_set(Ecore_Drm2_Output *output, int level)
EINA_SAFETY_ON_NULL_RETURN(output);
EINA_SAFETY_ON_TRUE_RETURN(!output->enabled);
drmModeConnectorSetProperty(output->fd, output->conn_id,
output->dpms->prop_id, level);
#ifdef HAVE_ATOMIC_DRM
if (_ecore_drm2_use_atomic)
_output_dpms_atomic_set(output, level);
else
#endif
drmModeConnectorSetProperty(output->fd, output->conn_id,
output->dpms->prop_id, level);
}
EAPI char *
@ -856,9 +1028,16 @@ ecore_drm2_output_edid_get(Ecore_Drm2_Output *output)
unsigned char *blob;
EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(output->edid.blob, NULL);
blob = output->edid.blob;
#ifdef HAVE_ATOMIC_DRM
if (_ecore_drm2_use_atomic)
blob = output->conn_state->edid.data;
else
#endif
{
EINA_SAFETY_ON_NULL_RETURN_VAL(output->edid.blob, NULL);
blob = output->edid.blob;
}
edid_str = malloc((128 * 2) + 1);
if (edid_str)

View File

@ -24,6 +24,7 @@
# include <drm_fourcc.h>
extern int _ecore_drm2_log_dom;
extern Eina_Bool _ecore_drm2_use_atomic;
# ifdef ECORE_DRM2_DEFAULT_LOG_COLOR
# undef ECORE_DRM2_DEFAULT_LOG_COLOR
@ -55,6 +56,63 @@ extern int _ecore_drm2_log_dom;
# endif
# define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_drm2_log_dom, __VA_ARGS__)
# ifdef HAVE_ATOMIC_DRM
typedef struct _Ecore_Drm2_Atomic_State Ecore_Drm2_Atomic_State;
typedef struct _Ecore_Drm2_Atomic_Blob
{
uint32_t id, value;
size_t len;
void *data;
} Ecore_Drm2_Atomic_Blob;
typedef struct _Ecore_Drm2_Atomic_Property
{
uint32_t id, value;
} Ecore_Drm2_Atomic_Property;
typedef struct _Ecore_Drm2_Connector_State
{
uint32_t obj_id;
Ecore_Drm2_Atomic_Property crtc;
Ecore_Drm2_Atomic_Property dpms;
Ecore_Drm2_Atomic_Property aspect;
Ecore_Drm2_Atomic_Property scaling;
Ecore_Drm2_Atomic_Blob edid;
} Ecore_Drm2_Connector_State;
typedef struct _Ecore_Drm2_Crtc_State
{
uint32_t obj_id;
int index;
Ecore_Drm2_Atomic_Property active;
Ecore_Drm2_Atomic_Blob mode;
} Ecore_Drm2_Crtc_State;
typedef struct _Ecore_Drm2_Plane_State
{
uint32_t obj_id, mask;
Ecore_Drm2_Atomic_Property type;
Ecore_Drm2_Atomic_Property cid, fid;
Ecore_Drm2_Atomic_Property sx, sy, sw, sh;
Ecore_Drm2_Atomic_Property cx, cy, cw, ch;
Ecore_Drm2_Atomic_Property rotation;
/* these are not part of an atomic state, but we store these here
* so that we do not have to refetch properties when iterating planes */
uint32_t rotation_map[6];
uint32_t supported_rotations;
} Ecore_Drm2_Plane_State;
struct _Ecore_Drm2_Atomic_State
{
int crtcs, conns, planes;
Ecore_Drm2_Crtc_State *crtc_states;
Ecore_Drm2_Connector_State *conn_states;
Ecore_Drm2_Plane_State *plane_states;
};
# endif
typedef enum _Ecore_Drm2_Backlight_Type
{
ECORE_DRM2_BACKLIGHT_RAW,
@ -157,6 +215,12 @@ struct _Ecore_Drm2_Output
Ecore_Drm2_Release_Handler release_cb;
void *release_data;
# ifdef HAVE_ATOMIC_DRM
Ecore_Drm2_Crtc_State *crtc_state;
Ecore_Drm2_Connector_State *conn_state;
Ecore_Drm2_Plane_State *plane_state;
# endif
Eina_Bool connected : 1;
Eina_Bool primary : 1;
Eina_Bool cloned : 1;
@ -187,6 +251,10 @@ struct _Ecore_Drm2_Device
Ecore_Event_Handler *active_hdlr;
Ecore_Event_Handler *device_change_hdlr;
# ifdef HAVE_ATOMIC_DRM
Ecore_Drm2_Atomic_State *state;
# endif
Eina_List *outputs;
};