summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Michael <cp.michael@samsung.com>2016-09-22 14:26:05 -0400
committerChris Michael <cp.michael@samsung.com>2016-09-22 14:26:05 -0400
commita2605240ee88a35156224be6f6dbb2f7b257fbb5 (patch)
treed97d166676a4ae97714339386b87729799b46dcf
parent76bdf4981c7184867c7352a3f887de83fa8097db (diff)
parentde5305e2243f8b2cde7ab04e629422a1c0f8a6c0 (diff)
downloadefl-a2605240ee88a35156224be6f6dbb2f7b257fbb5.tar.gz
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
-rw-r--r--src/lib/ecore_drm2/ecore_drm2_device.c453
-rw-r--r--src/lib/ecore_drm2/ecore_drm2_fb.c185
-rw-r--r--src/lib/ecore_drm2/ecore_drm2_outputs.c191
-rw-r--r--src/lib/ecore_drm2/ecore_drm2_private.h68
4 files changed, 856 insertions, 41 deletions
diff --git a/src/lib/ecore_drm2/ecore_drm2_device.c b/src/lib/ecore_drm2/ecore_drm2_device.c
index 8f2e43cfde..6cd415b481 100644
--- a/src/lib/ecore_drm2/ecore_drm2_device.c
+++ b/src/lib/ecore_drm2/ecore_drm2_device.c
@@ -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);
diff --git a/src/lib/ecore_drm2/ecore_drm2_fb.c b/src/lib/ecore_drm2/ecore_drm2_fb.c
index fc40a8edea..0ba6680476 100644
--- a/src/lib/ecore_drm2/ecore_drm2_fb.c
+++ b/src/lib/ecore_drm2/ecore_drm2_fb.c
@@ -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;
+ }
- return 0;
- }
+ output->pending = fb;
+ output->pending->busy = EINA_TRUE;
- 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;
+ return 0;
}
- else if (ret < 0)
+ else
+#endif
{
- output->next = fb;
- output->next->busy = EINA_TRUE;
+ 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;
+ }
+
+ 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
diff --git a/src/lib/ecore_drm2/ecore_drm2_outputs.c b/src/lib/ecore_drm2/ecore_drm2_outputs.c
index 989114749e..b667546657 100644
--- a/src/lib/ecore_drm2/ecore_drm2_outputs.c
+++ b/src/lib/ecore_drm2/ecore_drm2_outputs.c
@@ -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)
diff --git a/src/lib/ecore_drm2/ecore_drm2_private.h b/src/lib/ecore_drm2/ecore_drm2_private.h
index bce5edec89..04dcd1b459 100644
--- a/src/lib/ecore_drm2/ecore_drm2_private.h
+++ b/src/lib/ecore_drm2/ecore_drm2_private.h
@@ -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;
};