📄 dri_util.c
字号:
/* $XFree86: xc/lib/GL/dri/dri_util.c,v 1.7 2003/04/28 17:01:25 dawes Exp $ *//** * \file dri_util.c * DRI utility functions. * * This module acts as glue between GLX and the actual hardware driver. A DRI * driver doesn't really \e have to use any of this - it's optional. But, some * useful stuff is done here that otherwise would have to be duplicated in most * drivers. * * Basically, these utility functions take care of some of the dirty details of * screen initialization, context creation, context binding, DRM setup, etc. * * These functions are compiled into each DRI driver so libGL.so knows nothing * about them. */#include <assert.h>#include <stdarg.h>#include <unistd.h>#include <sys/mman.h>#include <stdio.h>#ifndef MAP_FAILED#define MAP_FAILED ((void *)-1)#endif#include "imports.h"#define None 0#include "dri_util.h"#include "drm_sarea.h"#include "utils.h"#ifndef GLX_OML_sync_controltypedef GLboolean ( * PFNGLXGETMSCRATEOMLPROC) (__DRIdrawable *drawable, int32_t *numerator, int32_t *denominator);#endif/** * This is just a token extension used to signal that the driver * supports setting a read drawable. */const __DRIextension driReadDrawableExtension = { __DRI_READ_DRAWABLE, __DRI_READ_DRAWABLE_VERSION};/** * Print message to \c stderr if the \c LIBGL_DEBUG environment variable * is set. * * Is called from the drivers. * * \param f \c printf like format string. */void__driUtilMessage(const char *f, ...){ va_list args; if (getenv("LIBGL_DEBUG")) { fprintf(stderr, "libGL error: \n"); va_start(args, f); vfprintf(stderr, f, args); va_end(args); fprintf(stderr, "\n"); }}GLintdriIntersectArea( drm_clip_rect_t rect1, drm_clip_rect_t rect2 ){ if (rect2.x1 > rect1.x1) rect1.x1 = rect2.x1; if (rect2.x2 < rect1.x2) rect1.x2 = rect2.x2; if (rect2.y1 > rect1.y1) rect1.y1 = rect2.y1; if (rect2.y2 < rect1.y2) rect1.y2 = rect2.y2; if (rect1.x1 > rect1.x2 || rect1.y1 > rect1.y2) return 0; return (rect1.x2 - rect1.x1) * (rect1.y2 - rect1.y1);}/*****************************************************************//** \name Context (un)binding functions *//*****************************************************************//*@{*//** * Unbind context. * * \param scrn the screen. * \param gc context. * * \return \c GL_TRUE on success, or \c GL_FALSE on failure. * * \internal * This function calls __DriverAPIRec::UnbindContext, and then decrements * __DRIdrawablePrivateRec::refcount which must be non-zero for a successful * return. * * While casting the opaque private pointers associated with the parameters * into their respective real types it also assures they are not \c NULL. */static int driUnbindContext(__DRIcontext *pcp){ __DRIscreen *psp; __DRIdrawable *pdp; __DRIdrawable *prp; /* ** Assume error checking is done properly in glXMakeCurrent before ** calling driUnbindContext. */ if (pcp == NULL) return GL_FALSE; psp = pcp->driScreenPriv; pdp = pcp->driDrawablePriv; prp = pcp->driReadablePriv; /* Let driver unbind drawable from context */ (*psp->DriverAPI.UnbindContext)(pcp); if (pdp->refcount == 0) { /* ERROR!!! */ return GL_FALSE; } pdp->refcount--; if (prp != pdp) { if (prp->refcount == 0) { /* ERROR!!! */ return GL_FALSE; } prp->refcount--; } /* XXX this is disabled so that if we call SwapBuffers on an unbound * window we can determine the last context bound to the window and * use that context's lock. (BrianP, 2-Dec-2000) */#if 0 /* Unbind the drawable */ pcp->driDrawablePriv = NULL; pdp->driContextPriv = &psp->dummyContextPriv;#endif return GL_TRUE;}/** * This function takes both a read buffer and a draw buffer. This is needed * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent * function. */static int driBindContext(__DRIcontext *pcp, __DRIdrawable *pdp, __DRIdrawable *prp){ __DRIscreenPrivate *psp = pcp->driScreenPriv; /* ** Assume error checking is done properly in glXMakeCurrent before ** calling driBindContext. */ if (pcp == NULL || pdp == None || prp == None) return GL_FALSE; /* Bind the drawable to the context */ pcp->driDrawablePriv = pdp; pcp->driReadablePriv = prp; pdp->driContextPriv = pcp; pdp->refcount++; if ( pdp != prp ) { prp->refcount++; } /* ** Now that we have a context associated with this drawable, we can ** initialize the drawable information if has not been done before. */ if (psp->dri2.enabled) { __driParseEvents(pcp, pdp); __driParseEvents(pcp, prp); } else { if (!pdp->pStamp || *pdp->pStamp != pdp->lastStamp) { DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); __driUtilUpdateDrawableInfo(pdp); DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); } if ((pdp != prp) && (!prp->pStamp || *prp->pStamp != prp->lastStamp)) { DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); __driUtilUpdateDrawableInfo(prp); DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); } } /* Call device-specific MakeCurrent */ (*psp->DriverAPI.MakeCurrent)(pcp, pdp, prp); return GL_TRUE;}/*@}*//*****************************************************************//** \name Drawable handling functions *//*****************************************************************//*@{*//** * Update private drawable information. * * \param pdp pointer to the private drawable information to update. * * This function basically updates the __DRIdrawablePrivate struct's * cliprect information by calling \c __DRIinterfaceMethods::getDrawableInfo. * This is usually called by the DRI_VALIDATE_DRAWABLE_INFO macro which * compares the __DRIdrwablePrivate pStamp and lastStamp values. If * the values are different that means we have to update the clipping * info. */void__driUtilUpdateDrawableInfo(__DRIdrawablePrivate *pdp){ __DRIscreenPrivate *psp = pdp->driScreenPriv; __DRIcontextPrivate *pcp = pdp->driContextPriv; if (!pcp || ((pdp != pcp->driDrawablePriv) && (pdp != pcp->driReadablePriv))) { /* ERROR!!! * ...but we must ignore it. There can be many contexts bound to a * drawable. */ } if (pdp->pClipRects) { _mesa_free(pdp->pClipRects); pdp->pClipRects = NULL; } if (pdp->pBackClipRects) { _mesa_free(pdp->pBackClipRects); pdp->pBackClipRects = NULL; } DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); if (! (*psp->getDrawableInfo->getDrawableInfo)(pdp, &pdp->index, &pdp->lastStamp, &pdp->x, &pdp->y, &pdp->w, &pdp->h, &pdp->numClipRects, &pdp->pClipRects, &pdp->backX, &pdp->backY, &pdp->numBackClipRects, &pdp->pBackClipRects, pdp->loaderPrivate)) { /* Error -- eg the window may have been destroyed. Keep going * with no cliprects. */ pdp->pStamp = &pdp->lastStamp; /* prevent endless loop */ pdp->numClipRects = 0; pdp->pClipRects = NULL; pdp->numBackClipRects = 0; pdp->pBackClipRects = NULL; } else pdp->pStamp = &(psp->pSAREA->drawableTable[pdp->index].stamp); DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);}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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -