int getDRIDrawableInfoLocked(void *drawHash, Display *display, int screen, Drawable draw, unsigned lockFlags, int drmFD, drm_context_t drmContext, drmAddress sarea, Bool updateInfo, drawableInfo **info, unsigned long infoSize) { drawableInfo *drawInfo; void *res; drm_drawable_t drmDraw=0; volatile drm_sarea_t *pSarea = (drm_sarea_t *) sarea; drm_clip_rect_t *clipFront, *clipBack; int ret; if (drmHashLookup(drawHash, (unsigned long) draw, &res)) { /* * The drawable is unknown to us. Create it and put it in the * hash table. */ DRM_UNLOCK(drmFD, &pSarea->lock, drmContext); if (!uniDRICreateDrawable(display, screen, draw, &drmDraw)) { DRM_LOCK(drmFD, &pSarea->lock, drmContext, lockFlags); return 1; } DRM_LOCK(drmFD, &pSarea->lock, drmContext, lockFlags); drawInfo = (drawableInfo *) malloc(infoSize); if (!drawInfo) return 1; drawInfo->drmDraw = drmDraw; drawInfo->stamp = 0; drawInfo->clipFront = 0; drawInfo->clipBack = 0; drmHashInsert( drawHash, (unsigned long) draw, drawInfo); } else { drawInfo = res; } drawInfo->touched = FALSE; while (!drawInfo->clipFront || drawInfo->stamp != drawStamp(pSarea, drawInfo->index)) { /* * The drawable has been touched since we last got info about it. * obtain new info from the X server. */ drawInfo->touched = TRUE; if (updateInfo || !drawInfo->clipFront) { DRM_UNLOCK(drmFD, &pSarea->lock, drmContext); ret = uniDRIGetDrawableInfo(display, screen, draw, &drawInfo->index, &drawInfo->stamp, &drawInfo->x, &drawInfo->y, &drawInfo->w, &drawInfo->h, &drawInfo->numClipFront, &clipFront, &drawInfo->backX, &drawInfo->backY, &drawInfo->numClipBack, &clipBack); DRM_LIGHT_LOCK(drmFD, &pSarea->lock, drmContext); /* * Error. Probably the drawable is destroyed. Return error and old values. */ if (!ret) { free(drawInfo); drawInfo = NULL; drmHashDelete(drawHash, (unsigned long) draw); DRM_UNLOCK(drmFD, &pSarea->lock, drmContext); uniDRIDestroyDrawable( display, screen, draw); DRM_LOCK(drmFD, &pSarea->lock, drmContext, lockFlags); return 1; } if (drawInfo->stamp != drawStamp(pSarea, drawInfo->index)) { /* * The info is already outdated. Sigh. Have another go. */ XFree(clipFront); XFree(clipBack); continue; } if (drawInfo->clipFront) XFree(drawInfo->clipFront); drawInfo->clipFront = clipFront; if (drawInfo->clipBack) XFree(drawInfo->clipBack); drawInfo->clipBack = clipBack; } else { if (!drawInfo->clipFront) drawInfo->clipFront = (drm_clip_rect_t *) ~0UL; drawInfo->stamp = drawStamp(pSarea, drawInfo->index); } } *info = drawInfo; return 0; }
int __driParseEvents(__DRIcontextPrivate *pcp, __DRIdrawablePrivate *pdp) { __DRIscreenPrivate *psp = pdp->driScreenPriv; __DRIDrawableConfigEvent *dc, *last_dc; __DRIBufferAttachEvent *ba, *last_ba; unsigned int tail, mask, *p, end, total, size, changed; unsigned char *data; size_t rect_size; /* Check for wraparound. */ if (pcp && psp->dri2.buffer->prealloc - pdp->dri2.tail > psp->dri2.buffer->size) { /* If prealloc overlaps into what we just parsed, the * server overwrote it and we have to reset our tail * pointer. */ DRM_UNLOCK(psp->fd, psp->lock, pcp->hHWContext); (*psp->dri2.loader->reemitDrawableInfo)(pdp, &pdp->dri2.tail, pdp->loaderPrivate); DRM_LIGHT_LOCK(psp->fd, psp->lock, pcp->hHWContext); } total = psp->dri2.buffer->head - pdp->dri2.tail; mask = psp->dri2.buffer->size - 1; end = psp->dri2.buffer->head; data = psp->dri2.buffer->data; changed = 0; last_dc = NULL; last_ba = NULL; 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) { /* illegal data, bail out. */ fprintf(stderr, "illegal event size\n"); break; } switch (DRI2_EVENT_TYPE(*p)) { case DRI2_EVENT_DRAWABLE_CONFIG: dc = (__DRIDrawableConfigEvent *) p; if (dc->drawable == pdp->dri2.drawable_id) last_dc = dc; break; case DRI2_EVENT_BUFFER_ATTACH: ba = (__DRIBufferAttachEvent *) p; if (ba->drawable == pdp->dri2.drawable_id && 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); } /* We only care about the most recent drawable config. */ if (last_dc && changed) (*psp->DriverAPI.HandleDrawableConfig)(pdp, pcp, last_dc); /* 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.HandleBufferAttach)(pdp, pcp, last_ba); /* If there was a drawable config event in the buffer and it * changed the size of the window, all buffer auxiliary 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; for ( ; tail != end; tail += size) { ba = (__DRIBufferAttachEvent *) (data + (tail & mask)); size = DRI2_EVENT_SIZE(ba->event_header); if (DRI2_EVENT_TYPE(ba->event_header) != DRI2_EVENT_BUFFER_ATTACH) continue; if (ba->drawable != pdp->dri2.drawable_id) continue; if (last_ba == ba) continue; (*psp->DriverAPI.HandleBufferAttach)(pdp, pcp, ba); changed = 1; } pdp->dri2.tail = tail; return changed || last_ba; }