summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Michael <cp.michael@samsung.com>2015-04-07 12:13:32 -0400
committerChris Michael <cp.michael@samsung.com>2015-04-08 14:03:48 -0400
commit135a1b8696eeed517c4eb8320d6c77ba093cd7e5 (patch)
treea4423db59bb2369d4f5322d7b9dc3146c52403d6
parent911f253770fba5d78f10f4c731c6e068e5aaff93 (diff)
downloadefl-135a1b8696eeed517c4eb8320d6c77ba093cd7e5.tar.gz
ecore-drm: Improve drm output creation, mode detection, and cloning support
Summary: This refactors the output creation code to support better mode detection, cloning of hotplugged outputs, and initial support for setting of output gamma (API to follow) @fix Signed-off-by: Chris Michael <cp.michael@samsung.com>
-rw-r--r--src/lib/ecore_drm/ecore_drm_output.c376
-rw-r--r--src/lib/ecore_drm/ecore_drm_private.h8
2 files changed, 184 insertions, 200 deletions
diff --git a/src/lib/ecore_drm/ecore_drm_output.c b/src/lib/ecore_drm/ecore_drm_output.c
index a2517074d3..3f2e77c9eb 100644
--- a/src/lib/ecore_drm/ecore_drm_output.c
+++ b/src/lib/ecore_drm/ecore_drm_output.c
@@ -25,6 +25,39 @@ static const char *conn_types[] =
EAPI int ECORE_DRM_EVENT_OUTPUT = 0;
+static void
+_ecore_drm_output_event_free(void *data EINA_UNUSED, void *event)
+{
+ Ecore_Drm_Event_Output *e = event;
+
+ eina_stringshare_del(e->make);
+ eina_stringshare_del(e->model);
+ free(event);
+}
+
+static void
+_ecore_drm_output_event_send(const Ecore_Drm_Output *output, Eina_Bool plug)
+{
+ Ecore_Drm_Event_Output *e;
+
+ if (!(e = calloc(1, sizeof(Ecore_Drm_Event_Output)))) return;
+ e->plug = plug;
+ e->id = output->crtc_id;
+ e->w = output->current_mode->width;
+ e->h = output->current_mode->height;
+ e->x = output->x;
+ e->y = output->y;
+ e->phys_width = output->phys_width;
+ e->phys_height = output->phys_height;
+ e->refresh = output->current_mode->refresh;
+ e->subpixel_order = output->subpixel;
+ e->make = eina_stringshare_ref(output->make);
+ e->model = eina_stringshare_ref(output->model);
+ e->transform = 0;
+ ecore_event_add(ECORE_DRM_EVENT_OUTPUT, e,
+ _ecore_drm_output_event_free, NULL);
+}
+
static drmModePropertyPtr
_ecore_drm_output_property_get(int fd, drmModeConnectorPtr conn, const char *name)
{
@@ -400,63 +433,65 @@ _ecore_drm_output_backlight_shutdown(Ecore_Drm_Backlight *backlight)
}
static Ecore_Drm_Output *
-_ecore_drm_output_create(Ecore_Drm_Device *dev, drmModeRes *res, drmModeConnector *conn, int x, int y)
+_ecore_drm_output_create(Ecore_Drm_Device *dev, drmModeRes *res, drmModeConnector *conn, int x, int y, Eina_Bool cloned)
{
Ecore_Drm_Output *output;
- Ecore_Drm_Output_Mode *mode;
- const char *conn_name;
- char name[32];
- int i = 0;
+ int i = -1;
+ char name[DRM_CONNECTOR_NAME_LEN];
+ const char *type;
+ drmModeCrtc *crtc;
drmModeEncoder *enc;
drmModeModeInfo crtc_mode;
- drmModeCrtc *crtc;
+ Ecore_Drm_Output_Mode *mode, *current, *preferred, *best;
Eina_List *l;
+ /* try to find a crtc for this connector */
i = _ecore_drm_output_crtc_find(dev, res, conn);
- if (i < 0)
- {
- ERR("Could not find crtc or encoder for connector");
- return NULL;
- }
+ if (i < 0) return NULL;
- /* try to allocate space for output */
- if (!(output = calloc(1, sizeof(Ecore_Drm_Output))))
- {
- ERR("Could not allocate space for output");
- return NULL;
- }
+ /* try to allocate space for new output */
+ if (!(output = calloc(1, sizeof(Ecore_Drm_Output)))) return NULL;
- output->dev = dev;
output->x = x;
output->y = y;
+ output->dev = dev;
+ output->cloned = cloned;
output->phys_width = conn->mmWidth;
output->phys_height = conn->mmHeight;
-
output->subpixel = conn->subpixel;
- output->make = eina_stringshare_add("unknown");
- output->model = eina_stringshare_add("unknown");
+
+ output->make = eina_stringshare_add("UNKNOWN");
+ output->model = eina_stringshare_add("UNKNOWN");
+ output->name = eina_stringshare_add("UNKNOWN");
if (conn->connector_type < ALEN(conn_types))
- conn_name = conn_types[conn->connector_type];
+ type = conn_types[conn->connector_type];
else
- conn_name = "UNKNOWN";
+ type = "UNKNOWN";
- snprintf(name, sizeof(name), "%s-%d", conn_name, conn->connector_type_id);
- output->name = eina_stringshare_add(name);
+ snprintf(name, sizeof(name), "%s-%d", type, conn->connector_type_id);
+ eina_stringshare_replace(&output->name, name);
output->crtc_id = res->crtcs[i];
+ output->pipe = i;
dev->crtc_allocator |= (1 << output->crtc_id);
output->conn_id = conn->connector_id;
dev->conn_allocator |= (1 << output->conn_id);
+
+ /* store original crtc so we can restore VT settings */
output->crtc = drmModeGetCrtc(dev->drm.fd, output->crtc_id);
+
+ /* get if dpms is supported */
output->dpms = _ecore_drm_output_property_get(dev->drm.fd, conn, "DPMS");
- memset(&mode, 0, sizeof(mode));
+ memset(&crtc_mode, 0, sizeof(crtc_mode));
+
+ /* get the encoder currently driving this connector */
if ((enc = drmModeGetEncoder(dev->drm.fd, conn->encoder_id)))
{
crtc = drmModeGetCrtc(dev->drm.fd, enc->crtc_id);
drmModeFreeEncoder(enc);
- if (!crtc) goto mode_err;
+ if (!crtc) goto err;
if (crtc->mode_valid) crtc_mode = crtc->mode;
drmModeFreeCrtc(crtc);
}
@@ -464,66 +499,89 @@ _ecore_drm_output_create(Ecore_Drm_Device *dev, drmModeRes *res, drmModeConnecto
for (i = 0; i < conn->count_modes; i++)
{
if (!(mode = _ecore_drm_output_mode_add(output, &conn->modes[i])))
- {
- ERR("Failed to add mode to output");
- goto mode_err;
- }
+ goto err;
}
EINA_LIST_REVERSE_FOREACH(output->modes, l, mode)
{
if (!memcmp(&crtc_mode, &mode->info, sizeof(crtc_mode)))
- {
- output->current_mode = mode;
- break;
- }
+ current = mode;
+ if (mode->flags & DRM_MODE_TYPE_PREFERRED)
+ preferred = mode;
+ best = mode;
}
- if ((!output->current_mode) && (crtc_mode.clock != 0))
+ if ((!current) && (crtc_mode.clock != 0))
{
- output->current_mode = _ecore_drm_output_mode_add(output, &crtc_mode);
- if (!output->current_mode)
- {
- ERR("Failed to add mode to output");
- goto mode_err;
- }
+ if (!(current = _ecore_drm_output_mode_add(output, &crtc_mode)))
+ goto err;
}
- _ecore_drm_output_edid_find(output, conn);
+ if (current) output->current_mode = current;
+ else if (preferred) output->current_mode = preferred;
+ else if (best) output->current_mode = best;
- dev->use_hw_accel = EINA_FALSE;
- if (!_ecore_drm_output_software_setup(dev, output))
- goto mode_err;
- else
+ if (!output->current_mode) goto err;
+
+ output->current_mode->flags |= DRM_MODE_TYPE_DEFAULT;
+
+ if (drmModeSetCrtc(output->dev->drm.fd, output->crtc_id,
+ output->crtc->buffer_id, 0, 0,
+ &output->conn_id, 1, &output->current_mode->info) < 0)
{
- DBG("Output %s", output->name);
- DBG("\tMake: %s", output->make);
- DBG("\tModel: %s", output->model);
- DBG("\tGeom: %d %d %d %d", output->x, output->y,
- output->current_mode->width, output->current_mode->height);
- DBG("\tConnector: %d", output->conn_id);
- DBG("\tCrtc: %d", output->crtc_id);
- DBG("\tSetup for Software Rendering");
+ ERR("Failed to set Mode %dx%d for Output %s: %m",
+ output->current_mode->width, output->current_mode->height,
+ output->name);
+ goto err;
}
+ /* try to init backlight */
output->backlight =
_ecore_drm_output_backlight_init(output, conn->connector_type);
- _ecore_drm_event_output_send(output, EINA_TRUE);
+ /* parse edid */
+ _ecore_drm_output_edid_find(output, conn);
+
+ /* TODO: implement support for LCMS ? */
+ output->gamma = output->crtc->gamma_size;
+
+ if (!_ecore_drm_output_software_setup(dev, output))
+ goto err;
+
+ dev->outputs = eina_list_append(dev->outputs, output);
+
+ DBG("Created New Output At %d,%d", output->x, output->y);
+ DBG("\tCrtc Pos: %d %d", output->crtc->x, output->crtc->y);
+ DBG("\tCrtc: %d", output->crtc_id);
+ DBG("\tConn: %d", output->conn_id);
+ DBG("\tMake: %s", output->make);
+ DBG("\tModel: %s", output->model);
+ DBG("\tName: %s", output->name);
+ DBG("\tCloned: %d", output->cloned);
+
+ EINA_LIST_FOREACH(output->modes, l, mode)
+ {
+ DBG("\tAdded Mode: %dx%d@%.1f%s%s%s",
+ mode->width, mode->height, (mode->refresh / 1000.0),
+ (mode->flags & DRM_MODE_TYPE_PREFERRED) ? ", preferred" : "",
+ (mode->flags & DRM_MODE_TYPE_DEFAULT) ? ", current" : "",
+ (conn->count_modes == 0) ? ", built-in" : "");
+ }
+
+ _ecore_drm_output_event_send(output, EINA_TRUE);
return output;
-mode_err:
- DBG("Removing Output %s", output->name);
- eina_stringshare_del(output->make);
- eina_stringshare_del(output->model);
- eina_stringshare_del(output->name);
+err:
EINA_LIST_FREE(output->modes, mode)
free(mode);
drmModeFreeProperty(output->dpms);
drmModeFreeCrtc(output->crtc);
dev->crtc_allocator &= ~(1 << output->crtc_id);
dev->conn_allocator &= ~(1 << output->conn_id);
+ eina_stringshare_del(output->name);
+ eina_stringshare_del(output->model);
+ eina_stringshare_del(output->make);
free(output);
return NULL;
}
@@ -541,11 +599,11 @@ _ecore_drm_output_free(Ecore_Drm_Output *output)
_ecore_drm_output_backlight_shutdown(output->backlight);
/* turn off hardware cursor */
- drmModeSetCursor(output->drm_fd, output->crtc_id, 0, 0, 0);
+ drmModeSetCursor(output->dev->drm.fd, output->crtc_id, 0, 0, 0);
/* restore crtc state */
if (output->crtc)
- drmModeSetCrtc(output->drm_fd, output->crtc->crtc_id,
+ drmModeSetCrtc(output->dev->drm.fd, output->crtc->crtc_id,
output->crtc->buffer_id, output->crtc->x, output->crtc->y,
&output->conn_id, 1, &output->crtc->mode);
@@ -616,124 +674,75 @@ finish:
void
_ecore_drm_outputs_update(Ecore_Drm_Device *dev)
{
- Ecore_Drm_Output *new_output;
- drmModeConnector *connector;
drmModeRes *res;
- drmModeCrtc *crtc;
- int x = 0, y = 0, i;
+ drmModeConnector *conn;
+ int i = 0, x = 0, y = 0;
+ Ecore_Drm_Output *output;
uint32_t connected = 0, disconnects = 0;
- Eina_List *l;
- res = drmModeGetResources(dev->drm.fd);
- if (!res)
- {
- ERR("Could not get resources for drm card: %m");
- return;
- }
+ /* try to get drm resources */
+ if (!(res = drmModeGetResources(dev->drm.fd))) return;
- for (i = 0; i < res->count_connectors; i++)
+ /* find any new connects */
+ for (; i < res->count_connectors; i++)
{
- int connector_id = res->connectors[i];
+ int conn_id;
+
+ conn_id = res->connectors[i];
- connector = drmModeGetConnector(dev->drm.fd, connector_id);
- if (connector == NULL)
+ /* try to get the connector */
+ if (!(conn = drmModeGetConnector(dev->drm.fd, conn_id)))
continue;
- if (connector->connection != DRM_MODE_CONNECTED)
- {
- drmModeFreeConnector(connector);
- continue;
- }
+ /* test if connected */
+ if (conn->connection != DRM_MODE_CONNECTED) goto next;
- connected |= (1 << connector_id);
+ connected |= (1 << conn_id);
- if (!(dev->conn_allocator & (1 << connector_id)))
+ if (!(dev->conn_allocator & (1 << conn_id)))
{
- drmModeEncoder *enc;
-
- if (!(new_output = _ecore_drm_output_create(dev, res, connector, x, y)))
+ if (eina_list_count(dev->outputs) > 0)
{
- drmModeFreeConnector(connector);
- _ecore_drm_output_free(new_output);
- continue;
- }
-
- new_output->drm_fd = dev->drm.fd;
-
- if (!(enc = drmModeGetEncoder(dev->drm.fd, connector->encoder_id)))
- {
- drmModeFreeConnector(connector);
- _ecore_drm_output_free(new_output);
- continue;
- }
+ Ecore_Drm_Output *last;
- if (!(crtc = drmModeGetCrtc(dev->drm.fd, enc->crtc_id)))
- {
- drmModeFreeEncoder(enc);
- drmModeFreeConnector(connector);
- _ecore_drm_output_free(new_output);
- continue;
+ if ((last = eina_list_last_data_get(dev->outputs)))
+ x = last->x + last->current_mode->width;
+ else
+ x = 0;
}
-
- x += crtc->width;
-
- drmModeFreeCrtc(crtc);
- drmModeFreeEncoder(enc);
-
- dev->outputs = eina_list_append(dev->outputs, new_output);
+ else
+ x = 0;
+
+ /* try to create a new output */
+ /* NB: hotplugged outputs will be set to cloned by default */
+ if (!(output =
+ _ecore_drm_output_create(dev, res, conn, x, y, EINA_TRUE)))
+ goto next;
}
-
- drmModeFreeConnector(connector);
+next:
+ drmModeFreeConnector(conn);
}
- disconnects = dev->conn_allocator & ~connected;
+ drmModeFreeResources(res);
+
+ /* find any disconnects */
+ disconnects = (dev->conn_allocator & ~connected);
if (disconnects)
{
- EINA_LIST_FOREACH(dev->outputs, l, new_output)
+ Eina_List *l;
+
+ EINA_LIST_FOREACH(dev->outputs, l, output)
{
- if (disconnects & (1 << new_output->conn_id))
+ if (disconnects & (1 << output->conn_id))
{
- disconnects &= ~(1 << new_output->conn_id);
- _ecore_drm_event_output_send(new_output, EINA_FALSE);
- ecore_drm_output_free(new_output);
+ disconnects &= ~(1 << output->conn_id);
+ _ecore_drm_output_event_send(output, EINA_FALSE);
+ ecore_drm_output_free(output);
}
}
}
}
-static void
-_ecore_drm_event_output_free(void *data EINA_UNUSED, void *event)
-{
- Ecore_Drm_Event_Output *e = event;
-
- eina_stringshare_del(e->make);
- eina_stringshare_del(e->model);
- free(event);
-}
-
-void
-_ecore_drm_event_output_send(const Ecore_Drm_Output *output, Eina_Bool plug)
-{
- Ecore_Drm_Event_Output *e;
-
- if (!(e = calloc(1, sizeof(Ecore_Drm_Event_Output)))) return;
- e->plug = plug;
- e->id = output->crtc_id;
- e->w = output->current_mode->width;
- e->h = output->current_mode->height;
- e->x = output->x;
- e->y = output->y;
- e->phys_width = output->phys_width;
- e->phys_height = output->phys_height;
- e->refresh = output->current_mode->refresh;
- e->subpixel_order = output->subpixel;
- e->make = eina_stringshare_ref(output->make);
- e->model = eina_stringshare_ref(output->model);
- e->transform = 0;
- ecore_event_add(ECORE_DRM_EVENT_OUTPUT, e,
- _ecore_drm_event_output_free, NULL);
-}
-
/* public functions */
/**
@@ -762,9 +771,10 @@ ecore_drm_outputs_create(Ecore_Drm_Device *dev)
Ecore_Drm_Output *output = NULL;
drmModeConnector *conn;
drmModeRes *res;
- drmModeCrtc *crtc;
int i = 0, x = 0, y = 0;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(dev, EINA_FALSE);
+
/* DBG("Create outputs for %d", dev->drm.fd); */
/* get the resources */
@@ -796,55 +806,25 @@ ecore_drm_outputs_create(Ecore_Drm_Device *dev)
if (!(conn = drmModeGetConnector(dev->drm.fd, res->connectors[i])))
continue;
- if ((conn->connection == DRM_MODE_CONNECTED) &&
- (conn->count_modes > 0))
- {
- drmModeEncoder *enc;
-
- /* create output for this connector */
- if (!(output = _ecore_drm_output_create(dev, res, conn, x, y)))
- {
- /* free the connector */
- drmModeFreeConnector(conn);
- _ecore_drm_output_free(output);
- continue;
- }
+ if (conn->connection != DRM_MODE_CONNECTED) goto next;
- output->drm_fd = dev->drm.fd;
+ /* create output for this connector */
+ if (!(output =
+ _ecore_drm_output_create(dev, res, conn, x, y, EINA_FALSE)))
+ goto next;
- if (!(enc = drmModeGetEncoder(dev->drm.fd, conn->encoder_id)))
- {
- drmModeFreeConnector(conn);
- _ecore_drm_output_free(output);
- continue;
- }
-
- if (!(crtc = drmModeGetCrtc(dev->drm.fd, enc->crtc_id)))
- {
- drmModeFreeEncoder(enc);
- drmModeFreeConnector(conn);
- _ecore_drm_output_free(output);
- continue;
- }
-
- x += crtc->width;
-
- drmModeFreeCrtc(crtc);
- drmModeFreeEncoder(enc);
-
- dev->outputs = eina_list_append(dev->outputs, output);
- }
+ x += output->current_mode->width;
+next:
/* free the connector */
drmModeFreeConnector(conn);
}
+ /* TODO: Planes */
+
ret = EINA_TRUE;
if (eina_list_count(dev->outputs) < 1)
- {
- ret = EINA_FALSE;
- free(dev->crtcs);
- }
+ ret = EINA_FALSE;
/* free resources */
drmModeFreeResources(res);
@@ -883,7 +863,7 @@ EAPI void
ecore_drm_output_cursor_size_set(Ecore_Drm_Output *output, int handle, int w, int h)
{
if (!output) return;
- drmModeSetCursor(output->drm_fd, output->crtc_id, handle, w, h);
+ drmModeSetCursor(output->dev->drm.fd, output->crtc_id, handle, w, h);
}
EAPI Eina_Bool
@@ -896,7 +876,7 @@ ecore_drm_output_enable(Ecore_Drm_Output *output)
ecore_drm_output_dpms_set(output, DRM_MODE_DPMS_ON);
mode = output->current_mode;
- if (drmModeSetCrtc(output->drm_fd, output->crtc_id, output->current->id,
+ if (drmModeSetCrtc(output->dev->drm.fd, output->crtc_id, output->current->id,
0, 0, &output->conn_id, 1, &mode->info) < 0)
{
ERR("Could not set output crtc: %m");
diff --git a/src/lib/ecore_drm/ecore_drm_private.h b/src/lib/ecore_drm/ecore_drm_private.h
index a0bcf12cf1..beea203b90 100644
--- a/src/lib/ecore_drm/ecore_drm_private.h
+++ b/src/lib/ecore_drm/ecore_drm_private.h
@@ -116,7 +116,6 @@ struct _Ecore_Drm_Output
drmModePropertyPtr dpms;
int x, y, phys_width, phys_height;
- int drm_fd;
Eina_Bool need_repaint : 1;
Eina_Bool repaint_scheduled : 1;
@@ -124,6 +123,7 @@ struct _Ecore_Drm_Output
Eina_Bool pending_flip : 1;
Eina_Bool pending_vblank : 1;
+ int pipe;
const char *make, *model, *name;
unsigned int subpixel;
@@ -141,6 +141,11 @@ struct _Ecore_Drm_Output
Ecore_Drm_Fb *current, *next;
Ecore_Drm_Fb *dumb[NUM_FRAME_BUFFERS];
Ecore_Drm_Backlight *backlight;
+
+ uint16_t gamma;
+
+ Eina_Bool enabled : 1;
+ Eina_Bool cloned : 1;
};
struct _Ecore_Drm_Seat
@@ -242,7 +247,6 @@ struct _Ecore_Drm_Sprite
typedef void (*Ecore_Drm_Open_Cb)(void *data, int fd, Eina_Bool b);
void _ecore_drm_event_activate_send(Eina_Bool active);
-void _ecore_drm_event_output_send(const Ecore_Drm_Output *output, Eina_Bool plug);
Eina_Bool _ecore_drm_launcher_device_open(const char *device, Ecore_Drm_Open_Cb callback, void *data, int flags);
int _ecore_drm_launcher_device_open_no_pending(const char *device, int flags);