Add plane setting to connector configuration 83/27383/4
authorDamian Hobson-Garcia <dhobsong@igel.co.jp>
Fri, 8 Apr 2022 01:40:03 +0000 (10:40 +0900)
committerDamian Hobson-Garcia <dhobsong@igel.co.jp>
Wed, 20 Apr 2022 03:05:07 +0000 (12:05 +0900)
Provide a setting to override the default DRM plane
alloction for each connector in a lease.

DRM planes that are compatible with multiple CRTCs/
connectors can now be assigned to a lease by
explicity setting the connector that they belong to
in the configuration file.

This can also be used to restrict the planes that
are available to a given connector.

Bug-AGL: SPEC-3815

Change-Id: If4168fc3081213c4ed1df09755cadf042c68d9a3
Signed-off-by: Damian Hobson-Garcia <dhobsong@igel.co.jp>
drm-lease-manager/drm-lease.h
drm-lease-manager/lease-config.c
drm-lease-manager/lease-manager.c
drm-lease-manager/test/lease-config-test.c
drm-lease-manager/test/lease-manager-test.c

index 84fa942..5670fa8 100644 (file)
@@ -26,6 +26,8 @@ struct lease_handle {
 struct connector_config {
        char *name;
        bool optional;
+       int nplanes;
+       uint32_t *planes;
 };
 
 struct lease_config {
index b3f35a1..aaba6b6 100644 (file)
 
 #define CONFIG_ERROR(x, ...) ERROR_LOG("%s: " x, filename, ##__VA_ARGS__)
 
+static bool populate_connector_planes(struct connector_config *config,
+                                     toml_array_t *planes)
+{
+       config->nplanes = toml_array_nelem(planes);
+       config->planes = calloc(config->nplanes, sizeof(uint32_t));
+       if (!config->planes) {
+               DEBUG_LOG("Memory allocation failed: %s\n", strerror(errno));
+               return false;
+       }
+
+       for (int j = 0; j < config->nplanes; j++) {
+               toml_datum_t plane = toml_int_at(planes, j);
+               if (!plane.ok) {
+                       return false;
+               }
+               config->planes[j] = plane.u.i;
+       }
+       return true;
+}
+
 static bool populate_connector_config(struct lease_config *config,
                                      toml_table_t *global_table,
                                      toml_array_t *conns)
@@ -55,6 +75,14 @@ static bool populate_connector_config(struct lease_config *config,
                    toml_bool_in(conn_config_data, "optional");
                if (optional.ok)
                        config->connectors[i].optional = optional.u.b;
+
+               toml_array_t *planes =
+                   toml_array_in(conn_config_data, "planes");
+               if (planes && !populate_connector_planes(conn_config, planes)) {
+                       ERROR_LOG("Invalid plane id for connector: %s\n",
+                                 conn_config->name);
+                       return false;
+               }
        }
        return true;
 }
@@ -128,8 +156,10 @@ void release_config(int num_leases, struct lease_config *config)
        for (int i = 0; i < num_leases; i++) {
                struct lease_config *c = &config[i];
                free(c->lease_name);
-               for (int j = 0; j < c->nconnectors; j++)
+               for (int j = 0; j < c->nconnectors; j++) {
                        free(c->connectors[j].name);
+                       free(c->connectors[j].planes);
+               }
                free(c->connectors);
        }
        free(config);
index 3834631..885ca29 100644 (file)
@@ -216,17 +216,48 @@ static bool drm_find_connector(struct lm *lm, char *name, uint32_t *id)
        return false;
 }
 
