From 7da5705b090d9c97a9b765d786c5e89afe9d1f25 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Kristian=20H=C3=B8gsberg?= Date: Mon, 14 Jan 2008 18:31:05 -0500 Subject: [PATCH] Add new DRI2 infrastructure. --- include/GL/internal/dri_interface.h | 38 ++++- include/GL/internal/dri_sarea.h | 131 +++++++++++++++ src/mesa/drivers/dri/common/dri_util.c | 215 +++++++++++++++++++++++-- src/mesa/drivers/dri/common/dri_util.h | 26 +++ 4 files changed, 390 insertions(+), 20 deletions(-) create mode 100644 include/GL/internal/dri_sarea.h diff --git a/include/GL/internal/dri_interface.h b/include/GL/internal/dri_interface.h index 1b637afaf38..50f1d1a765c 100644 --- a/include/GL/internal/dri_interface.h +++ b/include/GL/internal/dri_interface.h @@ -230,12 +230,6 @@ struct __DRItexOffsetExtensionRec { #define __DRI_REAL_MAKE_VERSION(name, version) name ## _ ## version #define __DRI_MAKE_VERSION(name, version) __DRI_REAL_MAKE_VERSION(name, version) -#define __DRI_CREATE_NEW_SCREEN \ - __DRI_MAKE_VERSION(__driCreateNewScreen, __DRI_INTERFACE_VERSION) - -#define __DRI_CREATE_NEW_SCREEN_STRING \ - __DRI_STRINGIFY(__DRI_CREATE_NEW_SCREEN) - /** * \name Functions and data provided by the driver. */ @@ -250,9 +244,32 @@ typedef void *(CREATENEWSCREENFUNC)(int scr, __DRIscreen *psc, const __DRIinterfaceMethods * interface, __GLcontextModes ** driver_modes); typedef CREATENEWSCREENFUNC* PFNCREATENEWSCREENFUNC; + +#define __DRI_CREATE_NEW_SCREEN \ + __DRI_MAKE_VERSION(__driCreateNewScreen, __DRI_INTERFACE_VERSION) + +#define __DRI_CREATE_NEW_SCREEN_STRING \ + __DRI_STRINGIFY(__DRI_CREATE_NEW_SCREEN) + extern CREATENEWSCREENFUNC __DRI_CREATE_NEW_SCREEN; +/* DRI2 Entry point */ + +typedef void *(__DRI2_CREATE_NEW_SCREEN_FUNC)(int scr, __DRIscreen *psc, + const __DRIversion * ddx_version, const __DRIversion * dri_version, + const __DRIversion * drm_version, int fd, + unsigned int sarea_handle, + const __DRIinterfaceMethods * interface, + __GLcontextModes ** driver_modes); +#define __DRI2_CREATE_NEW_SCREEN \ + __DRI_MAKE_VERSION(__dri2CreateNewScreen, __DRI_INTERFACE_VERSION) + +#define __DRI2_CREATE_NEW_SCREEN_STRING \ + __DRI_STRINGIFY(__DRI2_CREATE_NEW_SCREEN) + +extern __DRI2_CREATE_NEW_SCREEN_FUNC __DRI2_CREATE_NEW_SCREEN; + /** * XML document describing the configuration options supported by the @@ -357,6 +374,15 @@ struct __DRIinterfaceMethodsRec { int x, int y, drm_clip_rect_t *rects, int num_rects, GLboolean front_buffer); + + /** + * Ping the windowing system to get it to reemit info for the + * specified drawable in the DRI2 event buffer. + * + * \param draw the drawable for which to request info + */ + void (*reemitDrawableInfo)(__DRIdrawable *draw); + }; diff --git a/include/GL/internal/dri_sarea.h b/include/GL/internal/dri_sarea.h new file mode 100644 index 00000000000..ff4ff1021c4 --- /dev/null +++ b/include/GL/internal/dri_sarea.h @@ -0,0 +1,131 @@ +/* + * Copyright 2007 Red Hat, Inc + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef DRI_SAREA_H +#define DRI_SAREA_H + +#include + +/* The DRI2 SAREA holds a list of self-describing blocks. Each block + * is 8 byte aligned and has a common 32-bit header word. The upper + * 16 bits describe the type of the block and the lower 16 bits the + * size. DRI2 only defines a couple of blocks and allows drivers to + * define driver specific blocks using type codes from 0x8000 and up. + * The type code 0x0000 defines the end of the sarea. */ + +#define DRI2_SAREA_BLOCK_HEADER(type, size) (((type) << 16) | (size)) +#define DRI2_SAREA_BLOCK_TYPE(b) ((b) >> 16) +#define DRI2_SAREA_BLOCK_SIZE(b) ((b) & 0xffff) +#define DRI2_SAREA_BLOCK_NEXT(p) \ + ((void *) ((unsigned char *) (p) + \ + DRI2_SAREA_BLOCK_SIZE(*(unsigned int *) p))) + +#define DRI2_SAREA_BLOCK_END 0x0000 +#define DRI2_SAREA_BLOCK_LOCK 0x0001 +#define DRI2_SAREA_BLOCK_EVENT_BUFFER 0x0002 + +/* Chipset specific blocks start at 0x8000, 0xffff is reserved. */ + +typedef struct __DRILock __DRILock; +typedef struct __DRIEventBuffer __DRIEventBuffer; +typedef struct __DRIDrawableBuffer __DRIDrawableBuffer; +typedef struct __DRIDrawableConfigEvent __DRIDrawableConfigEvent; +typedef struct __DRIBufferAttachEvent __DRIBufferAttachEvent; + +struct __DRILock { + unsigned int block_header; + drm_hw_lock_t lock; +}; + +struct __DRIEventBuffer { + unsigned int block_header; + unsigned int head; /* last valid event */ + unsigned int prealloc; /* event currently being written */ + unsigned int size; /* size of data */ + unsigned char data[0]; +}; + +enum { + /* the four standard color buffers */ + DRI_DRAWABLE_BUFFER_FRONT_LEFT = 0, + DRI_DRAWABLE_BUFFER_BACK_LEFT = 1, + DRI_DRAWABLE_BUFFER_FRONT_RIGHT = 2, + DRI_DRAWABLE_BUFFER_BACK_RIGHT = 3, + /* optional aux buffer */ + DRI_DRAWABLE_BUFFER_AUX0 = 4, + DRI_DRAWABLE_BUFFER_AUX1 = 5, + DRI_DRAWABLE_BUFFER_AUX2 = 6, + DRI_DRAWABLE_BUFFER_AUX3 = 7, + DRI_DRAWABLE_BUFFER_DEPTH = 8, + DRI_DRAWABLE_BUFFER_STENCIL = 9, + DRI_DRAWABLE_BUFFER_ACCUM = 10, + /* generic renderbuffers */ + DRI_DRAWABLE_BUFFER_COLOR0 = 11, + DRI_DRAWABLE_BUFFER_COLOR1 = 12, + DRI_DRAWABLE_BUFFER_COLOR2 = 13, + DRI_DRAWABLE_BUFFER_COLOR3 = 14, + DRI_DRAWABLE_BUFFER_COLOR4 = 15, + DRI_DRAWABLE_BUFFER_COLOR5 = 16, + DRI_DRAWABLE_BUFFER_COLOR6 = 17, + DRI_DRAWABLE_BUFFER_COLOR7 = 18, + DRI_DRAWABLE_BUFFER_COUNT = 19 +}; + +struct __DRIDrawableBuffer { + unsigned int attachment; + unsigned int handle; + unsigned int pitch; + unsigned short cpp; + + /* Upper 8 bits are driver specific, lower 8 bits generic. The + * bits can inidicate buffer properties such as tiled, swizzled etc. */ + unsigned short flags; +}; + +#define DRI2_EVENT_HEADER(type, size) (((type) << 16) | (size)) +#define DRI2_EVENT_TYPE(b) ((b) >> 16) +#define DRI2_EVENT_SIZE(b) ((b) & 0xffff) + +#define DRI2_EVENT_PAD 0x0000 +#define DRI2_EVENT_DRAWABLE_CONFIG 0x0001 +#define DRI2_EVENT_BUFFER_ATTACH 0x0002 + +struct __DRIDrawableConfigEvent { + unsigned int event_header; + drm_drawable_t drawable; + short x; + short y; + unsigned int width; + unsigned int height; + unsigned int num_rects; + struct drm_clip_rect rects[0]; +}; + +struct __DRIBufferAttachEvent { + unsigned int event_header; + drm_drawable_t drawable; + __DRIDrawableBuffer buffer; +}; + +#endif /* DRI_SAREA_H */ diff --git a/src/mesa/drivers/dri/common/dri_util.c b/src/mesa/drivers/dri/common/dri_util.c index 797b2c66f5e..01751582faf 100644 --- a/src/mesa/drivers/dri/common/dri_util.c +++ b/src/mesa/drivers/dri/common/dri_util.c @@ -205,16 +205,22 @@ static GLboolean driBindContext(__DRIcontext * ctx, ** Now that we have a context associated with this drawable, we can ** initialize the drawable information if has not been done before. */ - 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); + if (psp->dri2.enabled) { + __driParseEvents(psp, pdp); + __driParseEvents(psp, 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 */ @@ -302,6 +308,103 @@ __driUtilUpdateDrawableInfo(__DRIdrawablePrivate *pdp) } +int +__driParseEvents(__DRIscreenPrivate *psp, __DRIdrawablePrivate *pdp) +{ + __DRIDrawableConfigEvent *dc; + __DRIBufferAttachEvent *ba; + unsigned int tail, mask, *p, end, total, size, changed; + unsigned char *data; + size_t rect_size; + __DRIcontextPrivate *pcp = pdp->driContextPriv; + + if (pcp == NULL) + return 0; + + /* Check for wraparound. */ + if (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); + (*dri_interface->reemitDrawableInfo)(pdp->pdraw); + DRM_LIGHT_LOCK(psp->fd, psp->lock, pcp->hHWContext); + } + + 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; + + while (tail != end) { + 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->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); + break; + + case DRI2_EVENT_BUFFER_ATTACH: + ba = (__DRIBufferAttachEvent *) p; + + if (ba->drawable != pdp->hHWDrawable) + break; + + (*psp->DriverAPI.UpdateBuffer)(pdp, p); + break; + + default: + break; + } + + tail += size; + } + + pdp->dri2.tail = tail; + + /* FIXME: Return whether we changed anything. This check always + * returns true if we received events, but we could refine the + * check to only return TRUE if the drawable actually changed. */ + + return total > 0; +} + /*@}*/ /*****************************************************************/ @@ -497,6 +600,11 @@ static void *driCreateNewDrawable(__DRIscreen *screen, pdp->swapBuffers = psp->DriverAPI.SwapBuffers; + if (psp->dri2.enabled) { + pdp->dri2.tail = 0; + pdp->pBackClipRects = _mesa_malloc(sizeof *pdp->pBackClipRects); + } + return (void *) pdp; } @@ -596,7 +704,7 @@ driCreateNewContext(__DRIscreen *screen, const __GLcontextModes *modes, * context. */ - if (!psp->dummyContextPriv.driScreenPriv) { + if (!psp->dri2.enabled && !psp->dummyContextPriv.driScreenPriv) { psp->dummyContextPriv.hHWContext = psp->pSAREA->dummy_context; psp->dummyContextPriv.driScreenPriv = psp; psp->dummyContextPriv.driDrawablePriv = NULL; @@ -655,15 +763,19 @@ static void driDestroyScreen(__DRIscreen *screen) if (psp->DriverAPI.DestroyScreen) (*psp->DriverAPI.DestroyScreen)(psp); - (void)drmUnmap((drmAddress)psp->pSAREA, SAREA_MAX); - (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize); - (void)drmCloseOnce(psp->fd); + if (psp->dri2.enabled) { + drmBOUnmap(psp->fd, &psp->dri2.sareaBO); + drmBOUnreference(psp->fd, &psp->dri2.sareaBO); + } else { + (void)drmUnmap((drmAddress)psp->pSAREA, SAREA_MAX); + (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize); + (void)drmCloseOnce(psp->fd); + } _mesa_free(psp); } } - /** * This is the bootstrap function for the driver. libGL supplies all of the * requisite information about the system, and the driver initializes itself. @@ -730,6 +842,7 @@ void * __DRI_CREATE_NEW_SCREEN( int scrn, __DRIscreen *psc, psp->dri_version = *dri_version; psp->pSAREA = pSAREA; + psp->lock = (drmLock *) &psp->pSAREA->lock; psp->pFB = frame_buffer->base; psp->fbSize = frame_buffer->size; @@ -743,6 +856,7 @@ void * __DRI_CREATE_NEW_SCREEN( int scrn, __DRIscreen *psc, psp->extensions = emptyExtensionList; psp->fd = fd; psp->myNum = scrn; + psp->dri2.enabled = GL_FALSE; /* ** Do not init dummy context here; actual initialization will be @@ -765,6 +879,79 @@ void * __DRI_CREATE_NEW_SCREEN( int scrn, __DRIscreen *psc, return psp; } +PUBLIC void * +__DRI2_CREATE_NEW_SCREEN(int scrn, __DRIscreen *psc, + const __DRIversion * ddx_version, + const __DRIversion * dri_version, + const __DRIversion * drm_version, + int fd, + unsigned int sarea_handle, + const __DRIinterfaceMethods * interface, + __GLcontextModes ** driver_modes) +{ + __DRIscreenPrivate *psp; + static const __DRIextension *emptyExtensionList[] = { NULL }; + dri_interface = interface; + unsigned int *p; + + psp = _mesa_malloc(sizeof(*psp)); + if (!psp) + return NULL; + + psp->psc = psc; + + psp->drm_version = *drm_version; + psp->ddx_version = *ddx_version; + psp->dri_version = *dri_version; + psp->extensions = emptyExtensionList; + psp->fd = fd; + psp->myNum = scrn; + psp->dri2.enabled = GL_TRUE; + + if (drmBOReference(psp->fd, sarea_handle, &psp->dri2.sareaBO)) { + fprintf(stderr, "Failed to reference DRI2 sarea BO\n"); + _mesa_free(psp); + return NULL; + } + + if (drmBOMap(psp->fd, &psp->dri2.sareaBO, + DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, &psp->dri2.sarea)) { + drmBOUnreference(psp->fd, &psp->dri2.sareaBO); + _mesa_free(psp); + return NULL; + } + + p = psp->dri2.sarea; + while (DRI2_SAREA_BLOCK_TYPE(*p)) { + switch (DRI2_SAREA_BLOCK_TYPE(*p)) { + case DRI2_SAREA_BLOCK_LOCK: + psp->dri2.lock = (__DRILock *) p; + break; + case DRI2_SAREA_BLOCK_EVENT_BUFFER: + psp->dri2.buffer = (__DRIEventBuffer *) p; + break; + } + p = DRI2_SAREA_BLOCK_NEXT(p); + } + + psp->lock = (drmLock *) &psp->dri2.lock->lock; + + psc->destroyScreen = driDestroyScreen; + psc->getExtensions = driGetExtensions; + psc->createNewDrawable = driCreateNewDrawable; + psc->createNewContext = driCreateNewContext; + + *driver_modes = __dri2DriverInitScreen(psp); + if (*driver_modes == NULL) { + drmBOUnmap(psp->fd, &psp->dri2.sareaBO); + drmBOUnreference(psp->fd, &psp->dri2.sareaBO); + _mesa_free(psp); + return NULL; + } + + return psp; +} + /** * Compare the current GLX API version with a driver supplied required version. * diff --git a/src/mesa/drivers/dri/common/dri_util.h b/src/mesa/drivers/dri/common/dri_util.h index def07758398..db7eeed92a8 100644 --- a/src/mesa/drivers/dri/common/dri_util.h +++ b/src/mesa/drivers/dri/common/dri_util.h @@ -55,6 +55,7 @@ #include "xf86drm.h" #include "GL/internal/glcore.h" #include "GL/internal/dri_interface.h" +#include "GL/internal/dri_sarea.h" #define GLX_BAD_CONTEXT 5 @@ -73,6 +74,9 @@ typedef struct __DRIutilversionRec2 __DRIutilversion2; */ extern __GLcontextModes *__driDriverInitScreen(__DRIscreenPrivate *psp); +/** Ditto for DRI2 capable drivers. */ +extern __GLcontextModes *__dri2DriverInitScreen(__DRIscreenPrivate *psp); + /** * Extensions. */ @@ -214,6 +218,10 @@ struct __DriverAPIRec { int (*GetDrawableMSC) ( __DRIscreenPrivate * priv, __DRIdrawablePrivate *drawablePrivate, int64_t *count); + + /* DRI2 Entry points */ + void (*UpdateBuffer)(__DRIdrawablePrivate *dPriv, + unsigned int *event); }; @@ -371,6 +379,9 @@ struct __DRIdrawablePrivateRec { * GLX_MESA_swap_control. */ unsigned int swap_interval; + struct { + unsigned int tail; + } dri2; }; /** @@ -516,6 +527,19 @@ struct __DRIscreenPrivateRec { * Extensions provided by this driver. */ const __DRIextension **extensions; + + struct { + /* Flag to indicate that this is a DRI2 screen. Many of the above + * fields will not be valid or initializaed in that case. */ + int enabled; + drmBO sareaBO; + void *sarea; + __DRIEventBuffer *buffer; + __DRILock *lock; + } dri2; + + /* The lock actually in use, old sarea or DRI2 */ + drmLock *lock; }; @@ -538,6 +562,8 @@ __driUtilMessage(const char *f, ...); extern void __driUtilUpdateDrawableInfo(__DRIdrawablePrivate *pdp); +extern int +__driParseEvents(__DRIscreenPrivate *psp, __DRIdrawablePrivate *pdp); extern __DRIscreenPrivate * __driUtilCreateNewScreen( int scr, __DRIscreen *psc, __GLcontextModes * modes, -- 2.30.2