[cogl/wip/outputs: 62/71] Adds CoglOutput support to KMS winsys
- From: Robert Bragg <rbragg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [cogl/wip/outputs: 62/71] Adds CoglOutput support to KMS winsys
- Date: Fri, 27 Sep 2013 13:43:23 +0000 (UTC)
commit d3712e30e222346fbe95e1a4d78e36e913c16e7d
Author: Robert Bragg <robert linux intel com>
Date: Thu Apr 18 23:39:17 2013 +0100
Adds CoglOutput support to KMS winsys
cogl/cogl-output-private.h | 17 +++-
cogl/cogl-output.c | 13 ++-
cogl/winsys/cogl-winsys-egl-kms.c | 227 ++++++++++++++++++++++++++++++++++++-
3 files changed, 251 insertions(+), 6 deletions(-)
---
diff --git a/cogl/cogl-output-private.h b/cogl/cogl-output-private.h
index a4910e9..f0e8d57 100644
--- a/cogl/cogl-output-private.h
+++ b/cogl/cogl-output-private.h
@@ -41,10 +41,21 @@ struct _CoglOutput
int mm_height;
float refresh_rate;
CoglSubpixelOrder subpixel_order;
+
+ void *winsys;
+ CoglUserDataDestroyCallback winsys_destroy_callback;
};
-CoglOutput *_cogl_output_new (const char *name);
-CoglBool _cogl_output_values_equal (CoglOutput *output,
- CoglOutput *other);
+CoglOutput *
+_cogl_output_new (const char *name);
+
+void
+_cogl_output_set_winsys_data (CoglOutput *output,
+ void *winsys,
+ CoglUserDataDestroyCallback destroy_callback);
+
+CoglBool
+_cogl_output_values_equal (CoglOutput *output,
+ CoglOutput *other);
#endif /* __COGL_OUTPUT_PRIVATE_H */
diff --git a/cogl/cogl-output.c b/cogl/cogl-output.c
index 1f5e78f..739c285 100644
--- a/cogl/cogl-output.c
+++ b/cogl/cogl-output.c
@@ -47,11 +47,22 @@ _cogl_output_new (const char *name)
static void
_cogl_output_free (CoglOutput *output)
{
- g_free (output->name);
+ if (output->winsys_destroy_callback)
+ output->winsys_destroy_callback (output->winsys);
+ g_free (output->name);
g_slice_free (CoglOutput, output);
}
+void
+_cogl_output_set_winsys_data (CoglOutput *output,
+ void *winsys,
+ CoglUserDataDestroyCallback destroy_callback)
+{
+ output->winsys = winsys;
+ output->winsys_destroy_callback = destroy_callback;
+}
+
gboolean
_cogl_output_values_equal (CoglOutput *output,
CoglOutput *other)
diff --git a/cogl/winsys/cogl-winsys-egl-kms.c b/cogl/winsys/cogl-winsys-egl-kms.c
index a570de6..2b8baaa 100644
--- a/cogl/winsys/cogl-winsys-egl-kms.c
+++ b/cogl/winsys/cogl-winsys-egl-kms.c
@@ -55,6 +55,7 @@
#include "cogl-error-private.h"
#include "cogl-poll-private.h"
#include "cogl-udev-private.h"
+#include "cogl-output-private.h"
static const CoglWinsysEGLVtable _cogl_winsys_egl_vtable;
@@ -70,6 +71,8 @@ typedef struct _CoglRendererKMS
typedef struct _CoglOutputKMS
{
+ uint32_t connector_id;
+
drmModeConnector *connector;
drmModeEncoder *encoder;
drmModeCrtc *saved_crtc;
@@ -263,6 +266,220 @@ dispatch_kms_events (void *user_data, int revents)
handle_drm_event (kms_renderer);
}
+static int
+compare_outputs (CoglOutput *a, CoglOutput *b)
+{
+ CoglOutputKMS *kms_output_a = a->winsys;
+ CoglOutputKMS *kms_output_b = b->winsys;
+ return kms_output_a->connector_id - kms_output_b->connector_id;
+}
+
+static void
+kms_output_destroy_cb (void *user_data)
+{
+ CoglOutputKMS *kms_output = user_data;
+
+ if (kms_output->saved_crtc)
+ drmModeFreeCrtc (kms_output->saved_crtc);
+
+ if (kms_output->encoder)
+ drmModeFreeEncoder (kms_output->encoder);
+
+ if (kms_output->connector)
+ drmModeFreeConnector (kms_output->connector);
+
+ g_slice_free (CoglOutputKMS, user_data);
+}
+
+static const char *kms_connector_types[] = {
+ "Unknown",
+ "VGA",
+ "DVII",
+ "DVID",
+ "DVIA",
+ "Composite",
+ "SVIDEO",
+ "LVDS",
+ "Component",
+ "9PinDIN",
+ "DisplayPort",
+ "HDMIA",
+ "HDMIB",
+ "TV",
+ "eDP"
+};
+
+static void
+update_outputs (CoglRenderer *renderer)
+{
+ CoglRendererEGL *egl_renderer = renderer->winsys;
+ CoglRendererKMS *kms_renderer = egl_renderer->platform;
+ int fd = kms_renderer->fd;
+ drmModeRes *resources;
+ GList *new_outputs = NULL;
+ int i;
+
+ resources = drmModeGetResources (fd);
+ if (!resources)
+ {
+ g_warning ("Failed to query KMS resources");
+ return;
+ }
+
+ for (i = 0; i < resources->count_connectors; i++)
+ {
+ CoglOutput *output = NULL;
+ CoglOutputKMS *kms_output;
+ const char *type_name;
+ GList *l;
+
+ drmModeConnector *connector =
+ drmModeGetConnector (fd, resources->connectors[i]);
+ if (!connector)
+ {
+ g_warning ("Failed to query KMS connector");
+ continue;
+ }
+
+ /* Connectors not actually connected to a display aren't very
+ * interesting */
+ if (connector->connection == DRM_MODE_DISCONNECTED ||
+ connector->count_modes == 0 ||
+ connector->count_encoders == 0)
+ {
+ drmModeFreeConnector (connector);
+ continue;
+ }
+
+ /* If we already have a CoglOutput corresponding to this
+ * connector id then we can simply keep it and move on... */
+ for (l = renderer->outputs; l; l = l->next)
+ {
+ CoglOutput *existing_output = l->data;
+ CoglOutputKMS *existing_kms_output = existing_output->winsys;
+
+ if (existing_kms_output->connector_id == connector->connector_id)
+ {
+ renderer->outputs = g_list_delete_link (renderer->outputs, l);
+ output = existing_output;
+ }
+ }
+
+ if (output)
+ {
+ new_outputs = g_list_prepend (new_outputs, output);
+ drmModeFreeConnector (connector);
+ continue;
+ }
+
+ if (connector->connector_type < G_N_ELEMENTS (kms_connector_types))
+ type_name = kms_connector_types[connector->connector_type];
+ else
+ type_name = kms_connector_types[0];
+
+ output = _cogl_output_new (type_name);
+
+ kms_output = g_slice_new0 (CoglOutputKMS);
+ kms_output->connector_id = connector->connector_id;
+ kms_output->connector = connector;
+
+ /* We can't determinine anything about the relative position
+ * of the outputs... */
+ output->x = output->y = 0;
+
+ output->mm_width = connector->mmWidth;
+ output->mm_height = connector->mmHeight;
+
+ switch (connector->subpixel)
+ {
+ case DRM_MODE_SUBPIXEL_UNKNOWN:
+ output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
+ break;
+ case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
+ output->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB;
+ break;
+ case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
+ output->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_BGR;
+ break;
+ case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
+ output->subpixel_order = COGL_SUBPIXEL_ORDER_VERTICAL_RGB;
+ break;
+ case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
+ output->subpixel_order = COGL_SUBPIXEL_ORDER_VERTICAL_BGR;
+ break;
+ case DRM_MODE_SUBPIXEL_NONE:
+ output->subpixel_order = COGL_SUBPIXEL_ORDER_NONE;
+ break;
+ }
+
+ /* To set a width/height we need to find a crtc mode that is
+ * associated with this connector. First we look at the current
+ * encoder. */
+
+ if (connector->encoder_id)
+ {
+ kms_output->encoder = drmModeGetEncoder (fd, connector->encoder_id);
+ if (!kms_output->encoder)
+ g_warning ("Failed to get encoder description from KMS");
+ }
+
+ if (kms_output->encoder)
+ {
+ drmModeEncoder *encoder = kms_output->encoder;
+
+ if (encoder->crtc_id)
+ {
+ kms_output->saved_crtc = drmModeGetCrtc (fd, encoder->crtc_id);
+ if (!kms_output->saved_crtc)
+ g_warning ("Failed to get crtc description from KMS");
+ }
+ }
+
+ if (kms_output->saved_crtc)
+ {
+ output->width = kms_output->saved_crtc->width;
+ output->height = kms_output->saved_crtc->height;
+
+ if (kms_output->saved_crtc->mode_valid)
+ {
+ drmModeModeInfo *mode = &kms_output->saved_crtc->mode;
+ output->refresh_rate = mode->vrefresh;
+ }
+ }
+ else
+ {
+ /* If there is no encoder associated with the connector then
+ * there is no crtc mode and so there's currently no basis
+ * to specify a width/height */
+ output->width = 0;
+ output->height = 0;
+ }
+
+ _cogl_output_set_winsys_data (output,
+ kms_output,
+ kms_output_destroy_cb);
+
+ new_outputs = g_list_prepend (new_outputs, output);
+ }
+
+ new_outputs = g_list_sort (new_outputs, (GCompareFunc)compare_outputs);
+
+ /* Any remaining outputs listed under renderer->outputs don't
+ * correspond to KMS connector ids that are still valid so we can
+ * free them... */
+ g_list_free_full (renderer->outputs, (GDestroyNotify)cogl_object_unref);
+
+ renderer->outputs = new_outputs;
+
+ drmModeFreeResources (resources);
+}
+
+static void
+handle_hotplug (void *user_data)
+{
+ update_outputs (user_data);
+}
+
static CoglBool
_cogl_winsys_renderer_connect (CoglRenderer *renderer,
CoglError **error)
@@ -281,9 +498,15 @@ _cogl_winsys_renderer_connect (CoglRenderer *renderer,
if (!kms_renderer->udev_drm_device)
goto error;
+ cogl_udev_drm_device_set_hotplug_callback (kms_renderer->udev_drm_device,
+ handle_hotplug,
+ renderer);
+
kms_renderer->fd =
cogl_udev_drm_device_get_fd (kms_renderer->udev_drm_device);
+ update_outputs (renderer);
+
kms_renderer->gbm = gbm_create_device (kms_renderer->fd);
if (kms_renderer->gbm == NULL)
{
@@ -547,8 +770,8 @@ _cogl_winsys_egl_display_setup (CoglDisplay *display,
if (!resources)
{
_cogl_set_error (error, COGL_WINSYS_ERROR,
- COGL_WINSYS_ERROR_INIT,
- "drmModeGetResources failed");
+ COGL_WINSYS_ERROR_INIT,
+ "drmModeGetResources failed");
return FALSE;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]