compositor-drm: allocate CRTC on enable()
authorPekka Paalanen <pekka.paalanen@collabora.co.uk>
Fri, 8 Sep 2017 10:32:40 +0000 (13:32 +0300)
committerPekka Paalanen <pekka.paalanen@collabora.co.uk>
Wed, 18 Apr 2018 08:53:54 +0000 (11:53 +0300)
A drm_output needs a CRTC only when it is in use. Allocating a CRTC on
creation of drm_output will reserve the CRTC regardless of whether the
output is actually used or not. This may cause creating other
drm_outputs to fail if there are not enough CRTCs.

Instead, allocate the CRTC on drm_output enable() time. A drm_output
will have a valid CRTC only while it is enabled.

This allows us to create drm_output objects arbitrarily and without a
head assignment, which is required by the head-based output API for the
backends. The assigned heads will be known only at enable() time.

Now drm_output_enable() has to call drmModeGetResources() to be able to
find a suitable CRTC. We might want to cache the resources somewhere,
but that is it topic for another patch.

v4: Force resetting unused CRTCs on fini.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
Reviewed-by: Daniel Stone <daniels@collabora.com>
Acked-by: Derek Foreman <derekf@osg.samsung.com>
libweston/compositor-drm.c

index 701a40c..90c6f24 100644 (file)
@@ -4698,6 +4698,8 @@ drm_output_init_crtc(struct drm_output *output,
                drm_output_find_special_plane(b, output,
                                              WDRM_PLANE_TYPE_CURSOR);
 
+       wl_array_remove_uint32(&b->unused_crtcs, output->crtc_id);
+
        return 0;
 
 err_crtc:
@@ -4717,6 +4719,7 @@ static void
 drm_output_fini_crtc(struct drm_output *output)
 {
        struct drm_backend *b = to_drm_backend(output->base.compositor);
+       uint32_t *unused;
 
        if (!b->universal_planes && !b->shutting_down) {
                /* With universal planes, the 'special' planes are allocated at
@@ -4738,6 +4741,15 @@ drm_output_fini_crtc(struct drm_output *output)
        }
 
        drm_property_info_free(output->props_crtc, WDRM_CRTC__COUNT);
+
+       assert(output->crtc_id != 0);
+
+       unused = wl_array_add(&b->unused_crtcs, sizeof(*unused));
+       *unused = output->crtc_id;
+
+       /* Force resetting unused CRTCs */
+       b->state_invalid = true;
+
        output->crtc_id = 0;
        output->cursor_plane = NULL;
        output->scanout_plane = NULL;
@@ -4750,6 +4762,21 @@ drm_output_enable(struct weston_output *base)
        struct drm_backend *b = to_drm_backend(base->compositor);
        struct drm_head *head = to_drm_head(weston_output_get_first_head(base));
        struct weston_mode *m;
+       drmModeRes *resources;
+       int ret;
+
+       resources = drmModeGetResources(b->drm.fd);
+       if (!resources) {
+               weston_log("drmModeGetResources failed\n");
+               return -1;
+       }
+       ret = drm_output_init_crtc(output, resources, head->connector);
+       drmModeFreeResources(resources);
+       if (ret < 0)
+               return -1;
+
+       if (drm_output_init_gamma_size(output) < 0)
+               goto err;
 
        if (b->pageflip_timeout)
                drm_output_pageflip_timer_create(output);
@@ -4792,7 +4819,6 @@ drm_output_enable(struct weston_output *base)
                                      &b->compositor->primary_plane);
 
        wl_array_remove_uint32(&b->unused_connectors, head->connector_id);
-       wl_array_remove_uint32(&b->unused_crtcs, output->crtc_id);
 
        weston_log("Output %s, (connector %d, crtc %d)\n",
                   output->base.name, head->connector_id, output->crtc_id);
@@ -4809,6 +4835,8 @@ drm_output_enable(struct weston_output *base)
        return 0;
 
 err:
+       drm_output_fini_crtc(output);
+
        return -1;
 }
 
@@ -4843,11 +4871,8 @@ drm_output_deinit(struct weston_output *base)
 
        unused = wl_array_add(&b->unused_connectors, sizeof(*unused));
        *unused = head->connector_id;
-       unused = wl_array_add(&b->unused_crtcs, sizeof(*unused));
-       *unused = output->crtc_id;
 
-       /* Force programming unused connectors and crtcs. */
-       b->state_invalid = true;
+       drm_output_fini_crtc(output);
 }
 
 static void
@@ -4877,8 +4902,6 @@ drm_output_destroy(struct weston_output *base)
 
        weston_output_release(&output->base);
 
-       drm_output_fini_crtc(output);
-
        assert(!output->state_last);
        drm_output_state_free(output->state_cur);
 
@@ -5148,12 +5171,6 @@ create_output_for_connector(struct drm_backend *b,
        output->destroy_pending = 0;
        output->disable_pending = 0;
 
-       if (drm_output_init_crtc(output, resources, connector) < 0)
-               goto err_output;
-
-       if (drm_output_init_gamma_size(output) < 0)
-               goto err_output;
-
        output->state_cur = drm_output_state_alloc(output, NULL);
 
        for (i = 0; i < head->connector->count_modes; i++) {