Add support for drmModeAtomicCommit 54/197754/1
authorZhaowei Yuan <zhaowei.yuan@samsung.com>
Wed, 16 Jan 2019 03:12:50 +0000 (11:12 +0800)
committerZhaowei Yuan <zhaowei.yuan@samsung.com>
Wed, 16 Jan 2019 06:09:13 +0000 (14:09 +0800)
Current display commit API drmModeSetPlane() takes too much time
and its caller tdm_layer_commit() holds a lock "private_display->lock"
which is also needed by other thread, it makes performance low.

In order to solve this problem, we need an asynchronous API to do
this job which is drmModeAtomicCommit() here.

Patch's modification includes:
1. Change display commit method to drmModeAtomicCommit.
2. Disable vblank wait event in function vc4_output_commit()
since it's not necessary any more for atomic mode.
3. Create an event and pass it to _tdm_vc4_display_commit_layer()
which is used to API finish callback.

Change-Id: If2ba5c80bcd553cdd7f4cd04364d1e40d203dc10

src/tdm_vc4_display.c

index fc9c76a..cbaa822 100644 (file)
@@ -44,6 +44,24 @@ struct _tdm_vc4_event_data {
        void *user_data;
 };
 
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+struct display_properties_ids {
+       uint32_t connector_crtc_id;
+       uint32_t crtc_mode_id;
+       uint32_t crtc_active;
+       uint32_t plane_fb_id;
+       uint32_t plane_crtc_id;
+       uint32_t plane_src_x;
+       uint32_t plane_src_y;
+       uint32_t plane_src_w;
+       uint32_t plane_src_h;
+       uint32_t plane_crtc_x;
+       uint32_t plane_crtc_y;
+       uint32_t plane_crtc_w;
+       uint32_t plane_crtc_h;
+       uint32_t plane_zpos;
+};
+
 struct _tdm_vc4_output_data {
        struct list_head link;
 
@@ -77,6 +95,9 @@ struct _tdm_vc4_output_data {
        int crtc_enabled;
        unsigned int crtc_fb_id;
 
+       uint32_t output_plane;
+       struct display_properties_ids props;
+
        /* hwc */
        int hwc_enable;
        tdm_vc4_hwc_data *hwc_data;
@@ -561,13 +582,147 @@ _tdm_vc4_display_wait_vblank(int fd, int pipe, uint *target_msc, void *data)
        return TDM_ERROR_NONE;
 }
 
+static int _tdm_vc4_display_get_properties(int drm_fd, uint32_t connector_id, uint32_t crtc_id,
+                                       uint32_t plane_id, struct display_properties_ids *ids)
+{
+       drmModeObjectPropertiesPtr properties = NULL;
+       drmModePropertyPtr property = NULL;
+       int i, j;
+       tdm_error ret = TDM_ERROR_NONE;
+       struct {
+               uint32_t object_type;
+               uint32_t object_id;
+               char *name;
+               uint32_t *value;
+       } glue[] = {
+               { DRM_MODE_OBJECT_CONNECTOR, connector_id, "CRTC_ID", &ids->connector_crtc_id },
+               { DRM_MODE_OBJECT_CRTC, crtc_id, "MODE_ID", &ids->crtc_mode_id },
+               { DRM_MODE_OBJECT_CRTC, crtc_id, "ACTIVE", &ids->crtc_active },
+               { DRM_MODE_OBJECT_PLANE, plane_id, "FB_ID", &ids->plane_fb_id },
+               { DRM_MODE_OBJECT_PLANE, plane_id, "CRTC_ID", &ids->plane_crtc_id },
+               { DRM_MODE_OBJECT_PLANE, plane_id, "SRC_X", &ids->plane_src_x },
+               { DRM_MODE_OBJECT_PLANE, plane_id, "SRC_Y", &ids->plane_src_y },
+               { DRM_MODE_OBJECT_PLANE, plane_id, "SRC_W", &ids->plane_src_w },
+               { DRM_MODE_OBJECT_PLANE, plane_id, "SRC_H", &ids->plane_src_h },
+               { DRM_MODE_OBJECT_PLANE, plane_id, "CRTC_X", &ids->plane_crtc_x },
+               { DRM_MODE_OBJECT_PLANE, plane_id, "CRTC_Y", &ids->plane_crtc_y },
+               { DRM_MODE_OBJECT_PLANE, plane_id, "CRTC_W", &ids->plane_crtc_w },
+               { DRM_MODE_OBJECT_PLANE, plane_id, "CRTC_H", &ids->plane_crtc_h },
+       };
+
+       for (i = 0; i < ARRAY_SIZE(glue); i++) {
+               properties = drmModeObjectGetProperties(drm_fd,
+                                                       glue[i].object_id,
+                                                       glue[i].object_type);
+
+               if (properties == NULL) {
+                       ret = TDM_ERROR_OPERATION_FAILED;
+                       goto finish;
+               }
+
+               for (j = 0; j < properties->count_props; j++) {
+                       property = drmModeGetProperty(drm_fd, properties->props[j]);
+                       if (property == NULL) {
+                               continue;
+                       }
+
+                       if (strcmp(property->name, glue[i].name) == 0) {
+                               *glue[i].value = property->prop_id;
+                               drmModeFreeProperty(property);
+                               break;
+                       }
+                       drmModeFreeProperty(property);
+               }
+
+               if (j == properties->count_props) {
+                       ret = TDM_ERROR_OPERATION_FAILED;
+                       goto finish;
+               }
+
+               drmModeFreeObjectProperties(properties);
+               properties = NULL;
+       }
+
+finish:
+       if (properties != NULL)
+               drmModeFreeObjectProperties(properties);
+
+       return ret;
+}
+
+static int _tdm_vc4_display_get_plane_id(int drm_fd, uint32_t crtc_id)
+{
+       drmModeResPtr ressources = NULL;
+       drmModePlaneResPtr plane_resources;
+       uint32_t crtc_index = 0;
+       uint32_t plane_id = 0;
+       uint32_t found_primary = 0;
+       int i, j;
+
+       ressources = drmModeGetResources(drm_fd);
+       if (ressources == NULL) {
+               goto finish;
+       }
+
+       for (i = 0; i < ressources->count_crtcs; i++) {
+               if (ressources->crtcs[i] == crtc_id) {
+                       crtc_index = i;
+                       break;
+               }
+       }
+
+       if (i == ressources->count_crtcs) {
+               goto free_resource;
+       }
+
+       plane_resources = drmModeGetPlaneResources(drm_fd);
+       if (!plane_resources) {
+               goto free_resource;
+       }
+
+       for (i = 0; (i < plane_resources->count_planes) && !found_primary; i++) {
+               plane_id = plane_resources->planes[i];
+               drmModePlanePtr plane = drmModeGetPlane(drm_fd, plane_id);
+               if (!plane) {
+                       continue;
+               }
+
+               if (plane->possible_crtcs & (1 << crtc_index)) {
+                       drmModeObjectPropertiesPtr props =
+                               drmModeObjectGetProperties(drm_fd, plane_id, DRM_MODE_OBJECT_PLANE);
+
+                       for (j = 0; j < props->count_props; j++) {
+                               drmModePropertyPtr p = drmModeGetProperty(drm_fd, props->props[j]);
+
+                               if ((strcmp(p->name, "type") == 0) &&
+                                               (props->prop_values[j] == DRM_PLANE_TYPE_PRIMARY)) {
+                                       found_primary = 1;
+                               }
+
+                               drmModeFreeProperty(p);
+                       }
+
+                       drmModeFreeObjectProperties(props);
+               }
+
+               drmModeFreePlane(plane);
+       }
+
+       drmModeFreePlaneResources(plane_resources);
+free_resource:
+       drmModeFreeResources(ressources);
+finish:
+       return plane_id;
+}
+
 static tdm_error
-_tdm_vc4_display_commit_layer(tdm_vc4_layer_data *layer_data)
+_tdm_vc4_display_commit_layer(tdm_vc4_layer_data *layer_data, void *event_data)
 {
        tdm_vc4_data *vc4_data = layer_data->vc4_data;
        tdm_vc4_output_data *output_data = layer_data->output_data;
        uint32_t fx, fy, fw, fh;
-       int crtc_w;
+       drmModeAtomicReqPtr request;
+       uint32_t flags =  0;
 
        if (!layer_data->display_buffer_changed && !layer_data->info_changed)
                return TDM_ERROR_NONE;
@@ -576,59 +731,41 @@ _tdm_vc4_display_commit_layer(tdm_vc4_layer_data *layer_data)
                if (_tdm_vc4_display_set_crtc(vc4_data, output_data, 1) != TDM_ERROR_NONE)
                        return TDM_ERROR_OPERATION_FAILED;
 
-               output_data->crtc_enabled = 1;
-       }
-
-       if (output_data->current_mode)
-               crtc_w = output_data->current_mode->hdisplay;
-       else {
-               drmModeCrtcPtr crtc = drmModeGetCrtc(vc4_data->drm_fd, output_data->crtc_id);
-               if (!crtc) {
-                       TDM_ERR("getting crtc failed");
-                       return TDM_ERROR_OPERATION_FAILED;
-               }
-               crtc_w = crtc->width;
-               if (crtc_w == 0) {
-                       TDM_ERR("getting crtc width failed");
-                       drmModeFreeCrtc(crtc);
-                       return TDM_ERROR_OPERATION_FAILED;
-               }
-               drmModeFreeCrtc(crtc);
-       }
+               drmSetClientCap(vc4_data->drm_fd, DRM_CLIENT_CAP_ATOMIC, 1);
+               drmSetClientCap(vc4_data->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
 
-       layer_data->display_buffer_changed = 0;
-       layer_data->info_changed = 0;
+               output_data->output_plane = _tdm_vc4_display_get_plane_id(vc4_data->drm_fd, output_data->crtc_id);
 
-       if (!layer_data->display_buffer) {
-               if (drmModeSetPlane(vc4_data->drm_fd, layer_data->plane_id,
-                                                       output_data->crtc_id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
-                       TDM_ERR("unset plane(%d) filed: %m", layer_data->plane_id);
+               _tdm_vc4_display_get_properties(vc4_data->drm_fd, output_data->connector_id,
+                                                       output_data->crtc_id, output_data->output_plane, &output_data->props);
 
-               return TDM_ERROR_NONE;
+               output_data->crtc_enabled = 1;
        }
 
+       flags = DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK;
+       request = drmModeAtomicAlloc();
+
        /* Source values are 16.16 fixed point */
        fx = ((unsigned int)layer_data->info.src_config.pos.x) << 16;
        fy = ((unsigned int)layer_data->info.src_config.pos.y) << 16;
        fw = ((unsigned int)layer_data->info.src_config.pos.w) << 16;
        fh = ((unsigned int)layer_data->info.src_config.pos.h) << 16;
 
-       if (drmModeSetPlane(vc4_data->drm_fd, layer_data->plane_id,
-                                               output_data->crtc_id, layer_data->display_buffer->fb_id, 0,
-                                               layer_data->info.dst_pos.x, layer_data->info.dst_pos.y,
-                                               layer_data->info.dst_pos.w, layer_data->info.dst_pos.h,
-                                               fx, fy, fw, fh) < 0) {
-               TDM_ERR("set plane(%d) failed: %m", layer_data->plane_id);
-               return TDM_ERROR_OPERATION_FAILED;
-       }
+       drmModeAtomicAddProperty(request, output_data->output_plane, output_data->props.plane_fb_id, layer_data->display_buffer->fb_id);
+       drmModeAtomicAddProperty(request, output_data->output_plane, output_data->props.plane_crtc_id, output_data->crtc_id);
+       drmModeAtomicAddProperty(request, output_data->output_plane, output_data->props.plane_src_x, fx);
+       drmModeAtomicAddProperty(request, output_data->output_plane, output_data->props.plane_src_y, fy);
+       drmModeAtomicAddProperty(request, output_data->output_plane, output_data->props.plane_src_w, fw);
+       drmModeAtomicAddProperty(request, output_data->output_plane, output_data->props.plane_src_h, fh);
+       drmModeAtomicAddProperty(request, output_data->output_plane, output_data->props.plane_crtc_x, layer_data->info.src_config.pos.x);
+       drmModeAtomicAddProperty(request, output_data->output_plane, output_data->props.plane_crtc_y, layer_data->info.src_config.pos.y);
+       drmModeAtomicAddProperty(request, output_data->output_plane, output_data->props.plane_crtc_w, layer_data->info.src_config.pos.w);
+       drmModeAtomicAddProperty(request, output_data->output_plane, output_data->props.plane_crtc_h, layer_data->info.src_config.pos.h);
+
+       layer_data->display_buffer_changed = 0;
+       layer_data->info_changed = 0;
 
-       TDM_DBG("plane(%d) crtc(%d) pos(%d) on: fb(%d,[%d,%d %dx%d]=>[%d,%d %dx%d])\n",
-                       layer_data->plane_id, output_data->crtc_id, layer_data->zpos,
-                       layer_data->display_buffer->fb_id,
-                       layer_data->info.src_config.pos.x, layer_data->info.src_config.pos.y,
-                       layer_data->info.src_config.pos.w, layer_data->info.src_config.pos.h,
-                       layer_data->info.dst_pos.x, layer_data->info.dst_pos.y,
-                       layer_data->info.dst_pos.w, layer_data->info.dst_pos.h);
+       drmModeAtomicCommit(vc4_data->drm_fd, request, flags, event_data);
 
        return TDM_ERROR_NONE;
 }
@@ -1723,12 +1860,17 @@ vc4_output_commit(tdm_output *output, int sync, void *user_data)
        tdm_vc4_data *vc4_data;
        tdm_vc4_layer_data *layer_data = NULL;
        tdm_error ret;
-       int do_waitvblank = 1;
+       int do_waitvblank = 0;
 
        RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
 
        vc4_data = output_data->vc4_data;
 
+       tdm_vc4_event_data *event_data = calloc(1, sizeof(tdm_vc4_event_data));
+       event_data->type = TDM_DRM_EVENT_TYPE_COMMIT;
+       event_data->output_data = output_data;
+       event_data->user_data = user_data;
+
 #if 0
        if (output_data->hwc_enable) {
                ret = _tdm_vc4_display_prepare_commit(output_data);
@@ -1737,13 +1879,15 @@ vc4_output_commit(tdm_output *output, int sync, void *user_data)
 #endif
 
        LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
-               ret = _tdm_vc4_display_commit_layer(layer_data);
-               if (ret != TDM_ERROR_NONE)
+               ret = _tdm_vc4_display_commit_layer(layer_data, event_data);
+               if (ret != TDM_ERROR_NONE) {
+                       free(event_data);
                        return ret;
+               }
        }
 
        if (do_waitvblank == 1) {
-               tdm_vc4_event_data *event_data = calloc(1, sizeof(tdm_vc4_event_data));
+               event_data = calloc(1, sizeof(tdm_vc4_event_data));
                uint target_msc;
 
                if (!event_data) {