-static bool lease_add_planes(struct lm *lm, struct lease *lease, int crtc_index)
+static void config_get_planes(struct lm *lm,
+                             const struct connector_config *config,
+                             int *nplanes, uint32_t **planes)
 {
-       for (uint32_t i = 0; i < lm->drm_plane_resource->count_planes; i++) {
-               uint32_t plane_id = lm->drm_plane_resource->planes[i];
+       if (config && config->planes) {
+               *nplanes = config->nplanes;
+               *planes = config->planes;
+       } else {
+               *nplanes = (int)lm->drm_plane_resource->count_planes;
+               *planes = lm->drm_plane_resource->planes;
+       }
+}
+
+static bool lease_add_planes(struct lm *lm, struct lease *lease,
+                            uint32_t crtc_index,
+                            const struct connector_config *con_config)
+{
+       int nplanes;
+       uint32_t *planes;
+       uint32_t crtc_mask = (1 << crtc_index);
+
+       /* Only allow shared planes when plane list is explicitly set */
+       bool allow_shared = con_config && con_config->planes;
+
+       config_get_planes(lm, con_config, &nplanes, &planes);
+
+       for (int i = 0; i < nplanes; i++) {
+               uint32_t plane_id = planes[i];
                drmModePlanePtr plane = drmModeGetPlane(lm->drm_fd, plane_id);
 
-               assert(plane);
+               if (!plane) {
+                       ERROR_LOG(
+                           "Unknown plane id %d configured in lease: %s\n",
+                           plane_id, lease->base.name);
+                       return false;
+               }
 
-               // Exclude planes that can be used with multiple CRTCs for now
-               if (plane->possible_crtcs == (1u << crtc_index)) {
-                       lease->object_ids[lease->nobject_ids++] = plane_id;
+               if (plane->possible_crtcs & crtc_mask) {
+                       bool shared_plane = plane->possible_crtcs != crtc_mask;
+                       if (allow_shared || !shared_plane)
+                               lease->object_ids[lease->nobject_ids++] =
+                                   plane_id;
                }
                drmModeFreePlane(plane);
        }
@@ -404,7 +435,7 @@ static struct lease *lease_create(struct lm *lm,
                        goto err;
                }
 
-               if (!lease_add_planes(lm, lease, crtc_index))
+               if (!lease_add_planes(lm, lease, crtc_index, con_config))
                        goto err;
 
                uint32_t crtc_id = lm->drm_resource->crtcs[crtc_index];
@@ -487,6 +518,13 @@ static struct lm *drm_device_get_resources(const char *device)
                goto err;
        }
 
+       /* Enable universal planes so that ALL planes, even primary and cursor
+        * planes can be assigned from lease configurations. */
+       if (drmSetClientCap(lm->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1)) {
+               DEBUG_LOG("drmSetClientCap failed\n");
+               goto err;
+       }
+
        lm->drm_resource = drmModeGetResources(lm->drm_fd);
        if (!lm->drm_resource) {
                ERROR_LOG("Invalid DRM device(%s)\n", device);
index 65bd32a..0dc171f 100644 (file)
@@ -74,6 +74,43 @@ START_TEST(parse_leases)
 }
 END_TEST
 
+START_TEST(connector_config)
+{
+       ck_assert_ptr_ne(config_file, NULL);
+
+       char test_data[] = "[[lease]]\n"
+                          "name = \"lease 1\"\n"
+                          "connectors = [\"1\", \"b\",\"gamma\" ]\n"
+                          "[b]\n"
+                          "optional = true\n"
+                          "planes = [1, 4, 3]\n";
+
+       write(config_fd, test_data, sizeof(test_data));
+
+       struct lease_config *config = NULL;
+       int nconfigs = parse_config(config_file, &config);
+
+       ck_assert_int_eq(nconfigs, 1);
+       ck_assert_ptr_ne(config, NULL);
+
+       ck_assert_str_eq(config[0].lease_name, "lease 1");
+       ck_assert_int_eq(config[0].nconnectors, 3);
+       ck_assert_str_eq(config[0].connectors[0].name, "1");
+       ck_assert_str_eq(config[0].connectors[1].name, "b");
+       ck_assert_str_eq(config[0].connectors[2].name, "gamma");
+
+       ck_assert(!config[0].connectors[0].optional);
+       ck_assert(config[0].connectors[1].optional);
+       ck_assert(!config[0].connectors[2].optional);
+
+       ck_assert_int_eq(config[0].connectors[1].nplanes, 3);
+       ck_assert_int_eq(config[0].connectors[1].planes[0], 1);
+       ck_assert_int_eq(config[0].connectors[1].planes[1], 4);
+       ck_assert_int_eq(config[0].connectors[1].planes[2], 3);
+
+       release_config(nconfigs, config);
+}
+END_TEST
 static void add_parse_tests(Suite *s)
 {
        TCase *tc = tcase_create("Config file parsing tests");
@@ -81,6 +118,7 @@ static void add_parse_tests(Suite *s)
        tcase_add_checked_fixture(tc, test_setup, test_shutdown);
 
        tcase_add_test(tc, parse_leases);
+       tcase_add_test(tc, connector_config);
        suite_add_tcase(s, tc);
 }
 
index b32cd05..fa87815 100644 (file)
@@ -61,6 +61,7 @@ FAKE_VOID_FUNC(drmModeFreeEncoder, drmModeEncoderPtr);
 FAKE_VALUE_FUNC(int, drmModeCreateLease, int, const uint32_t *, int, int,
                uint32_t *);
 FAKE_VALUE_FUNC(int, drmModeRevokeLease, int, uint32_t);
+FAKE_VALUE_FUNC(int, drmSetClientCap, int, uint64_t, uint64_t);
 
 /************** Test fixutre functions *************************/
 struct lm *g_lm = NULL;
@@ -90,6 +91,8 @@ static void test_setup(void)
        drmModeGetEncoder_fake.custom_fake = get_encoder;
        drmModeCreateLease_fake.custom_fake = create_lease;
 
+       drmSetClientCap_fake.return_val = 0;
+
        ck_assert_msg(g_lm == NULL,
                      "Lease manager context not clear at start of test");
 }
@@ -524,6 +527,73 @@ START_TEST(named_connector_config)
 }
 END_TEST
 
