+static void grdrm_crtc_commit_deep(grdrm_crtc *crtc, grdev_fb **slot) {
+ struct drm_mode_crtc set_crtc = { .crtc_id = crtc->object.id };
+ grdrm_card *card = crtc->object.card;
+ grdrm_pipe *pipe = crtc->pipe;
+ grdrm_fb *fb = fb_from_base(*slot);
+ size_t i;
+ int r;
+
+ assert(crtc);
+ assert(slot);
+ assert(*slot);
+ assert(pipe);
+
+ 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;
+ }
+
+ *slot = 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);
+
+ if (!pipe->base.back) {
+ for (i = 0; i < pipe->base.max_fbs; ++i) {
+ if (!pipe->base.fbs[i])
+ continue;
+
+ fb = fb_from_base(pipe->base.fbs[i]);
+ if (&fb->base == pipe->base.front)
+ continue;
+
+ fb->flipid = 0;
+ pipe->base.back = &fb->base;
+ break;
+ }
+ }
+}
+
+static int grdrm_crtc_commit_flip(grdrm_crtc *crtc, grdev_fb **slot) {