summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2013-07-29 14:44:51 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2013-07-29 15:21:19 +0100
commit5751b9f1f5beb943db8cb5d260379ae39eb18db4 (patch)
treec0c0d947cb0009d30be9cb6e4ec74f8c84a1ae37 /src
parent8619db7224f5c3ec417a1d00a68e981549366adc (diff)
sna/dri: Prevent stale DRI buffers from a NULL dereference
If the DRI buffer is stale, the drawable may have been recreated and no longer be associated with DRI. In this case, the pixmap may not be on the GPU, so just subsitute the client's old bo and hope the it catches up and does a GetBuffers in the near future. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'src')
-rw-r--r--src/sna/sna_dri.c73
1 files changed, 46 insertions, 27 deletions
diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c
index b6a605b7..8d0b424d 100644
--- a/src/sna/sna_dri.c
+++ b/src/sna/sna_dri.c
@@ -672,20 +672,15 @@ __sna_dri_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
* the risk of copying around invalid data. So either you may not
* see the results of the copy, or you may see the wrong pixels.
* Either way you eventually lose.
+ *
+ * We also have to be careful in case that the stale buffers are
+ * now attached to invalid (non-DRI) pixmaps.
*/
assert(dst->attachment == DRI2BufferFrontLeft ||
src->attachment == DRI2BufferFrontLeft);
assert(dst->attachment != src->attachment);
- src_bo = src_priv->bo;
- if (src->attachment == DRI2BufferFrontLeft)
- src_bo = sna_pixmap_get_bo(pixmap);
-
- dst_bo = dst_priv->bo;
- if (dst->attachment == DRI2BufferFrontLeft)
- dst_bo = sna_pixmap_get_bo(pixmap);
-
/* Copy the minimum of the Drawable / src / dst extents */
w = draw->width;
if ((src_priv->size & 0xffff) < w)
@@ -717,16 +712,6 @@ __sna_dri_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
return NULL;
}
- if (!wedged(sna)) {
- if (dst->attachment != DRI2BufferFrontLeft)
- sync = false;
- if (sync)
- sync = sna_pixmap_is_scanout(sna, pixmap);
-
- sna_dri_select_mode(sna, dst_bo, src_bo, sync);
- } else
- sync = false;
-
sx = sy = dx = dy = 0;
if (dst->attachment == DRI2BufferFrontLeft) {
sx = -draw->x;
@@ -756,15 +741,6 @@ __sna_dri_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
region = &clip;
}
- if (sync) {
- xf86CrtcPtr crtc;
-
- crtc = sna_covering_crtc(sna->scrn, &clip.extents, NULL);
- sync = crtc &&
- sna_wait_for_scanline(sna, pixmap, crtc,
- &clip.extents);
- }
-
if (get_drawable_deltas(draw, pixmap, &tx, &ty)) {
if (dst->attachment == DRI2BufferFrontLeft) {
pixman_region_translate(region ?: &clip, tx, ty);
@@ -775,7 +751,50 @@ __sna_dri_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
sy += ty;
}
}
+ } else
+ sync = false;
+
+ src_bo = src_priv->bo;
+ if (src->attachment == DRI2BufferFrontLeft) {
+ struct sna_pixmap *priv;
+
+ priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ);
+ if (priv)
+ src_bo = priv->gpu_bo;
}
+
+ dst_bo = dst_priv->bo;
+ if (dst->attachment == DRI2BufferFrontLeft) {
+ struct sna_pixmap *priv;
+ unsigned int flags;
+
+ flags = MOVE_WRITE;
+ if (clip.data ||
+ clip.extents.x1 > 0 ||
+ clip.extents.x2 < pixmap->drawable.width ||
+ clip.extents.y1 > 0 ||
+ clip.extents.y2 < pixmap->drawable.height)
+ flags |= MOVE_READ;
+
+ priv = sna_pixmap_move_to_gpu(pixmap, flags);
+ if (priv)
+ dst_bo = priv->gpu_bo;
+ } else
+ sync = false;
+
+ if (!wedged(sna)) {
+ xf86CrtcPtr crtc;
+
+ crtc = NULL;
+ if (sync && sna_pixmap_is_scanout(sna, pixmap))
+ crtc = sna_covering_crtc(sna->scrn, &clip.extents, NULL);
+ sna_dri_select_mode(sna, dst_bo, src_bo, crtc != NULL);
+
+ sync = (crtc != NULL&&
+ sna_wait_for_scanline(sna, pixmap, crtc,
+ &clip.extents));
+ }
+
if (dst->attachment == DRI2BufferFrontLeft)
damage(pixmap, region);
if (region) {