summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMario Kleiner <mario.kleiner@tuebingen.mpg.de>2012-02-16 00:45:19 +0100
committerBen Skeggs <bskeggs@redhat.com>2012-03-06 08:12:57 +1000
commit5ede4538366a352aa9726560f8d42e85df4aec82 (patch)
tree3078cf8f886f766d2027971c6d7365db8ed462be
parent6fdf60b7288d49f889c80705aabc1db3bc327ba3 (diff)
dri2: Update front buffer pixmap and name before exchanging buffers
Buffer exchange assumes that the front buffer pixmap and name information is accurate. That may not be the case eg. if the window has been (un)redirected since the buffer was created. This is a translation to nouveau of a fix that was originally developed by Ville Syrjala <syrjala@sci.fi> for the ati/radeon ddx to fix the same bug there. See thread at: http://lists.x.org/archives/xorg-devel/2011-May/021908.html Fixes FDO bug #35452. Signed-off-by: Mario Kleiner <mario.kleiner@tuebingen.mpg.de> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--src/nouveau_dri2.c45
1 files changed, 42 insertions, 3 deletions
diff --git a/src/nouveau_dri2.c b/src/nouveau_dri2.c
index 2908e56..8608678 100644
--- a/src/nouveau_dri2.c
+++ b/src/nouveau_dri2.c
@@ -149,6 +149,35 @@ struct nouveau_dri2_vblank_state {
};
static Bool
+update_front(DrawablePtr draw, DRI2BufferPtr front)
+{
+ int r;
+ PixmapPtr pixmap;
+ struct nouveau_dri2_buffer *nvbuf = nouveau_dri2_buffer(front);
+
+ if (draw->type == DRAWABLE_PIXMAP)
+ pixmap = (PixmapPtr)draw;
+ else
+ pixmap = (*draw->pScreen->GetWindowPixmap)((WindowPtr)draw);
+
+ pixmap->refcnt++;
+
+ exaMoveInPixmap(pixmap);
+ r = nouveau_bo_handle_get(nouveau_pixmap_bo(pixmap), &front->name);
+ if (r) {
+ (*draw->pScreen->DestroyPixmap)(pixmap);
+ return FALSE;
+ }
+
+ (*draw->pScreen->DestroyPixmap)(nvbuf->ppix);
+ front->pitch = pixmap->devKind;
+ front->cpp = pixmap->drawable.bitsPerPixel / 8;
+ nvbuf->ppix = pixmap;
+
+ return TRUE;
+}
+
+static Bool
can_exchange(DrawablePtr draw, PixmapPtr dst_pix, PixmapPtr src_pix)
{
ScrnInfoPtr scrn = xf86Screens[draw->pScreen->myNum];
@@ -234,13 +263,14 @@ nouveau_dri2_finish_swap(DrawablePtr draw, unsigned int frame,
{
ScrnInfoPtr scrn = xf86Screens[draw->pScreen->myNum];
NVPtr pNv = NVPTR(scrn);
- PixmapPtr dst_pix = nouveau_dri2_buffer(s->dst)->ppix;
+ PixmapPtr dst_pix;
PixmapPtr src_pix = nouveau_dri2_buffer(s->src)->ppix;
- struct nouveau_bo *dst_bo = nouveau_pixmap_bo(dst_pix);
+ struct nouveau_bo *dst_bo;
struct nouveau_bo *src_bo = nouveau_pixmap_bo(src_pix);
struct nouveau_channel *chan = pNv->chan;
RegionRec reg;
int type, ret;
+ Bool front_updated;
REGION_INIT(0, &reg, (&(BoxRec){ 0, 0, draw->width, draw->height }), 0);
REGION_TRANSLATE(0, &reg, draw->x, draw->y);
@@ -257,6 +287,15 @@ nouveau_dri2_finish_swap(DrawablePtr draw, unsigned int frame,
if (ref_crtc_hw_id & 1)
ref_crtc_hw_id = 1;
+ /* Update frontbuffer pixmap and name: Could have changed due to
+ * window (un)redirection as part of compositing.
+ */
+ front_updated = update_front(draw, s->dst);
+
+ /* Assign frontbuffer pixmap, after update in update_front() */
+ dst_pix = nouveau_dri2_buffer(s->dst)->ppix;
+ dst_bo = nouveau_pixmap_bo(dst_pix);
+
/* Throttle on the previous frame before swapping */
nouveau_bo_map(dst_bo, NOUVEAU_BO_RD);
nouveau_bo_unmap(dst_bo);
@@ -275,7 +314,7 @@ nouveau_dri2_finish_swap(DrawablePtr draw, unsigned int frame,
FIRE_RING(chan);
}
- if (can_exchange(draw, dst_pix, src_pix)) {
+ if (front_updated && can_exchange(draw, dst_pix, src_pix)) {
type = DRI2_EXCHANGE_COMPLETE;
DamageRegionAppend(draw, &reg);