예제 #1
0
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;
}
예제 #2
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;
}