/* * Copyright © 2007 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Soft- * ware"), to deal in the Software without restriction, including without * limitation the rights to use, copy, modify, merge, publish, distribute, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, provided that the above copyright * notice(s) and this permission notice appear in all copies of the Soft- * ware and that both the above copyright notice(s) and this permission * notice appear in supporting documentation. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE- * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR- * MANCE OF THIS SOFTWARE. * * Except as contained in this notice, the name of a copyright holder shall * not be used in advertising or otherwise to promote the sale, use or * other dealings in this Software without prior written authorization of * the copyright holder. * * Authors: * Kristian Høgsberg (krh@redhat.com) */ #ifdef HAVE_XORG_CONFIG_H #include #endif #include #include "xf86Module.h" #include "scrnintstr.h" #include "windowstr.h" #include "region.h" #include "damage.h" #include "dri2.h" #include #include "xf86.h" static DevPrivateKey dri2ScreenPrivateKey = &dri2ScreenPrivateKey; static DevPrivateKey dri2WindowPrivateKey = &dri2WindowPrivateKey; static DevPrivateKey dri2PixmapPrivateKey = &dri2PixmapPrivateKey; typedef struct _DRI2DrawablePriv { unsigned int refCount; unsigned int boHandle; unsigned int dri2Handle; } DRI2DrawablePrivRec, *DRI2DrawablePrivPtr; typedef struct _DRI2Screen { int fd; drmBO sareaBO; void *sarea; unsigned int sareaSize; const char *driverName; unsigned int nextHandle; __DRIEventBuffer *buffer; int locked; DRI2GetPixmapHandleProcPtr getPixmapHandle; DRI2BeginClipNotifyProcPtr beginClipNotify; DRI2EndClipNotifyProcPtr endClipNotify; ClipNotifyProcPtr ClipNotify; HandleExposuresProcPtr HandleExposures; } DRI2ScreenRec, *DRI2ScreenPtr; static DRI2ScreenPtr DRI2GetScreen(ScreenPtr pScreen) { return dixLookupPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey); } static void * DRI2ScreenAllocEvent(DRI2ScreenPtr ds, size_t size) { unsigned int *pad, mask = ds->buffer->size - 1; size_t pad_size; void *p; if ((ds->buffer->head & mask) + size > ds->buffer->size) { /* The requested event size would wrap the buffer, so pad to * the end and allocate the event from the start. */ pad_size = ds->buffer->size - (ds->buffer->head & mask); pad = (unsigned int *) (ds->buffer->data + (ds->buffer->prealloc & mask)); *pad = DRI2_EVENT_HEADER(DRI2_EVENT_PAD, pad_size); ds->buffer->prealloc += pad_size; } p = ds->buffer->data + (ds->buffer->prealloc & mask); ds->buffer->prealloc += size; return p; } static void DRI2ScreenCommitEvents(DRI2ScreenPtr ds) { ds->buffer->head = ds->buffer->prealloc; } static void DRI2PostDrawableConfig(DrawablePtr pDraw) { ScreenPtr pScreen = pDraw->pScreen; DRI2ScreenPtr ds = DRI2GetScreen(pScreen); DRI2DrawablePrivPtr pPriv; WindowPtr pWin; PixmapPtr pPixmap; BoxPtr pBox; BoxRec pixmapBox; int nBox; int i; __DRIDrawableConfigEvent *e; size_t size; if (pDraw->type == DRAWABLE_WINDOW) { pWin = (WindowPtr) pDraw; pPriv = dixLookupPrivate(&pWin->devPrivates, dri2WindowPrivateKey); nBox = REGION_NUM_RECTS(&pWin->clipList); pBox = REGION_RECTS(&pWin->clipList); pPixmap = pScreen->GetWindowPixmap(pWin); } else { pPixmap = (PixmapPtr) pDraw; pPriv = dixLookupPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey); pixmapBox.x1 = 0; pixmapBox.y1 = 0; pixmapBox.x2 = pDraw->width; pixmapBox.y2 = pDraw->height; nBox = 1; pBox = &pixmapBox; } if (!pPriv) return; size = sizeof *e + nBox * sizeof e->rects[0]; e = DRI2ScreenAllocEvent(ds, size); e->event_header = DRI2_EVENT_HEADER(DRI2_EVENT_DRAWABLE_CONFIG, size); e->drawable = pPriv->dri2Handle; e->x = pDraw->x - pPixmap->screen_x; e->y = pDraw->y - pPixmap->screen_y; e->width = pDraw->width; e->height = pDraw->height; e->num_rects = nBox; for (i = 0; i < nBox; i++) { e->rects[i].x1 = pBox->x1 - pPixmap->screen_x; e->rects[i].y1 = pBox->y1 - pPixmap->screen_y; e->rects[i].x2 = pBox->x2 - pPixmap->screen_x; e->rects[i].y2 = pBox->y2 - pPixmap->screen_y; pBox++; } } static void DRI2PostBufferAttach(DrawablePtr pDraw, Bool force) { ScreenPtr pScreen = pDraw->pScreen; DRI2ScreenPtr ds = DRI2GetScreen(pScreen); DRI2DrawablePrivPtr pPriv; WindowPtr pWin; PixmapPtr pPixmap; __DRIBufferAttachEvent *e; size_t size; unsigned int flags; unsigned int boHandle; if (pDraw->type == DRAWABLE_WINDOW) { pWin = (WindowPtr) pDraw; pPixmap = pScreen->GetWindowPixmap(pWin); pPriv = dixLookupPrivate(&pWin->devPrivates, dri2WindowPrivateKey); } else { pPixmap = (PixmapPtr) pDraw; pPriv = dixLookupPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey); } if (!pPriv) return; boHandle = ds->getPixmapHandle(pPixmap, &flags); if (boHandle == pPriv->boHandle && !force) return; pPriv->boHandle = boHandle; size = sizeof *e; e = DRI2ScreenAllocEvent(ds, size); e->event_header = DRI2_EVENT_HEADER(DRI2_EVENT_BUFFER_ATTACH, size); e->drawable = pPriv->dri2Handle; e->buffer.attachment = DRI_DRAWABLE_BUFFER_FRONT_LEFT; e->buffer.handle = pPriv->boHandle; e->buffer.pitch = pPixmap->devKind; e->buffer.cpp = pPixmap->drawable.bitsPerPixel / 8; e->buffer.flags = flags; } static void DRI2ClipNotify(WindowPtr pWin, int dx, int dy) { ScreenPtr pScreen = pWin->drawable.pScreen; DRI2ScreenPtr ds = DRI2GetScreen(pScreen); if (!ds->locked) { ds->beginClipNotify(pScreen); ds->locked = 1; } if (ds->ClipNotify) { pScreen->ClipNotify = ds->ClipNotify; pScreen->ClipNotify(pWin, dx, dy); pScreen->ClipNotify = DRI2ClipNotify; } DRI2PostDrawableConfig(&pWin->drawable); DRI2PostBufferAttach(&pWin->drawable, FALSE); } static void DRI2HandleExposures(WindowPtr pWin) { ScreenPtr pScreen = pWin->drawable.pScreen; DRI2ScreenPtr ds = DRI2GetScreen(pScreen); if (ds->HandleExposures) { pScreen->HandleExposures = ds->HandleExposures; pScreen->HandleExposures(pWin); pScreen->HandleExposures = DRI2HandleExposures; } DRI2ScreenCommitEvents(ds); if (ds->locked) { ds->endClipNotify(pScreen); ds->locked = 0; } } void DRI2CloseScreen(ScreenPtr pScreen) { DRI2ScreenPtr ds = DRI2GetScreen(pScreen); pScreen->ClipNotify = ds->ClipNotify; pScreen->HandleExposures = ds->HandleExposures; drmBOUnmap(ds->fd, &ds->sareaBO); drmBOUnreference(ds->fd, &ds->sareaBO); xfree(ds); dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, NULL); } Bool DRI2CreateDrawable(DrawablePtr pDraw, unsigned int *handle, unsigned int *head) { DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); WindowPtr pWin; PixmapPtr pPixmap; DRI2DrawablePrivPtr pPriv; DevPrivateKey key; PrivateRec **devPrivates; if (pDraw->type == DRAWABLE_WINDOW) { pWin = (WindowPtr) pDraw; devPrivates = &pWin->devPrivates; key = dri2WindowPrivateKey; } else { pPixmap = (PixmapPtr) pDraw; devPrivates = &pPixmap->devPrivates; key = dri2PixmapPrivateKey; } pPriv = dixLookupPrivate(devPrivates, key); if (pPriv != NULL) { pPriv->refCount++; } else { pPriv = xalloc(sizeof *pPriv); pPriv->refCount = 1; pPriv->boHandle = 0; pPriv->dri2Handle = ds->nextHandle++; dixSetPrivate(devPrivates, key, pPriv); } *handle = pPriv->dri2Handle; *head = ds->buffer->head; DRI2PostDrawableConfig(pDraw); DRI2PostBufferAttach(pDraw, TRUE); DRI2ScreenCommitEvents(ds); return TRUE; } void DRI2DestroyDrawable(DrawablePtr pDraw) { PixmapPtr pPixmap; WindowPtr pWin; DRI2DrawablePrivPtr pPriv; DevPrivateKey key; PrivateRec **devPrivates; if (pDraw->type == DRAWABLE_WINDOW) { pWin = (WindowPtr) pDraw; devPrivates = &pWin->devPrivates; key = dri2WindowPrivateKey; } else { pPixmap = (PixmapPtr) pDraw; devPrivates = &pPixmap->devPrivates; key = dri2PixmapPrivateKey; } pPriv = dixLookupPrivate(devPrivates, key); if (pPriv == NULL) return; pPriv->refCount--; if (pPriv->refCount == 0) { dixSetPrivate(devPrivates, key, NULL); xfree(pPriv); } } void DRI2ReemitDrawableInfo(DrawablePtr pDraw, unsigned int *head) { DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); *head = ds->buffer->head; DRI2PostDrawableConfig(pDraw); DRI2PostBufferAttach(pDraw, TRUE); DRI2ScreenCommitEvents(ds); } Bool DRI2Connect(ScreenPtr pScreen, int *fd, const char **driverName, unsigned int *sareaHandle) { DRI2ScreenPtr ds = DRI2GetScreen(pScreen); if (ds == NULL) return FALSE; *fd = ds->fd; *driverName = ds->driverName; *sareaHandle = ds->sareaBO.handle; return TRUE; } Bool DRI2AuthConnection(ScreenPtr pScreen, drm_magic_t magic) { DRI2ScreenPtr ds = DRI2GetScreen(pScreen); if (ds == NULL || drmAuthMagic(ds->fd, magic)) return FALSE; return TRUE; } unsigned int DRI2GetPixmapHandle(PixmapPtr pPixmap, unsigned int *flags) { DRI2ScreenPtr ds = DRI2GetScreen(pPixmap->drawable.pScreen); return ds->getPixmapHandle(pPixmap, flags); } static void * DRI2SetupSAREA(ScreenPtr pScreen, size_t driverSareaSize) { DRI2ScreenPtr ds = DRI2GetScreen(pScreen); unsigned long mask; const size_t event_buffer_size = 32 * 1024; ds->sareaSize = sizeof(*ds->buffer) + event_buffer_size + driverSareaSize + sizeof (unsigned int); mask = DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_MAPPABLE | DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_SHAREABLE; if (drmBOCreate(ds->fd, ds->sareaSize, 1, NULL, mask, 0, &ds->sareaBO)) return NULL; if (drmBOMap(ds->fd, &ds->sareaBO, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, &ds->sarea)) { drmBOUnreference(ds->fd, &ds->sareaBO); return NULL; } xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2] Allocated %d byte SAREA, BO handle 0x%08x\n", ds->sareaSize, ds->sareaBO.handle); memset(ds->sarea, 0, ds->sareaSize); ds->buffer = ds->sarea; ds->buffer->block_header = DRI2_SAREA_BLOCK_HEADER(DRI2_SAREA_BLOCK_EVENT_BUFFER, sizeof *ds->buffer + event_buffer_size); ds->buffer->size = event_buffer_size; return DRI2_SAREA_BLOCK_NEXT(ds->buffer); } void * DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info) { DRI2ScreenPtr ds; void *p; ds = xalloc(sizeof *ds); if (!ds) return NULL; ds->fd = info->fd; ds->driverName = info->driverName; ds->nextHandle = 1; ds->getPixmapHandle = info->getPixmapHandle; ds->beginClipNotify = info->beginClipNotify; ds->endClipNotify = info->endClipNotify; ds->ClipNotify = pScreen->ClipNotify; pScreen->ClipNotify = DRI2ClipNotify; ds->HandleExposures = pScreen->HandleExposures; pScreen->HandleExposures = DRI2HandleExposures; dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, ds); p = DRI2SetupSAREA(pScreen, info->driverSareaSize); if (p == NULL) { xfree(ds); return NULL; } xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2] Setup complete\n"); return p; } extern ExtensionModule dri2ExtensionModule; static pointer DRI2Setup(pointer module, pointer opts, int *errmaj, int *errmin) { static Bool setupDone = FALSE; if (!setupDone) { setupDone = TRUE; LoadExtension(&dri2ExtensionModule, FALSE); } else { if (errmaj) *errmaj = LDR_ONCEONLY; } return (pointer) 1; } static XF86ModuleVersionInfo DRI2VersRec = { "dri2", MODULEVENDORSTRING, MODINFOSTRING1, MODINFOSTRING2, XORG_VERSION_CURRENT, 1, 0, 0, ABI_CLASS_EXTENSION, ABI_EXTENSION_VERSION, MOD_CLASS_NONE, { 0, 0, 0, 0 } }; _X_EXPORT XF86ModuleData dri2ModuleData = { &DRI2VersRec, DRI2Setup, NULL };