summaryrefslogtreecommitdiff
path: root/src/sna
diff options
context:
space:
mode:
Diffstat (limited to 'src/sna')
-rw-r--r--src/sna/kgem.c25
-rw-r--r--src/sna/sna.h2
-rw-r--r--src/sna/sna_display.c46
3 files changed, 71 insertions, 2 deletions
diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index 82ff619f..485ef8fb 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -3200,7 +3200,7 @@ static void dump_fence_regs(struct kgem *kgem)
static int do_execbuf(struct kgem *kgem, struct drm_i915_gem_execbuffer2 *execbuf)
{
- int ret;
+ int ret, err;
retry:
ret = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, execbuf);
@@ -3216,7 +3216,28 @@ retry:
goto retry;
/* last gasp */
- return do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, execbuf);
+ ret = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, execbuf);
+ if (ret == 0)
+ return 0;
+
+ xf86DrvMsg(kgem_get_screen_index(kgem), X_WARNING,
+ "Failed to submit rendering commands, trying again with outputs disabled.\n");
+
+ /* One last trick up our sleeve for when we run out of space.
+ * We turn everything off to free up our pinned framebuffers,
+ * sprites and cursors, and try one last time.
+ */
+ err = errno;
+ if (sna_mode_disable(container_of(kgem, struct sna, kgem))) {
+ kgem_cleanup_cache(kgem);
+ ret = do_ioctl(kgem->fd,
+ DRM_IOCTL_I915_GEM_EXECBUFFER2,
+ execbuf);
+ sna_mode_enable(container_of(kgem, struct sna, kgem));
+ }
+ errno = err;
+
+ return ret;
}
void _kgem_submit(struct kgem *kgem)
diff --git a/src/sna/sna.h b/src/sna/sna.h
index ad74870a..04ee35c9 100644
--- a/src/sna/sna.h
+++ b/src/sna/sna.h
@@ -426,6 +426,8 @@ bool sna_mode_wants_tear_free(struct sna *sna);
void sna_mode_adjust_frame(struct sna *sna, int x, int y);
extern void sna_mode_discover(struct sna *sna);
extern void sna_mode_check(struct sna *sna);
+extern bool sna_mode_disable(struct sna *sna);
+extern void sna_mode_enable(struct sna *sna);
extern void sna_mode_reset(struct sna *sna);
extern void sna_mode_wakeup(struct sna *sna);
extern void sna_mode_redisplay(struct sna *sna);
diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index 54ebe786..2a98fb94 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -5785,6 +5785,52 @@ sna_mode_set_primary(struct sna *sna)
#endif
}
+bool
+sna_mode_disable(struct sna *sna)
+{
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
+ int i;
+
+ if (sna->flags & SNA_IS_HOSTED)
+ return false;
+
+ if (!sna->scrn->vtSema)
+ return false;
+
+ sna_hide_cursors(sna->scrn);
+ for (i = 0; i < sna->mode.num_real_crtc; i++)
+ sna_crtc_disable(config->crtc[i]);
+
+ while (sna_mode_has_pending_events(sna))
+ sna_mode_wakeup(sna);
+
+ kgem_clean_scanout_cache(&sna->kgem);
+ return true;
+}
+
+void
+sna_mode_enable(struct sna *sna)
+{
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
+ int i;
+
+ if (sna->flags & SNA_IS_HOSTED)
+ return;
+
+ if (!sna->scrn->vtSema)
+ return;
+
+ for (i = 0; i < sna->mode.num_real_crtc; i++) {
+ xf86CrtcPtr crtc = config->crtc[i];
+
+ assert(to_sna_crtc(crtc) != NULL);
+ if (!crtc->enabled)
+ continue;
+
+ __sna_crtc_set_mode(crtc);
+ }
+}
+
void
sna_mode_close(struct sna *sna)
{