+/* config plane sharing */
+/* Test details: Add overlay planes to leases. Some planes are shared between
+ *               multiple CRTCs. These planes are explicitly assigned to a
+ * connector. Expected results: The leases contain all of the unique planes for
+ * each CRTC. Shared planes are also included as defined by the lease
+ *                   configuration.
+ */
+START_TEST(config_plane_sharing)
+{
+
+       int out_cnt = 2, plane_cnt = 3, lease_cnt = 2;
+
+       ck_assert_int_eq(
+           setup_drm_test_device(out_cnt, out_cnt, out_cnt, plane_cnt), true);
+
+       drmModeConnector connectors[] = {
+           CONNECTOR_FULL(CONNECTOR_ID(0), ENCODER_ID(0), &ENCODER_ID(0), 1,
+                          DRM_MODE_CONNECTOR_HDMIA, 1),
+           CONNECTOR_FULL(CONNECTOR_ID(1), ENCODER_ID(1), &ENCODER_ID(1), 1,
+                          DRM_MODE_CONNECTOR_VGA, 3),
+       };
+
+       drmModeEncoder encoders[] = {
+           ENCODER(ENCODER_ID(0), CRTC_ID(0), 0x1),
+           ENCODER(ENCODER_ID(1), CRTC_ID(1), 0x2),
+       };
+
+       drmModePlane planes[] = {
+           PLANE(PLANE_ID(0), 0x2),
+           PLANE(PLANE_ID(1), 0x1),
+           PLANE(PLANE_ID(2), 0x3),
+       };
+
+       setup_test_device_layout(connectors, encoders, planes);
+
+       struct lease_config lconfig[] = {
+           [0] =
+               {
+                   .lease_name = "Lease Config Test 1",
+                   .nconnectors = 1,
+                   .connectors =
+                       (struct connector_config[]){
+                           {.name = "HDMI-A-1",
+                            .nplanes = 2,
+                            .planes = (uint32_t[]){PLANE_ID(1), PLANE_ID(2)}},
+                       },
+               },
+           [1] =
+               {
+                   .lease_name = "Lease Config Test 2",
+                   .nconnectors = 1,
+                   .connectors =
+                       (struct connector_config[]){
+                           {.name = "VGA-3"},
+                       },
+               },
+       };
+
+       struct lease_handle **handles = create_leases(lease_cnt, lconfig);
+
+       CHECK_LEASE_OBJECTS(handles[0], PLANE_ID(1), PLANE_ID(2), CRTC_ID(0),
+                           CONNECTOR_ID(0));
+       CHECK_LEASE_OBJECTS(handles[1], PLANE_ID(0), CRTC_ID(1),
+                           CONNECTOR_ID(1));
+}
+END_TEST
+
 static void add_lease_config_tests(Suite *s)
 {
        TCase *tc = tcase_create("Lease configuration");
@@ -533,6 +603,7 @@ static void add_lease_config_tests(Suite *s)
        tcase_add_test(tc, multiple_connector_lease);
        tcase_add_test(tc, single_failed_lease);
        tcase_add_test(tc, named_connector_config);
+       tcase_add_test(tc, config_plane_sharing);
        suite_add_tcase(s, tc);
 }