aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/hw/xfree86/dri2/dri2.c
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/hw/xfree86/dri2/dri2.c')
-rw-r--r--xorg-server/hw/xfree86/dri2/dri2.c493
1 files changed, 493 insertions, 0 deletions
diff --git a/xorg-server/hw/xfree86/dri2/dri2.c b/xorg-server/hw/xfree86/dri2/dri2.c
new file mode 100644
index 000000000..74aef7196
--- /dev/null
+++ b/xorg-server/hw/xfree86/dri2/dri2.c
@@ -0,0 +1,493 @@
+/*
+ * 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 };
+