diff --git a/src/lib/ecore_drm/Ecore_Drm.h b/src/lib/ecore_drm/Ecore_Drm.h index feb48f8414..481da42f15 100644 --- a/src/lib/ecore_drm/Ecore_Drm.h +++ b/src/lib/ecore_drm/Ecore_Drm.h @@ -29,9 +29,9 @@ # endif // ifdef __GNUC__ # endif // ifdef _MSC_VER -#ifdef __cplusplus +# ifdef __cplusplus extern "C" { -#endif +# endif typedef enum _Ecore_Drm_Evdev_Capabilities { @@ -153,8 +153,14 @@ struct _Ecore_Drm_Event_Output /* opaque structure to represent a drm device */ typedef struct _Ecore_Drm_Device Ecore_Drm_Device; -/* opaque structure to represent a drm output mode */ -typedef struct _Ecore_Drm_Output_Mode Ecore_Drm_Output_Mode; +/* structure to represent a drm output mode */ +typedef struct _Ecore_Drm_Output_Mode +{ + unsigned int flags; + int width, height; + unsigned int refresh; + drmModeModeInfo info; +} Ecore_Drm_Output_Mode; /* opaque structure to represent a drm output */ typedef struct _Ecore_Drm_Output Ecore_Drm_Output; @@ -708,6 +714,19 @@ EAPI Eina_Stringshare *ecore_drm_output_model_get(Ecore_Drm_Output *output); */ EAPI Eina_Stringshare *ecore_drm_output_make_get(Ecore_Drm_Output *output); +/** + * Get the name of Ecore_Drm_Output + * + * This function will give the name of Ecore_Drm_Output + * + * @param output The Ecore_Drm_Output to get name for + * @return The name. Caller should free this return. + * + * @ingroup Ecore_Drm_Output_Group + * @since 1.15 + */ +EAPI char *ecore_drm_output_name_get(Ecore_Drm_Output *output); + /** * Set the dpms level of an Ecore_Drm_Output * @@ -761,11 +780,137 @@ EAPI void ecore_drm_device_pointer_xy_get(Ecore_Drm_Device *dev, int *x, int *y) */ EAPI const Eina_List *ecore_drm_devices_get(void); -#ifdef __cplusplus +/** + * Get the minimum and maximum screen size range + * + * @param dev The Ecore_Drm_Device to get screen size range from + * @param *minw The parameter in which smallest width is stored + * @param *minh The parameter in which smallest height is stored + * @param *maxw The parameter in which largest width is stored + * @param *maxh The parameter in which largest height is stored + * + * @ingroup Ecore_Drm_Device_Group + * @since 1.15 + */ +EAPI void ecore_drm_screen_size_range_get(Ecore_Drm_Device *dev, int *minw, int *minh, int *maxw, int *maxh); + +/** + * Get if a given output is connected + * + * @param output The Ecore_Drm_Output to get the connected status of + * + * @return EINA_TRUE if output is connected, EINA_FALSE otherwise + * + * @ingroup Ecore_Drm_Output_Group + * @since 1.15 + */ +EAPI Eina_Bool ecore_drm_output_connected_get(Ecore_Drm_Output *output); + +/** + * Get the connector type of a given Ecore_Drm_Output + * + * @param output The Ecore_Drm_Output to get the connector type of + * + * @return An unsigned integer representing the type of connector for this output + * + * @ingroup Ecore_Drm_Output_Group + * @since 1.15 + */ +EAPI unsigned int ecore_drm_output_connector_type_get(Ecore_Drm_Output *output); + +/** + * Get if a given output has a backlight + * + * @param output The Ecore_Drm_Output to get the backlight of + * + * @return EINA_TRUE if this output has a backlight, EINA_FALSE otherwise + * + * @ingroup Ecore_Drm_Output_Group + * @since 1.15 + */ +EAPI Eina_Bool ecore_drm_output_backlight_get(Ecore_Drm_Output *output); + +/** + * Get the edid of a given output + * + * @param output The Ecore_Drm_Output to get the backlight of + * + * @return A string representing the edid + * + * @ingroup Ecore_Drm_Output_Group + * @since 1.15 + */ +EAPI char *ecore_drm_output_edid_get(Ecore_Drm_Output *output); + +/** + * Get a list of the modes supported on a given output + * + * @param output The Ecore_Drm_Output to get the modes for + * + * @return An Eina_List of the modes supported for this output + * + * @note The returned list should not be freed + * + * @ingroup Ecore_Drm_Output_Group + * @since 1.15 + */ +EAPI Eina_List *ecore_drm_output_modes_get(Ecore_Drm_Output *output); + +/** + * Get the output which is marked as primary + * + * @param dev The Ecore_Drm_Device to get the primary output from + * + * @return The primary Ecore_Drm_Output or NULL if no primary output is set + * + * @ingroup Ecore_Drm_Output_Group + * @since 1.15 + */ +EAPI Ecore_Drm_Output *ecore_drm_output_primary_get(Ecore_Drm_Device *dev); + +/** + * Set a given output as primary + * + * @param output The Ecore_Drm_Output to set as primary + * + * @ingroup Ecore_Drm_Output_Group + * @since 1.15 + */ +EAPI void ecore_drm_output_primary_set(Ecore_Drm_Output *output); + +/** + * Get the size of the crtc for a given output + * + * @param output The Ecore_Drm_Output to get the crtc size of + * @param *width The parameter in which width is stored + * @param *height The parameter in which height is stored + * + * @ingroup Ecore_Drm_Output_Group + * @since 1.15 + */ +EAPI void ecore_drm_output_crtc_size_get(Ecore_Drm_Output *output, int *width, int *height); + +/** + * Find an Ecore_Drm_Output which has the given name + * + * This function will loop all the existing outputs in Ecore_Drm_Device and + * return an output if one exists that matches the given name. + * + * @param dev The Ecore_Drm_Device to search + * @param name The Ecore_Drm_Output matching this name + * + * @return An Ecore_Drm_Output if one exists at these coordinates or NULL + * + * @ingroup Ecore_Drm_Device_Group + * @since 1.15 + */ +EAPI Ecore_Drm_Output *ecore_drm_device_output_name_find(Ecore_Drm_Device *dev, const char *name); + +# ifdef __cplusplus } -#endif +# endif -#undef EAPI -#define EAPI +# undef EAPI +# define EAPI #endif diff --git a/src/lib/ecore_drm/ecore_drm_device.c b/src/lib/ecore_drm/ecore_drm_device.c index 2646483436..b902c19d34 100644 --- a/src/lib/ecore_drm/ecore_drm_device.c +++ b/src/lib/ecore_drm/ecore_drm_device.c @@ -281,6 +281,10 @@ ecore_drm_device_open(Ecore_Drm_Device *dev) DBG("Opened Device %s : %d", dev->drm.name, dev->drm.fd); + /* set client capabilities to 'universal planes' so drm core will expose + * the full universal plane list (including primary & cursor planes) */ + drmSetClientCap(dev->drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); + if (!drmGetCap(dev->drm.fd, DRM_CAP_TIMESTAMP_MONOTONIC, &caps)) { if (caps == 1) @@ -530,3 +534,30 @@ ecore_drm_device_output_find(Ecore_Drm_Device *dev, int x, int y) return NULL; } + +EAPI void +ecore_drm_screen_size_range_get(Ecore_Drm_Device *dev, int *minw, int *minh, int *maxw, int *maxh) +{ + EINA_SAFETY_ON_NULL_RETURN(dev); + + if (minw) *minw = dev->min_width; + if (minh) *minh = dev->min_height; + if (maxw) *maxw = dev->max_width; + if (maxh) *maxh = dev->max_height; +} + +EAPI Ecore_Drm_Output * +ecore_drm_device_output_name_find(Ecore_Drm_Device *dev, const char *name) +{ + Ecore_Drm_Output *output; + Eina_List *l; + + EINA_SAFETY_ON_NULL_RETURN_VAL(dev, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL); + + EINA_LIST_FOREACH(dev->outputs, l, output) + if ((output->name) && (!strcmp(name, output->name))) + return output; + + return NULL; +} diff --git a/src/lib/ecore_drm/ecore_drm_output.c b/src/lib/ecore_drm/ecore_drm_output.c index b564f10626..25965383c5 100644 --- a/src/lib/ecore_drm/ecore_drm_output.c +++ b/src/lib/ecore_drm/ecore_drm_output.c @@ -160,10 +160,13 @@ _ecore_drm_output_edid_find(Ecore_Drm_Output *output, drmModeConnector *conn) conn->prop_values[i]); } drmModeFreeProperty(prop); + if (blob) break; } if (!blob) return; + output->edid_blob = (char *)eina_memdup(blob->data, blob->length, 1); + ret = _ecore_drm_output_edid_parse(output, blob->data, blob->length); if (!ret) { @@ -419,6 +422,8 @@ _ecore_drm_output_create(Ecore_Drm_Device *dev, drmModeRes *res, drmModeConnecto output->model = eina_stringshare_add("UNKNOWN"); output->name = eina_stringshare_add("UNKNOWN"); + output->connected = (conn->connection == DRM_MODE_CONNECTED); + output->conn_type = conn->connector_type; if (conn->connector_type < ALEN(conn_types)) type = conn_types[conn->connector_type]; else @@ -502,6 +507,13 @@ _ecore_drm_output_create(Ecore_Drm_Device *dev, drmModeRes *res, drmModeConnecto dev->outputs = eina_list_append(dev->outputs, output); + /* NB: 'primary' output property is not supported in HW, so we need to + * implement it via software. As such, the First output which gets + * listed via libdrm will be assigned 'primary' until user changes + * it via config */ + if (eina_list_count(dev->outputs) == 1) + output->primary = EINA_TRUE; + 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); @@ -510,6 +522,7 @@ _ecore_drm_output_create(Ecore_Drm_Device *dev, drmModeRes *res, drmModeConnecto DBG("\tModel: %s", output->model); DBG("\tName: %s", output->name); DBG("\tCloned: %d", output->cloned); + DBG("\tPrimary: %d", output->primary); EINA_LIST_FOREACH(output->modes, l, mode) { @@ -702,6 +715,95 @@ next: } } +static void +_ecore_drm_output_planes_get(Ecore_Drm_Device *dev) +{ + drmModePlaneRes *pres; + unsigned int i = 0, j = 0; + int k = 0; + + pres = drmModeGetPlaneResources(dev->drm.fd); + if (!pres) return; + + for (; i < pres->count_planes; i++) + { + drmModePlane *plane; + drmModeObjectPropertiesPtr props; + int type = -1; + + plane = drmModeGetPlane(dev->drm.fd, pres->planes[i]); + if (!plane) continue; + + props = drmModeObjectGetProperties(dev->drm.fd, plane->plane_id, + DRM_MODE_OBJECT_PLANE); + if (!props) goto free_plane; + + DBG("Plane %u Properties:", plane->plane_id); + + for (j = 0; type == -1 && j < props->count_props; j++) + { + drmModePropertyPtr prop; + + prop = drmModeGetProperty(dev->drm.fd, props->props[j]); + if (!prop) continue; + + if (!strcmp(prop->name, "type")) + type = props->prop_values[j]; + + drmModeFreeProperty(prop); + } + + DBG("\tFormats:"); + for (j = 0; j < plane->count_formats; j++) + DBG("\t\t%4.4s", (char *)&plane->formats[j]); + + for (j = 0; j < props->count_props; j++ ) + { + drmModePropertyPtr prop; + + prop = drmModeGetProperty(dev->drm.fd, props->props[j]); + if (!prop) continue; + + DBG("\tProperty Name: %s", prop->name); + + if (prop->flags & DRM_MODE_PROP_RANGE) + { + DBG("\t\tRange Property"); + for (k = 0; k < prop->count_values; k++) + DBG("\t\t\t%"PRIu64, prop->values[k]); + } + if (prop->flags & DRM_MODE_PROP_ENUM) + { + DBG("\t\tEnum Property"); + for (k = 0; k < prop->count_enums; k++) + DBG("\t\t\t%s=%llu", prop->enums[k].name, + prop->enums[k].value); + } + if (prop->flags & DRM_MODE_PROP_BITMASK) + { + DBG("\t\tBitmask Property"); + for (k = 0; k < prop->count_enums; k++) + DBG("\t\t\t%s=0x%llx", prop->enums[k].name, + (1LL << prop->enums[k].value)); + } + + DBG("\t\tValue: %"PRIu64, props->prop_values[j]); + + drmModeFreeProperty(prop); + } + + DBG("\tCurrent Crtc: %d", plane->crtc_id); + DBG("\tPossible Crtcs: 0x%08x", plane->possible_crtcs); + + drmModeFreeObjectProperties(props); + +free_plane: + drmModeFreePlane(plane); + } + + drmModeFreePlaneResources(pres); +} + /* public functions */ /** @@ -748,13 +850,19 @@ ecore_drm_outputs_create(Ecore_Drm_Device *dev) dev->max_width = res->max_width; dev->max_height = res->max_height; + /* DBG("Dev Size"); */ + /* DBG("\tMin Width: %u", res->min_width); */ + /* DBG("\tMin Height: %u", res->min_height); */ + /* DBG("\tMax Width: %u", res->max_width); */ + /* DBG("\tMax Height: %u", res->max_height); */ + for (i = 0; i < res->count_connectors; i++) { /* get the connector */ if (!(conn = drmModeGetConnector(dev->drm.fd, res->connectors[i]))) continue; - if (conn->connection != DRM_MODE_CONNECTED) goto next; + /* if (conn->connection != DRM_MODE_CONNECTED) goto next; */ /* create output for this connector */ if (!(output = @@ -769,6 +877,7 @@ next: } /* TODO: Planes */ + _ecore_drm_output_planes_get(dev); ret = EINA_TRUE; if (eina_list_count(dev->outputs) < 1) @@ -1091,3 +1200,94 @@ ecore_drm_output_connector_id_get(Ecore_Drm_Output *output) return output->conn_id; } + +EAPI char * +ecore_drm_output_name_get(Ecore_Drm_Output *output) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL); + + return strdup(output->name); +} + +EAPI Eina_Bool +ecore_drm_output_connected_get(Ecore_Drm_Output *output) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE); + + return output->connected; +} + +EAPI unsigned int +ecore_drm_output_connector_type_get(Ecore_Drm_Output *output) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(output, 0); + + return output->conn_type; +} + +EAPI Eina_Bool +ecore_drm_output_backlight_get(Ecore_Drm_Output *output) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE); + return (output->backlight != NULL); +} + +EAPI char * +ecore_drm_output_edid_get(Ecore_Drm_Output *output) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(output->edid_blob, NULL); + + return strdup(output->edid_blob); +} + +EAPI Eina_List * +ecore_drm_output_modes_get(Ecore_Drm_Output *output) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(output->modes, NULL); + + return output->modes; +} + +EAPI Ecore_Drm_Output * +ecore_drm_output_primary_get(Ecore_Drm_Device *dev) +{ + Ecore_Drm_Output *ret; + const Eina_List *l; + + EINA_SAFETY_ON_NULL_RETURN_VAL(dev, NULL); + + EINA_LIST_FOREACH(dev->outputs, l, ret) + if (ret->primary) return ret; + + return NULL; +} + +EAPI void +ecore_drm_output_primary_set(Ecore_Drm_Output *output) +{ + const Eina_List *l; + Ecore_Drm_Output *out; + + EINA_SAFETY_ON_NULL_RETURN(output); + + /* unmark all outputs as primary */ + EINA_LIST_FOREACH(output->dev->outputs, l, out) + out->primary = EINA_FALSE; + + /* mark this output as primary */ + output->primary = EINA_TRUE; +} + +EAPI void +ecore_drm_output_crtc_size_get(Ecore_Drm_Output *output, int *width, int *height) +{ + if (width) *width = 0; + if (height) *height = 0; + + EINA_SAFETY_ON_NULL_RETURN(output); + + if (width) *width = output->crtc->width; + if (height) *height = output->crtc->height; +} diff --git a/src/lib/ecore_drm/ecore_drm_private.h b/src/lib/ecore_drm/ecore_drm_private.h index 75e103a62b..063ac06632 100644 --- a/src/lib/ecore_drm/ecore_drm_private.h +++ b/src/lib/ecore_drm/ecore_drm_private.h @@ -87,14 +87,6 @@ typedef struct _Ecore_Drm_Pageflip_Callback int count; } Ecore_Drm_Pageflip_Callback; -struct _Ecore_Drm_Output_Mode -{ - unsigned int flags; - int width, height; - unsigned int refresh; - drmModeModeInfo info; -}; - typedef enum _Ecore_Drm_Backlight_Type { ECORE_DRM_BACKLIGHT_RAW, @@ -117,6 +109,7 @@ struct _Ecore_Drm_Output Ecore_Drm_Device *dev; unsigned int crtc_id; unsigned int conn_id; + unsigned int conn_type; drmModeCrtcPtr crtc; drmModePropertyPtr dpms; @@ -130,6 +123,8 @@ struct _Ecore_Drm_Output Ecore_Drm_Output_Mode *current_mode; Eina_List *modes; + char *edid_blob; + struct { char eisa[13]; @@ -140,6 +135,8 @@ struct _Ecore_Drm_Output Ecore_Drm_Backlight *backlight; + Eina_Bool primary : 1; + Eina_Bool connected : 1; Eina_Bool enabled : 1; Eina_Bool cloned : 1; Eina_Bool need_repaint : 1;