diff options
Diffstat (limited to 'src/sna')
-rw-r--r-- | src/sna/kgem.c | 25 | ||||
-rw-r--r-- | src/sna/sna.h | 2 | ||||
-rw-r--r-- | src/sna/sna_display.c | 46 |
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) { |