+ grdrm_pipe *pipe = crtc->pipe;
+ grdrm_fb *fb;
+ int r;
+
+ assert(crtc);
+ assert(basefb);
+ assert(pipe);
+
+ fb = fb_from_base(basefb);
+
+ set_crtc.set_connectors_ptr = PTR_TO_UINT64(crtc->set.connectors);
+ set_crtc.count_connectors = crtc->set.n_connectors;
+ set_crtc.fb_id = fb->id;
+ set_crtc.x = 0;
+ set_crtc.y = 0;
+ set_crtc.mode_valid = 1;
+ set_crtc.mode = crtc->set.mode;
+
+ r = ioctl(card->fd, DRM_IOCTL_MODE_SETCRTC, &set_crtc);
+ if (r < 0) {
+ r = -errno;
+ log_debug("grdrm: %s: cannot set crtc %" PRIu32 ": %m",
+ card->base.name, crtc->object.id);
+
+ grdrm_card_async(card, r);
+ return;
+ }
+
+ if (!crtc->applied) {
+ log_debug("grdrm: %s: crtc %" PRIu32 " applied via deep modeset",
+ card->base.name, crtc->object.id);
+ crtc->applied = true;
+ }
+
+ pipe->base.back = NULL;
+ pipe->base.front = &fb->base;
+ fb->flipid = 0;
+ ++pipe->counter;
+ pipe->base.flipping = false;
+ pipe->base.flip = false;
+
+ /* We cannot schedule dummy page-flips on pipes, hence, the
+ * application would have to schedule their own frame-timers.
+ * To avoid duplicating that everywhere, we schedule our own
+ * timer and raise a fake FRAME event when it fires. */
+ grdev_pipe_schedule(&pipe->base, 1);
+}
+
+static int grdrm_crtc_commit_flip(grdrm_crtc *crtc, grdev_fb *basefb) {
+ struct drm_mode_crtc_page_flip page_flip = { .crtc_id = crtc->object.id };
+ grdrm_card *card = crtc->object.card;
+ grdrm_pipe *pipe = crtc->pipe;