494 lines
13 KiB
C
494 lines
13 KiB
C
|
/*
|
||
|
* 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 <xorg-config.h>
|
||
|
#endif
|
||
|
|
||
|
#include <xf86drm.h>
|
||
|
#include "xf86Module.h"
|
||
|
#include "scrnintstr.h"
|
||
|
#include "windowstr.h"
|
||
|
#include "region.h"
|
||
|
#include "damage.h"
|
||
|
#include "dri2.h"
|
||
|
#include <GL/internal/dri_sarea.h>
|
||
|
|
||
|
#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 };
|
||
|
|