uterm: drm: activate context before swapping
[platform/upstream/kmscon.git] / src / uterm_drm_shared.c
index cfa8a80..ec486ab 100644 (file)
@@ -461,7 +461,38 @@ static void io_event(struct ev_fd *fd, int mask, void *data)
        }
 }
 
+static void vt_timeout(struct ev_timer *timer, uint64_t exp, void *data)
+{
+       struct uterm_video *video = data;
+       struct uterm_drm_video *vdrm = video->data;
+       struct uterm_display *disp;
+       struct shl_dlist *iter;
+       int r;
+
+       r = uterm_drm_video_wake_up(video);
+       if (!r) {
+               ev_timer_update(vdrm->vt_timer, NULL);
+               shl_dlist_for_each(iter, &video->displays) {
+                       disp = shl_dlist_entry(iter, struct uterm_display, list);
+                       VIDEO_CB(video, disp, UTERM_REFRESH);
+               }
+       }
+}
+
+void uterm_drm_video_arm_vt_timer(struct uterm_video *video)
+{
+       struct uterm_drm_video *vdrm = video->data;
+       struct itimerspec spec;
+
+       spec.it_value.tv_sec = 0;
+       spec.it_value.tv_nsec = 20L * 1000L * 1000L; /* 20ms */
+       spec.it_interval = spec.it_value;
+
+       ev_timer_update(vdrm->vt_timer, &spec);
+}
+
 int uterm_drm_video_init(struct uterm_video *video, const char *node,
+                        const struct display_ops *display_ops,
                         uterm_drm_page_flip_t pflip, void *data)
 {
        struct uterm_drm_video *vdrm;
@@ -476,6 +507,7 @@ int uterm_drm_video_init(struct uterm_video *video, const char *node,
        video->data = vdrm;
        vdrm->data = data;
        vdrm->page_flip = pflip;
+       vdrm->display_ops = display_ops;
 
        vdrm->fd = open(node, O_RDWR | O_CLOEXEC | O_NONBLOCK);
        if (vdrm->fd < 0) {
@@ -495,9 +527,16 @@ int uterm_drm_video_init(struct uterm_video *video, const char *node,
        if (ret)
                goto err_fd;
 
+       ret = ev_eloop_new_timer(video->eloop, &vdrm->vt_timer, NULL,
+                                vt_timeout, video);
+       if (ret)
+               goto err_timer;
+
        video->flags |= VIDEO_HOTPLUG;
        return 0;
 
+err_timer:
+       shl_timer_free(vdrm->timer);
 err_fd:
        ev_eloop_rm_fd(vdrm->efd);
 err_close:
@@ -511,6 +550,7 @@ void uterm_drm_video_destroy(struct uterm_video *video)
 {
        struct uterm_drm_video *vdrm = video->data;
 
+       ev_eloop_rm_timer(vdrm->vt_timer);
        ev_eloop_unregister_idle_cb(video->eloop, do_pflips, video, EV_SINGLE);
        shl_timer_free(vdrm->timer);
        ev_eloop_rm_fd(vdrm->efd);
@@ -546,8 +586,7 @@ int uterm_drm_video_find_crtc(struct uterm_video *video, drmModeRes *res,
 }
 
 static void bind_display(struct uterm_video *video, drmModeRes *res,
-                        drmModeConnector *conn,
-                        const struct display_ops *ops)
+                        drmModeConnector *conn)
 {
        struct uterm_drm_video *vdrm = video->data;
        struct uterm_display *disp;
@@ -555,7 +594,7 @@ static void bind_display(struct uterm_video *video, drmModeRes *res,
        struct uterm_mode *mode;
        int ret, i;
 
-       ret = display_new(&disp, ops);
+       ret = display_new(&disp, vdrm->display_ops);
        if (ret)
                return;
        ddrm = disp->data;
@@ -606,8 +645,7 @@ err_unref:
 }
 
 int uterm_drm_video_hotplug(struct uterm_video *video,
-                           const struct display_ops *ops,
-                           bool read_dpms)
+                           bool read_dpms, bool modeset)
 {
        struct uterm_drm_video *vdrm = video->data;
        drmModeRes *res;
@@ -620,6 +658,8 @@ int uterm_drm_video_hotplug(struct uterm_video *video,
        if (!video_is_awake(video) || !video_need_hotplug(video))
                return 0;
 
+       log_debug("testing DRM hotplug status");
+
        res = drmModeGetResources(vdrm->fd);
        if (!res) {
                log_err("cannot retrieve drm resources");
@@ -649,20 +689,29 @@ int uterm_drm_video_hotplug(struct uterm_video *video,
                                continue;
 
                        disp->flags |= DISPLAY_AVAILABLE;
-                       if (!read_dpms || !display_is_online(disp))
+                       if (!display_is_online(disp))
                                break;
 
-                       dpms = uterm_drm_get_dpms(vdrm->fd, conn);
-                       if (dpms != disp->dpms) {
-                               log_debug("DPMS state for display %p changed",
-                                         disp);
-                               uterm_drm_display_set_dpms(disp, disp->dpms);
+                       if (read_dpms) {
+                               dpms = uterm_drm_get_dpms(vdrm->fd, conn);
+                               if (dpms != disp->dpms) {
+                                       log_debug("DPMS state for display %p changed",
+                                                 disp);
+                                       uterm_drm_display_set_dpms(disp, disp->dpms);
+                               }
                        }
+
+                       if (modeset) {
+                               log_debug("re-activate display %p", disp);
+                               uterm_display_use(disp, NULL);
+                               uterm_display_swap(disp, true);
+                       }
+
                        break;
                }
 
                if (iter == &video->displays)
-                       bind_display(video, res, conn, ops);
+                       bind_display(video, res, conn);
 
                drmModeFreeConnector(conn);
        }
@@ -679,8 +728,7 @@ int uterm_drm_video_hotplug(struct uterm_video *video,
        return 0;
 }
 
-int uterm_drm_video_wake_up(struct uterm_video *video,
-                           const struct display_ops *ops)
+int uterm_drm_video_wake_up(struct uterm_video *video)
 {
        int ret;
        struct uterm_drm_video *vdrm = video->data;
@@ -691,8 +739,8 @@ int uterm_drm_video_wake_up(struct uterm_video *video,
                return -EACCES;
        }
 
-       video->flags |= VIDEO_AWAKE;
-       ret = uterm_drm_video_hotplug(video, ops, true);
+       video->flags |= VIDEO_AWAKE | VIDEO_HOTPLUG;
+       ret = uterm_drm_video_hotplug(video, true, true);
        if (ret) {
                drmDropMaster(vdrm->fd);
                return ret;
@@ -706,13 +754,14 @@ void uterm_drm_video_sleep(struct uterm_video *video)
        struct uterm_drm_video *vdrm = video->data;
 
        drmDropMaster(vdrm->fd);
+       ev_timer_drain(vdrm->vt_timer, NULL);
+       ev_timer_update(vdrm->vt_timer, NULL);
 }
 
-int uterm_drm_video_poll(struct uterm_video *video,
-                        const struct display_ops *ops)
+int uterm_drm_video_poll(struct uterm_video *video)
 {
        video->flags |= VIDEO_HOTPLUG;
-       return uterm_drm_video_hotplug(video, ops, false);
+       return uterm_drm_video_hotplug(video, false, false);
 }
 
 /* Waits for events on DRM fd for \mtimeout milliseconds and returns 0 if the