diff options
author | Kristian Høgsberg <krh@redhat.com> | 2008-03-03 19:04:22 -0500 |
---|---|---|
committer | Kristian Høgsberg <krh@redhat.com> | 2008-03-03 19:16:20 -0500 |
commit | 4f7a75cc8a6cee7763b2d92e3d34858c3de7bd4f (patch) | |
tree | 27a5de065753cf85f2454bece79f1836d76f0de1 | |
parent | 36c26d321b5d17902f0e8f531654dfb2fe2bdd2d (diff) |
[dri2] Optimize event parsing to skip obsolete events.
This also fixes the problem where the X server does multiple resizes before
the DRI driver gets the events. The obsolete buffer attach events then
reference already destroyed buffer objects.
-rw-r--r-- | src/mesa/drivers/dri/common/dri_util.c | 124 |
1 files changed, 84 insertions, 40 deletions
diff --git a/src/mesa/drivers/dri/common/dri_util.c b/src/mesa/drivers/dri/common/dri_util.c index 89c1a099d9..7283653883 100644 --- a/src/mesa/drivers/dri/common/dri_util.c +++ b/src/mesa/drivers/dri/common/dri_util.c @@ -287,8 +287,8 @@ __driUtilUpdateDrawableInfo(__DRIdrawablePrivate *pdp) int __driParseEvents(__DRIscreenPrivate *psp, __DRIdrawablePrivate *pdp) { - __DRIDrawableConfigEvent *dc; - __DRIBufferAttachEvent *ba; + __DRIDrawableConfigEvent *dc, *last_dc; + __DRIBufferAttachEvent *ba, *last_ba; unsigned int tail, mask, *p, end, total, size, changed; unsigned char *data; size_t rect_size; @@ -309,12 +309,14 @@ __driParseEvents(__DRIscreenPrivate *psp, __DRIdrawablePrivate *pdp) total = psp->dri2.buffer->head - pdp->dri2.tail; mask = psp->dri2.buffer->size - 1; - tail = pdp->dri2.tail; end = psp->dri2.buffer->head; data = psp->dri2.buffer->data; + changed = 0; + last_dc = NULL; + last_ba = NULL; - while (tail != end) { + for (tail = pdp->dri2.tail; tail != end; tail += size) { p = (unsigned int *) (data + (tail & mask)); size = DRI2_EVENT_SIZE(*p); if (size > total || (tail & mask) + size > psp->dri2.buffer->size) { @@ -326,50 +328,92 @@ __driParseEvents(__DRIscreenPrivate *psp, __DRIdrawablePrivate *pdp) switch (DRI2_EVENT_TYPE(*p)) { case DRI2_EVENT_DRAWABLE_CONFIG: dc = (__DRIDrawableConfigEvent *) p; - - if (dc->drawable != pdp->hHWDrawable) - break; - - if (pdp->w != dc->width || pdp->h != dc->height) - changed = 1; - - pdp->x = dc->x; - pdp->y = dc->y; - pdp->w = dc->width; - pdp->h = dc->height; - - pdp->backX = 0; - pdp->backY = 0; - pdp->numBackClipRects = 1; - pdp->pBackClipRects[0].x1 = 0; - pdp->pBackClipRects[0].y1 = 0; - pdp->pBackClipRects[0].x2 = pdp->w; - pdp->pBackClipRects[0].y2 = pdp->h; - - pdp->numClipRects = dc->num_rects; - _mesa_free(pdp->pClipRects); - rect_size = dc->num_rects * sizeof dc->rects[0]; - pdp->pClipRects = _mesa_malloc(rect_size); - memcpy(pdp->pClipRects, dc->rects, rect_size); - - if (changed) - (*psp->DriverAPI.UpdateBuffer)(pdp, p); + if (dc->drawable == pdp->hHWDrawable) + last_dc = dc; break; case DRI2_EVENT_BUFFER_ATTACH: ba = (__DRIBufferAttachEvent *) p; + if (ba->drawable == pdp->hHWDrawable && + ba->buffer.attachment == DRI_DRAWABLE_BUFFER_FRONT_LEFT) + last_ba = ba; + break; + } + } + + if (last_dc) { + if (pdp->w != last_dc->width || pdp->h != last_dc->height) + changed = 1; + + pdp->x = last_dc->x; + pdp->y = last_dc->y; + pdp->w = last_dc->width; + pdp->h = last_dc->height; + + pdp->backX = 0; + pdp->backY = 0; + pdp->numBackClipRects = 1; + pdp->pBackClipRects[0].x1 = 0; + pdp->pBackClipRects[0].y1 = 0; + pdp->pBackClipRects[0].x2 = pdp->w; + pdp->pBackClipRects[0].y2 = pdp->h; + + pdp->numClipRects = last_dc->num_rects; + _mesa_free(pdp->pClipRects); + rect_size = last_dc->num_rects * sizeof last_dc->rects[0]; + pdp->pClipRects = _mesa_malloc(rect_size); + memcpy(pdp->pClipRects, last_dc->rects, rect_size); + + if (changed) + (*psp->DriverAPI.UpdateBuffer)(pdp, (unsigned int *) last_dc); + } - if (ba->drawable != pdp->hHWDrawable) - break; + /* Front buffer attachments are special, they typically mean that + * we're rendering to a redirected window (or a child window of a + * redirected window) and that it got resized. Resizing the root + * window on randr events is a special case of this. Other causes + * may be a window transitioning between redirected and + * non-redirected, or a window getting reparented between parents + * with different window pixmaps (eg two redirected windows). + * These events are special in that the X server allocates the + * buffer and that the buffer may be shared by other child + * windows. When our window share the window pixmap with its + * parent, drawable config events doesn't affect the front buffer. + * We only care about the last such event in the buffer; in fact, + * older events will refer to invalid buffer objects.*/ + if (last_ba) + (*psp->DriverAPI.UpdateBuffer)(pdp, (unsigned int *) last_ba); + + /* Like for buffer attachments, we only care about the most recent + * drawable config. */ + if (last_dc) + (*psp->DriverAPI.UpdateBuffer)(pdp, (unsigned int *) last_dc); + + /* If there was a drawable config event in the buffer and it + * changed the size of the window, all buffer auxillary buffer + * attachments prior to that are invalid (as opposed to the front + * buffer case discussed above). In that case we can start + * looking for buffer attachment after the last drawable config + * event. If there is no drawable config event in this batch of + * events, we have to assume that the last batch might have had + * one and process all buffer attach events.*/ + if (last_dc && changed) + tail = (unsigned char *) last_dc - data; + else + tail = pdp->dri2.tail; - (*psp->DriverAPI.UpdateBuffer)(pdp, p); - break; + for ( ; tail != end; tail += size) { + ba = (__DRIBufferAttachEvent *) (data + (tail & mask)); + size = DRI2_EVENT_SIZE(ba->event_header); - default: - break; - } + if (DRI2_EVENT_TYPE(ba->event_header) != DRI2_EVENT_BUFFER_ATTACH) + continue; + if (ba->drawable != pdp->hHWDrawable) + continue; + if (last_ba == ba) + continue; - tail += size; + (*psp->DriverAPI.UpdateBuffer)(pdp, (unsigned int *) ba); } pdp->dri2.tail = tail; |