diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2012-03-30 22:51:21 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2012-03-30 23:01:21 +0100 |
commit | cc20c45aa0ca15720510668d6918bf3c99104626 (patch) | |
tree | 8530e45efcf170eda2d25adf7dce5a3696ba6393 | |
parent | 305734ebdf3d51c084cfbee8804b6c60b1f03a98 (diff) |
sna: Minimise the risk of hotplug hangs by checking fb before vsync
Everytime we issue a MI_WAIT_FOR_EVENT on a scan-line from userspace we
run the risk of that pipe being disable before we submit a batch. As the
pipe is then disabled or configured differently, we encounter an
indefinite wait and trigger a GPU hang.
To minimise the risk of a hotplug event being detected and submitting a
vsynced batch prior to noticing the removal of the pipe, perform an
explicit query of the current CRTC and delete the wait if we spot that
our framebuffer is no longer attached. This is about as good as we can
achieve without extra help from the kernel.
Reported-by: Francis Leblanc <Francis.Leblanc-Lebeau@verint.com>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=45413 (and others)
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r-- | src/sna/kgem.h | 1 | ||||
-rw-r--r-- | src/sna/sna.h | 1 | ||||
-rw-r--r-- | src/sna/sna_display.c | 30 | ||||
-rw-r--r-- | src/sna/sna_dri.c | 18 | ||||
-rw-r--r-- | src/sna/sna_video_textured.c | 5 |
5 files changed, 39 insertions, 16 deletions
diff --git a/src/sna/kgem.h b/src/sna/kgem.h index 27e0e040..e52645ca 100644 --- a/src/sna/kgem.h +++ b/src/sna/kgem.h @@ -141,6 +141,7 @@ struct kgem { uint16_t nexec; uint16_t nreloc; uint16_t nfence; + uint16_t wait; uint16_t max_batch_size; uint32_t flush:1; diff --git a/src/sna/sna.h b/src/sna/sna.h index 7a1e2f63..308e3298 100644 --- a/src/sna/sna.h +++ b/src/sna/sna.h @@ -363,6 +363,7 @@ extern xf86CrtcPtr sna_covering_crtc(ScrnInfoPtr scrn, extern bool sna_wait_for_scanline(struct sna *sna, PixmapPtr pixmap, xf86CrtcPtr crtc, const BoxRec *clip); +extern bool sna_crtc_is_bound(struct sna *sna, xf86CrtcPtr crtc); Bool sna_dri_open(struct sna *sna, ScreenPtr pScreen); void sna_dri_wakeup(struct sna *sna); diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c index f413ac1e..ef3b0f96 100644 --- a/src/sna/sna_display.c +++ b/src/sna/sna_display.c @@ -2102,6 +2102,7 @@ static void sna_emit_wait_for_scanline_gen6(struct sna *sna, b[1] = pipe; b[2] = y2 - 1; b[3] = MI_WAIT_FOR_EVENT | event; + sna->kgem.wait = sna->kgem.nbatch + 3; kgem_advance_batch(&sna->kgem, 4); } @@ -2131,6 +2132,7 @@ static void sna_emit_wait_for_scanline_gen4(struct sna *sna, b[2] = b[0] = MI_LOAD_SCAN_LINES_INCL | pipe << 20; b[3] = b[1] = (y1 << 16) | (y2-1); b[4] = MI_WAIT_FOR_EVENT | event; + sna->kgem.wait = sna->kgem.nbatch + 4; kgem_advance_batch(&sna->kgem, 5); } @@ -2158,6 +2160,7 @@ static void sna_emit_wait_for_scanline_gen2(struct sna *sna, b[4] = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW; else b[4] = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW; + sna->kgem.wait = sna->kgem.nbatch + 4; kgem_advance_batch(&sna->kgem, 5); } @@ -2171,21 +2174,15 @@ sna_wait_for_scanline(struct sna *sna, Bool full_height; int y1, y2, pipe; + assert(crtc); + assert(sna_crtc_on(crtc)); + assert(pixmap_is_scanout(pixmap)); + /* XXX WAIT_EVENT is still causing hangs on SNB */ if (sna->kgem.gen >= 60) return false; - if (!pixmap_is_scanout(pixmap)) - return false; - - if (crtc == NULL) { - crtc = sna_covering_crtc(sna->scrn, clip, NULL, &crtc_box); - if (crtc == NULL) - return false; - } else - sna_crtc_box(crtc, &crtc_box); - assert(sna_crtc_on(crtc)); - + sna_crtc_box(crtc, &crtc_box); if (crtc->transform_in_use) { box = *clip; pixman_f_transform_bounds(&crtc->f_framebuffer_to_crtc, &box); @@ -2227,3 +2224,14 @@ sna_wait_for_scanline(struct sna *sna, return true; } + +bool sna_crtc_is_bound(struct sna *sna, xf86CrtcPtr crtc) +{ + struct drm_mode_crtc mode; + + mode.crtc_id = crtc_id(crtc->driver_private); + if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode)) + return false; + + return mode.mode_valid && sna->mode.fb_id == mode.fb_id; +} diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c index 95ec07e0..afec8316 100644 --- a/src/sna/sna_dri.c +++ b/src/sna/sna_dri.c @@ -400,6 +400,7 @@ sna_dri_copy_to_front(struct sna *sna, DrawablePtr draw, RegionPtr region, PixmapPtr pixmap = get_drawable_pixmap(draw); pixman_region16_t clip; bool flush = false; + xf86CrtcPtr crtc; BoxRec box, *boxes; int16_t dx, dy; int n; @@ -442,9 +443,15 @@ sna_dri_copy_to_front(struct sna *sna, DrawablePtr draw, RegionPtr region, return; } - if (pixmap == sna->front && sync) - flush = sna_wait_for_scanline(sna, pixmap, NULL, - ®ion->extents); + if (pixmap == sna->front && sync) { + BoxRec crtc_box; + + crtc = sna_covering_crtc(sna->scrn, ®ion->extents, + NULL, &crtc_box); + if (crtc) + flush = sna_wait_for_scanline(sna, pixmap, crtc, + ®ion->extents); + } get_drawable_deltas(draw, pixmap, &dx, &dy); } @@ -482,8 +489,11 @@ sna_dri_copy_to_front(struct sna *sna, DrawablePtr draw, RegionPtr region, boxes, n); DBG(("%s: flushing? %d\n", __FUNCTION__, flush)); - if (flush) /* STAT! */ + if (flush) { /* STAT! */ + if (!sna_crtc_is_bound(sna, crtc)) + sna->kgem.batch[sna->kgem.wait] = 0; kgem_submit(&sna->kgem); + } pixman_region_translate(region, dx, dy); DamageRegionAppend(&pixmap->drawable, region); diff --git a/src/sna/sna_video_textured.c b/src/sna/sna_video_textured.c index a71751c6..b740b6a0 100644 --- a/src/sna/sna_video_textured.c +++ b/src/sna/sna_video_textured.c @@ -306,8 +306,11 @@ sna_video_textured_put_image(ScrnInfoPtr scrn, /* Push the frame to the GPU as soon as possible so * we can hit the next vsync. */ - if (flush) + if (flush) { + if (!sna_crtc_is_bound(sna, crtc)) + sna->kgem.batch[sna->kgem.wait] = 0; kgem_submit(&sna->kgem); + } return ret; } |