summaryrefslogtreecommitdiff
path: root/glx/glxdri.c
diff options
context:
space:
mode:
authorKristian Høgsberg <krh@redhat.com>2008-05-21 13:33:36 -0400
committerKristian Høgsberg <krh@redhat.com>2008-05-21 13:33:36 -0400
commitc3eb5b80d8cc7ca6a425ccf359718d1ef3d5af55 (patch)
tree02bedd78921c0950f39cf951dee4dcee7dcde6ae /glx/glxdri.c
parenta8a9b40e554dd0c184866978889a39519afc466a (diff)
Move GL/glx on level up now that it's the only thing left under GL.
Diffstat (limited to 'glx/glxdri.c')
-rw-r--r--glx/glxdri.c1156
1 files changed, 1156 insertions, 0 deletions
diff --git a/glx/glxdri.c b/glx/glxdri.c
new file mode 100644
index 000000000..43b0523f3
--- /dev/null
+++ b/glx/glxdri.c
@@ -0,0 +1,1156 @@
+/*
+ * Copyright © 2006 Red Hat, Inc
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of Red Hat,
+ * Inc not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Red Hat, Inc makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * RED HAT, INC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL RED HAT, INC BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL 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 PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <dlfcn.h>
+
+#include <drm.h>
+#include <GL/gl.h>
+#include <GL/internal/dri_interface.h>
+
+#include <windowstr.h>
+#include <os.h>
+
+#define _XF86DRI_SERVER_
+#include <drm_sarea.h>
+#include <xf86drm.h>
+#include <xf86dristr.h>
+#include <xf86str.h>
+#include <xf86.h>
+#include <dri.h>
+
+#include "servermd.h"
+
+#define DRI_NEW_INTERFACE_ONLY
+#include "glxserver.h"
+#include "glxutil.h"
+#include "glxdricommon.h"
+
+#include "g_disptab.h"
+#include "glapitable.h"
+#include "glapi.h"
+#include "glthread.h"
+#include "dispatch.h"
+#include "extension_string.h"
+
+typedef struct __GLXDRIscreen __GLXDRIscreen;
+typedef struct __GLXDRIcontext __GLXDRIcontext;
+typedef struct __GLXDRIdrawable __GLXDRIdrawable;
+
+struct __GLXDRIscreen {
+ __GLXscreen base;
+ __DRIscreen *driScreen;
+ void *driver;
+
+ xf86EnterVTProc *enterVT;
+ xf86LeaveVTProc *leaveVT;
+
+ const __DRIcoreExtension *core;
+ const __DRIlegacyExtension *legacy;
+ const __DRIcopySubBufferExtension *copySubBuffer;
+ const __DRIswapControlExtension *swapControl;
+
+#ifdef __DRI_TEX_OFFSET
+ const __DRItexOffsetExtension *texOffset;
+ DRITexOffsetStartProcPtr texOffsetStart;
+ DRITexOffsetFinishProcPtr texOffsetFinish;
+ __GLXDRIdrawable *texOffsetOverride[16];
+ GLuint lastTexOffsetOverride;
+#endif
+
+ unsigned char glx_enable_bits[__GLX_EXT_BYTES];
+};
+
+struct __GLXDRIcontext {
+ __GLXcontext base;
+ __DRIcontext *driContext;
+ XID hwContextID;
+};
+
+struct __GLXDRIdrawable {
+ __GLXdrawable base;
+ __DRIdrawable *driDrawable;
+
+ /* Pulled in from old __GLXpixmap */
+#ifdef __DRI_TEX_OFFSET
+ GLint texname;
+ __GLXDRIcontext *ctx;
+ unsigned long offset;
+ DamagePtr pDamage;
+#endif
+};
+
+static void
+__glXDRIleaveServer(GLboolean rendering)
+{
+ int i;
+
+ for (i = 0; rendering && i < screenInfo.numScreens; i++) {
+ __GLXDRIscreen * const screen =
+ (__GLXDRIscreen *) glxGetScreen(screenInfo.screens[i]);
+ GLuint lastOverride = screen->lastTexOffsetOverride;
+
+ if (lastOverride) {
+ __GLXDRIdrawable **texOffsetOverride = screen->texOffsetOverride;
+ int j;
+
+ for (j = 0; j < lastOverride; j++) {
+ __GLXDRIdrawable *pGlxPix = texOffsetOverride[j];
+
+ if (pGlxPix && pGlxPix->texname) {
+ pGlxPix->offset =
+ screen->texOffsetStart((PixmapPtr)pGlxPix->base.pDraw);
+ }
+ }
+ }
+ }
+
+ DRIBlockHandler(NULL, NULL, NULL);
+
+ for (i = 0; rendering && i < screenInfo.numScreens; i++) {
+ __GLXDRIscreen * const screen =
+ (__GLXDRIscreen *) glxGetScreen(screenInfo.screens[i]);
+ GLuint lastOverride = screen->lastTexOffsetOverride;
+
+ if (lastOverride) {
+ __GLXDRIdrawable **texOffsetOverride = screen->texOffsetOverride;
+ int j;
+
+ for (j = 0; j < lastOverride; j++) {
+ __GLXDRIdrawable *pGlxPix = texOffsetOverride[j];
+
+ if (pGlxPix && pGlxPix->texname) {
+ screen->texOffset->setTexOffset(pGlxPix->ctx->driContext,
+ pGlxPix->texname,
+ pGlxPix->offset,
+ pGlxPix->base.pDraw->depth,
+ ((PixmapPtr)pGlxPix->base.pDraw)->devKind);
+ }
+ }
+ }
+ }
+}
+
+static void
+__glXDRIenterServer(GLboolean rendering)
+{
+ int i;
+
+ for (i = 0; rendering && i < screenInfo.numScreens; i++) {
+ __GLXDRIscreen * const screen = (__GLXDRIscreen *)
+ glxGetScreen(screenInfo.screens[i]);
+
+ if (screen->lastTexOffsetOverride) {
+ CALL_Flush(GET_DISPATCH(), ());
+ break;
+ }
+ }
+
+ DRIWakeupHandler(NULL, 0, NULL);
+}
+
+
+static void
+__glXDRIdoReleaseTexImage(__GLXDRIscreen *screen, __GLXDRIdrawable *drawable)
+{
+ GLuint lastOverride = screen->lastTexOffsetOverride;
+
+ if (lastOverride) {
+ __GLXDRIdrawable **texOffsetOverride = screen->texOffsetOverride;
+ int i;
+
+ for (i = 0; i < lastOverride; i++) {
+ if (texOffsetOverride[i] == drawable) {
+
+ texOffsetOverride[i] = NULL;
+
+ if (i + 1 == lastOverride) {
+ lastOverride = 0;
+
+ while (i--) {
+ if (texOffsetOverride[i]) {
+ lastOverride = i + 1;
+ break;
+ }
+ }
+
+ screen->lastTexOffsetOverride = lastOverride;
+
+ break;
+ }
+ }
+ }
+ }
+}
+
+
+static void
+__glXDRIdrawableDestroy(__GLXdrawable *drawable)
+{
+ __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable;
+ __GLXDRIscreen *screen;
+ int i;
+
+ for (i = 0; i < screenInfo.numScreens; i++) {
+ screen = (__GLXDRIscreen *) glxGetScreen(screenInfo.screens[i]);
+ __glXDRIdoReleaseTexImage(screen, private);
+ }
+
+ /* If the X window was destroyed, the dri DestroyWindow hook will
+ * aready have taken care of this, so only call if pDraw isn't NULL. */
+ if (drawable->pDraw != NULL) {
+ screen = (__GLXDRIscreen *) glxGetScreen(drawable->pDraw->pScreen);
+ (*screen->core->destroyDrawable)(private->driDrawable);
+
+ __glXenterServer(GL_FALSE);
+ DRIDestroyDrawable(drawable->pDraw->pScreen,
+ serverClient, drawable->pDraw);
+ __glXleaveServer(GL_FALSE);
+ }
+
+ xfree(private);
+}
+
+static GLboolean
+__glXDRIdrawableResize(__GLXdrawable *glxPriv)
+{
+ /* Nothing to do here, the DRI driver asks the server for drawable
+ * geometry when it sess the SAREA timestamps change.*/
+
+ return GL_TRUE;
+}
+
+static GLboolean
+__glXDRIdrawableSwapBuffers(__GLXdrawable *basePrivate)
+{
+ __GLXDRIdrawable *private = (__GLXDRIdrawable *) basePrivate;
+ __GLXDRIscreen *screen =
+ (__GLXDRIscreen *) glxGetScreen(basePrivate->pDraw->pScreen);
+
+ (*screen->core->swapBuffers)(private->driDrawable);
+
+ return TRUE;
+}
+
+
+static int
+__glXDRIdrawableSwapInterval(__GLXdrawable *baseDrawable, int interval)
+{
+ __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseDrawable;
+ __GLXDRIscreen *screen =
+ (__GLXDRIscreen *) glxGetScreen(baseDrawable->pDraw->pScreen);
+
+ if (screen->swapControl)
+ screen->swapControl->setSwapInterval(draw->driDrawable, interval);
+
+ return 0;
+}
+
+
+static void
+__glXDRIdrawableCopySubBuffer(__GLXdrawable *basePrivate,
+ int x, int y, int w, int h)
+{
+ __GLXDRIdrawable *private = (__GLXDRIdrawable *) basePrivate;
+ __GLXDRIscreen *screen = (__GLXDRIscreen *)
+ glxGetScreen(basePrivate->pDraw->pScreen);
+
+ if (screen->copySubBuffer)
+ screen->copySubBuffer->copySubBuffer(private->driDrawable, x, y, w, h);
+}
+
+static void
+__glXDRIcontextDestroy(__GLXcontext *baseContext)
+{
+ __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
+ __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
+ Bool retval;
+
+ screen->core->destroyContext(context->driContext);
+
+ __glXenterServer(GL_FALSE);
+ retval = DRIDestroyContext(baseContext->pGlxScreen->pScreen,
+ context->hwContextID);
+ __glXleaveServer(GL_FALSE);
+
+ __glXContextDestroy(&context->base);
+ xfree(context);
+}
+
+static int
+__glXDRIcontextMakeCurrent(__GLXcontext *baseContext)
+{
+ __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
+ __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
+ __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv;
+ __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv;
+
+ return (*screen->core->bindContext)(context->driContext,
+ draw->driDrawable,
+ read->driDrawable);
+}
+
+static int
+__glXDRIcontextLoseCurrent(__GLXcontext *baseContext)
+{
+ __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
+ __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
+
+ return (*screen->core->unbindContext)(context->driContext);
+}
+
+static int
+__glXDRIcontextCopy(__GLXcontext *baseDst, __GLXcontext *baseSrc,
+ unsigned long mask)
+{
+ __GLXDRIcontext *dst = (__GLXDRIcontext *) baseDst;
+ __GLXDRIcontext *src = (__GLXDRIcontext *) baseSrc;
+ __GLXDRIscreen *screen = (__GLXDRIscreen *) dst->base.pGlxScreen;
+
+ return (*screen->core->copyContext)(dst->driContext,
+ src->driContext, mask);
+}
+
+static int
+__glXDRIcontextForceCurrent(__GLXcontext *baseContext)
+{
+ __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
+ __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv;
+ __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv;
+ __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
+
+ return (*screen->core->bindContext)(context->driContext,
+ draw->driDrawable,
+ read->driDrawable);
+}
+
+static void
+glxFillAlphaChannel (CARD32 *pixels, CARD32 rowstride, int width, int height)
+{
+ int i;
+ CARD32 *p, *end;
+
+ rowstride /= 4;
+
+ for (i = 0; i < height; i++)
+ {
+ p = pixels;
+ end = p + width;
+ while (p < end)
+ *p++ |= 0xFF000000;
+ pixels += rowstride;
+ }
+}
+
+/*
+ * (sticking this here for lack of a better place)
+ * Known issues with the GLX_EXT_texture_from_pixmap implementation:
+ * - In general we ignore the fbconfig, lots of examples follow
+ * - No fbconfig handling for multiple mipmap levels
+ * - No fbconfig handling for 1D textures
+ * - No fbconfig handling for TEXTURE_TARGET
+ * - No fbconfig exposure of Y inversion state
+ * - No GenerateMipmapEXT support (due to no FBO support)
+ * - No support for anything but 16bpp and 32bpp-sparse pixmaps
+ */
+
+static int
+__glXDRIbindTexImage(__GLXcontext *baseContext,
+ int buffer,
+ __GLXdrawable *glxPixmap)
+{
+ RegionPtr pRegion = NULL;
+ PixmapPtr pixmap;
+ int bpp, override = 0, texname;
+ GLenum format, type;
+ ScreenPtr pScreen = glxPixmap->pDraw->pScreen;
+ __GLXDRIdrawable *driDraw = (__GLXDRIdrawable *) glxPixmap;
+ __GLXDRIscreen * const screen = (__GLXDRIscreen *) glxGetScreen(pScreen);
+
+ CALL_GetIntegerv(GET_DISPATCH(), (glxPixmap->target == GL_TEXTURE_2D ?
+ GL_TEXTURE_BINDING_2D :
+ GL_TEXTURE_BINDING_RECTANGLE_NV,
+ &texname));
+
+ if (!texname)
+ return __glXError(GLXBadContextState);
+
+ pixmap = (PixmapPtr) glxPixmap->pDraw;
+
+ if (screen->texOffsetStart && screen->texOffset) {
+ __GLXDRIdrawable **texOffsetOverride = screen->texOffsetOverride;
+ int i, firstEmpty = 16;
+
+ for (i = 0; i < 16; i++) {
+ if (texOffsetOverride[i] == driDraw)
+ goto alreadyin;
+
+ if (firstEmpty == 16 && !texOffsetOverride[i])
+ firstEmpty = i;
+ }
+
+ if (firstEmpty == 16) {
+ ErrorF("%s: Failed to register texture offset override\n", __func__);
+ goto nooverride;
+ }
+
+ if (firstEmpty >= screen->lastTexOffsetOverride)
+ screen->lastTexOffsetOverride = firstEmpty + 1;
+
+ texOffsetOverride[firstEmpty] = driDraw;
+
+alreadyin:
+ override = 1;
+
+ driDraw->ctx = (__GLXDRIcontext*)baseContext;
+
+ if (texname == driDraw->texname)
+ return Success;
+
+ driDraw->texname = texname;
+
+ screen->texOffset->setTexOffset(driDraw->ctx->driContext, texname, 0,
+ pixmap->drawable.depth,
+ pixmap->devKind);
+ }
+nooverride:
+
+ if (!driDraw->pDamage) {
+ if (!override) {
+ driDraw->pDamage = DamageCreate(NULL, NULL, DamageReportNone,
+ TRUE, pScreen, NULL);
+ if (!driDraw->pDamage)
+ return BadAlloc;
+
+ DamageRegister ((DrawablePtr) pixmap, driDraw->pDamage);
+ }
+
+ pRegion = NULL;
+ } else {
+ pRegion = DamageRegion(driDraw->pDamage);
+ if (REGION_NIL(pRegion))
+ return Success;
+ }
+
+ /* XXX 24bpp packed, 8, etc */
+ if (pixmap->drawable.depth >= 24) {
+ bpp = 4;
+ format = GL_BGRA;
+ type =
+#if X_BYTE_ORDER == X_BIG_ENDIAN
+ !override ? GL_UNSIGNED_INT_8_8_8_8_REV :
+#endif
+ GL_UNSIGNED_BYTE;
+ } else {
+ bpp = 2;
+ format = GL_RGB;
+ type = GL_UNSIGNED_SHORT_5_6_5;
+ }
+
+ if (pRegion == NULL)
+ {
+ void *data = NULL;
+
+ if (!override) {
+ unsigned pitch = PixmapBytePad(pixmap->drawable.width,
+ pixmap->drawable.depth);
+
+ data = xalloc(pitch * pixmap->drawable.height);
+
+ pScreen->GetImage(&pixmap->drawable, 0 /*pixmap->drawable.x*/,
+ 0 /*pixmap->drawable.y*/, pixmap->drawable.width,
+ pixmap->drawable.height, ZPixmap, ~0, data);
+
+ if (pixmap->drawable.depth == 24)
+ glxFillAlphaChannel(data,
+ pitch,
+ pixmap->drawable.width,
+ pixmap->drawable.height);
+
+ CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_ROW_LENGTH,
+ pitch / bpp) );
+ CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_SKIP_PIXELS, 0) );
+ CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_SKIP_ROWS, 0) );
+ }
+
+ CALL_TexImage2D( GET_DISPATCH(),
+ (glxPixmap->target,
+ 0,
+ bpp == 4 ? 4 : 3,
+ pixmap->drawable.width,
+ pixmap->drawable.height,
+ 0,
+ format,
+ type,
+ data) );
+
+ xfree(data);
+ } else if (!override) {
+ int i, numRects;
+ BoxPtr p;
+
+ numRects = REGION_NUM_RECTS (pRegion);
+ p = REGION_RECTS (pRegion);
+
+ CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_SKIP_PIXELS, 0) );
+ CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_SKIP_ROWS, 0) );
+
+ for (i = 0; i < numRects; i++)
+ {
+ unsigned pitch = PixmapBytePad(p[i].x2 - p[i].x1,
+ pixmap->drawable.depth);
+ void *data = xalloc(pitch * (p[i].y2 - p[i].y1));
+
+ pScreen->GetImage(&pixmap->drawable, /*pixmap->drawable.x +*/ p[i].x1,
+ /*pixmap->drawable.y*/ + p[i].y1, p[i].x2 - p[i].x1,
+ p[i].y2 - p[i].y1, ZPixmap, ~0, data);
+
+ if (pixmap->drawable.depth == 24)
+ glxFillAlphaChannel(data,
+ pitch,
+ p[i].x2 - p[i].x1,
+ p[i].y2 - p[i].y1);
+
+ CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_ROW_LENGTH,
+ pitch / bpp) );
+
+ CALL_TexSubImage2D( GET_DISPATCH(),
+ (glxPixmap->target,
+ 0,
+ p[i].x1, p[i].y1,
+ p[i].x2 - p[i].x1, p[i].y2 - p[i].y1,
+ format,
+ type,
+ data) );
+
+ xfree(data);
+ }
+ }
+
+ if (!override)
+ DamageEmpty(driDraw->pDamage);
+
+ return Success;
+}
+
+static int
+__glXDRIreleaseTexImage(__GLXcontext *baseContext,
+ int buffer,
+ __GLXdrawable *pixmap)
+{
+ __GLXDRIscreen *screen =
+ (__GLXDRIscreen *) glxGetScreen(pixmap->pDraw->pScreen);
+ __GLXDRIdrawable *drawable = (__GLXDRIdrawable *) pixmap;
+
+ __glXDRIdoReleaseTexImage(screen, drawable);
+
+ return Success;
+}
+
+static __GLXtextureFromPixmap __glXDRItextureFromPixmap = {
+ __glXDRIbindTexImage,
+ __glXDRIreleaseTexImage
+};
+
+static void
+__glXDRIscreenDestroy(__GLXscreen *baseScreen)
+{
+ __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen;
+
+ screen->core->destroyScreen(screen->driScreen);
+
+ dlclose(screen->driver);
+
+ __glXScreenDestroy(baseScreen);
+
+ xfree(screen);
+}
+
+static __GLXcontext *
+__glXDRIscreenCreateContext(__GLXscreen *baseScreen,
+ __GLXconfig *glxConfig,
+ __GLXcontext *baseShareContext)
+{
+ __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen;
+ __GLXDRIcontext *context, *shareContext;
+ __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig;
+ VisualPtr visual;
+ int i;
+ GLboolean retval;
+ __DRIcontext *driShare;
+ drm_context_t hwContext;
+ ScreenPtr pScreen = baseScreen->pScreen;
+
+ shareContext = (__GLXDRIcontext *) baseShareContext;
+ if (shareContext)
+ driShare = shareContext->driContext;
+ else
+ driShare = NULL;
+
+ if (baseShareContext && baseShareContext->isDirect)
+ return NULL;
+
+ context = xalloc(sizeof *context);
+ if (context == NULL)
+ return NULL;
+
+ memset(context, 0, sizeof *context);
+ context->base.destroy = __glXDRIcontextDestroy;
+ context->base.makeCurrent = __glXDRIcontextMakeCurrent;
+ context->base.loseCurrent = __glXDRIcontextLoseCurrent;
+ context->base.copy = __glXDRIcontextCopy;
+ context->base.forceCurrent = __glXDRIcontextForceCurrent;
+
+ context->base.textureFromPixmap = &__glXDRItextureFromPixmap;
+ /* Find the requested X visual */
+ visual = pScreen->visuals;
+ for (i = 0; i < pScreen->numVisuals; i++, visual++)
+ if (visual->vid == glxConfig->visualID)
+ break;
+ if (i == pScreen->numVisuals)
+ return GL_FALSE;
+
+ context->hwContextID = FakeClientID(0);
+
+ __glXenterServer(GL_FALSE);
+ retval = DRICreateContext(baseScreen->pScreen, visual,
+ context->hwContextID, &hwContext);
+ __glXleaveServer(GL_FALSE);
+
+ context->driContext =
+ screen->legacy->createNewContext(screen->driScreen,
+ config->driConfig,
+ 0, /* render type */
+ driShare,
+ hwContext,
+ context);
+
+ if (context->driContext == NULL) {
+ __glXenterServer(GL_FALSE);
+ retval = DRIDestroyContext(baseScreen->pScreen, context->hwContextID);
+ __glXleaveServer(GL_FALSE);
+ xfree(context);
+ return NULL;
+ }
+
+ return &context->base;
+}
+
+static __GLXdrawable *
+__glXDRIscreenCreateDrawable(__GLXscreen *screen,
+ DrawablePtr pDraw,
+ int type,
+ XID drawId,
+ __GLXconfig *glxConfig)
+{
+ __GLXDRIscreen *driScreen = (__GLXDRIscreen *) screen;
+ __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig;
+ __GLXDRIdrawable *private;
+ GLboolean retval;
+ drm_drawable_t hwDrawable;
+
+ private = xalloc(sizeof *private);
+ if (private == NULL)
+ return NULL;
+
+ memset(private, 0, sizeof *private);
+
+ if (!__glXDrawableInit(&private->base, screen,
+ pDraw, type, drawId, glxConfig)) {
+ xfree(private);
+ return NULL;
+ }
+
+ private->base.destroy = __glXDRIdrawableDestroy;
+ private->base.resize = __glXDRIdrawableResize;
+ private->base.swapBuffers = __glXDRIdrawableSwapBuffers;
+ private->base.copySubBuffer = __glXDRIdrawableCopySubBuffer;
+
+ __glXenterServer(GL_FALSE);
+ retval = DRICreateDrawable(screen->pScreen, serverClient,
+ pDraw, &hwDrawable);
+ __glXleaveServer(GL_FALSE);
+
+ /* The last argument is 'attrs', which is used with pbuffers which
+ * we currently don't support. */
+
+ private->driDrawable =
+ (driScreen->legacy->createNewDrawable)(driScreen->driScreen,
+ config->driConfig,
+ hwDrawable, 0, NULL, private);
+
+ if (private->driDrawable == NULL) {
+ __glXenterServer(GL_FALSE);
+ DRIDestroyDrawable(screen->pScreen, serverClient, pDraw);
+ __glXleaveServer(GL_FALSE);
+ xfree(private);
+ return NULL;
+ }
+
+ return &private->base;
+}
+
+static GLboolean
+getDrawableInfo(__DRIdrawable *driDrawable,
+ unsigned int *index, unsigned int *stamp,
+ int *x, int *y, int *width, int *height,
+ int *numClipRects, drm_clip_rect_t **ppClipRects,
+ int *backX, int *backY,
+ int *numBackClipRects, drm_clip_rect_t **ppBackClipRects,
+ void *data)
+{
+ __GLXDRIdrawable *drawable = data;
+ ScreenPtr pScreen;
+ drm_clip_rect_t *pClipRects, *pBackClipRects;
+ GLboolean retval;
+ size_t size;
+
+ /* If the X window has been destroyed, give up here. */
+ if (drawable->base.pDraw == NULL)
+ return GL_FALSE;
+
+ pScreen = drawable->base.pDraw->pScreen;
+ __glXenterServer(GL_FALSE);
+ retval = DRIGetDrawableInfo(pScreen, drawable->base.pDraw, index, stamp,
+ x, y, width, height,
+ numClipRects, &pClipRects,
+ backX, backY,
+ numBackClipRects, &pBackClipRects);
+ __glXleaveServer(GL_FALSE);
+
+ if (*numClipRects > 0) {
+ size = sizeof (drm_clip_rect_t) * *numClipRects;
+ *ppClipRects = xalloc (size);
+
+ /* Clip cliprects to screen dimensions (redirected windows) */
+ if (*ppClipRects != NULL) {
+ int i, j;
+
+ for (i = 0, j = 0; i < *numClipRects; i++) {
+ (*ppClipRects)[j].x1 = max(pClipRects[i].x1, 0);
+ (*ppClipRects)[j].y1 = max(pClipRects[i].y1, 0);
+ (*ppClipRects)[j].x2 = min(pClipRects[i].x2, pScreen->width);
+ (*ppClipRects)[j].y2 = min(pClipRects[i].y2, pScreen->height);
+
+ if ((*ppClipRects)[j].x1 < (*ppClipRects)[j].x2 &&
+ (*ppClipRects)[j].y1 < (*ppClipRects)[j].y2) {
+ j++;
+ }
+ }
+
+ if (*numClipRects != j) {
+ *numClipRects = j;
+ *ppClipRects = xrealloc (*ppClipRects,
+ sizeof (drm_clip_rect_t) *
+ *numClipRects);
+ }
+ } else
+ *numClipRects = 0;
+ }
+ else {
+ *ppClipRects = NULL;
+ }
+
+ if (*numBackClipRects > 0) {
+ size = sizeof (drm_clip_rect_t) * *numBackClipRects;
+ *ppBackClipRects = xalloc (size);
+ if (*ppBackClipRects != NULL)
+ memcpy (*ppBackClipRects, pBackClipRects, size);
+ }
+ else {
+ *ppBackClipRects = NULL;
+ }
+
+ return retval;
+}
+
+static void __glXReportDamage(__DRIdrawable *driDraw,
+ int x, int y,
+ drm_clip_rect_t *rects, int num_rects,
+ GLboolean front_buffer,
+ void *data)
+{
+ __GLXDRIdrawable *drawable = data;
+ DrawablePtr pDraw = drawable->base.pDraw;
+ RegionRec region;
+
+ __glXenterServer(GL_FALSE);
+
+ REGION_INIT(pDraw->pScreen, &region, (BoxPtr) rects, num_rects);
+ REGION_TRANSLATE(pScreen, &region, pDraw->x, pDraw->y);
+ DamageDamageRegion(pDraw, &region);
+ REGION_UNINIT(pDraw->pScreen, &region);
+
+ __glXleaveServer(GL_FALSE);
+}
+
+static const __DRIgetDrawableInfoExtension getDrawableInfoExtension = {
+ { __DRI_GET_DRAWABLE_INFO, __DRI_GET_DRAWABLE_INFO_VERSION },
+ getDrawableInfo
+};
+
+static const __DRIdamageExtension damageExtension = {
+ { __DRI_DAMAGE, __DRI_DAMAGE_VERSION },
+ __glXReportDamage,
+};
+
+static const __DRIextension *loader_extensions[] = {
+ &systemTimeExtension.base,
+ &getDrawableInfoExtension.base,
+ &damageExtension.base,
+ NULL
+};
+
+
+
+static const char dri_driver_path[] = DRI_DRIVER_PATH;
+
+static Bool
+glxDRIEnterVT (int index, int flags)
+{
+ __GLXDRIscreen *screen = (__GLXDRIscreen *)
+ glxGetScreen(screenInfo.screens[index]);
+
+ LogMessage(X_INFO, "AIGLX: Resuming AIGLX clients after VT switch\n");
+
+ if (!(*screen->enterVT) (index, flags))
+ return FALSE;
+
+ glxResumeClients();
+
+ return TRUE;
+}
+
+static void
+glxDRILeaveVT (int index, int flags)
+{
+ __GLXDRIscreen *screen = (__GLXDRIscreen *)
+ glxGetScreen(screenInfo.screens[index]);
+
+ LogMessage(X_INFO, "AIGLX: Suspending AIGLX clients for VT switch\n");
+
+ glxSuspendClients();
+
+ return (*screen->leaveVT) (index, flags);
+}
+
+static void
+initializeExtensions(__GLXDRIscreen *screen)
+{
+ const __DRIextension **extensions;
+ int i;
+
+ extensions = screen->core->getExtensions(screen->driScreen);
+
+ for (i = 0; extensions[i]; i++) {
+#ifdef __DRI_COPY_SUB_BUFFER
+ if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) {
+ screen->copySubBuffer = (__DRIcopySubBufferExtension *) extensions[i];
+ __glXEnableExtension(screen->glx_enable_bits,
+ "GLX_MESA_copy_sub_buffer");
+
+ LogMessage(X_INFO, "AIGLX: enabled GLX_MESA_copy_sub_buffer\n");
+ }
+#endif
+
+#ifdef __DRI_SWAP_CONTROL
+ if (strcmp(extensions[i]->name, __DRI_SWAP_CONTROL) == 0) {
+ screen->swapControl = (__DRIswapControlExtension *) extensions[i];
+ __glXEnableExtension(screen->glx_enable_bits,
+ "GLX_SGI_swap_control");
+ __glXEnableExtension(screen->glx_enable_bits,
+ "GLX_MESA_swap_control");
+
+ LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_swap_control and GLX_MESA_swap_control\n");
+ }
+#endif
+
+#ifdef __DRI_TEX_OFFSET
+ if (strcmp(extensions[i]->name, __DRI_TEX_OFFSET) == 0) {
+ screen->texOffset = (__DRItexOffsetExtension *) extensions[i];
+ LogMessage(X_INFO, "AIGLX: enabled GLX_texture_from_pixmap with driver support\n");
+ }
+#endif
+ /* Ignore unknown extensions */
+ }
+}
+
+extern __GLXconfig *
+glxConvertConfigs(const __DRIcoreExtension *core, const __DRIconfig **configs);
+
+static __GLXscreen *
+__glXDRIscreenProbe(ScreenPtr pScreen)
+{
+ drm_handle_t hSAREA;
+ drmAddress pSAREA = NULL;
+ char *BusID;
+ __DRIversion ddx_version;
+ __DRIversion dri_version;
+ __DRIversion drm_version;
+ __DRIframebuffer framebuffer;
+ int fd = -1;
+ int status;
+ drm_magic_t magic;
+ drmVersionPtr version;
+ int newlyopened;
+ char *driverName;
+ drm_handle_t hFB;
+ int junk;
+ __GLXDRIscreen *screen;
+ char filename[128];
+ Bool isCapable;
+ size_t buffer_size;
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ const __DRIconfig **driConfigs;
+ const __DRIextension **extensions;
+ int i;
+
+ if (!xf86LoaderCheckSymbol("DRIQueryDirectRenderingCapable") ||
+ !DRIQueryDirectRenderingCapable(pScreen, &isCapable) ||
+ !isCapable) {
+ LogMessage(X_INFO,
+ "AIGLX: Screen %d is not DRI capable\n", pScreen->myNum);
+ return NULL;
+ }
+
+ screen = xalloc(sizeof *screen);
+ if (screen == NULL)
+ return NULL;
+ memset(screen, 0, sizeof *screen);
+
+ screen->base.destroy = __glXDRIscreenDestroy;
+ screen->base.createContext = __glXDRIscreenCreateContext;
+ screen->base.createDrawable = __glXDRIscreenCreateDrawable;
+ screen->base.swapInterval = __glXDRIdrawableSwapInterval;
+ screen->base.pScreen = pScreen;
+
+ __glXInitExtensionEnableBits(screen->glx_enable_bits);
+
+ /* DRI protocol version. */
+ dri_version.major = XF86DRI_MAJOR_VERSION;
+ dri_version.minor = XF86DRI_MINOR_VERSION;
+ dri_version.patch = XF86DRI_PATCH_VERSION;
+
+ if (!DRIOpenConnection(pScreen, &hSAREA, &BusID)) {
+ LogMessage(X_ERROR, "AIGLX error: DRIOpenConnection failed\n");
+ goto handle_error;
+ }
+
+ fd = drmOpenOnce(NULL, BusID, &newlyopened);
+
+ if (fd < 0) {
+ LogMessage(X_ERROR, "AIGLX error: drmOpenOnce failed (%s)\n",
+ strerror(-fd));
+ goto handle_error;
+ }
+
+ if (drmGetMagic(fd, &magic)) {
+ LogMessage(X_ERROR, "AIGLX error: drmGetMagic failed\n");
+ goto handle_error;
+ }
+
+ version = drmGetVersion(fd);
+ if (version) {
+ drm_version.major = version->version_major;
+ drm_version.minor = version->version_minor;
+ drm_version.patch = version->version_patchlevel;
+ drmFreeVersion(version);
+ }
+ else {
+ drm_version.major = -1;
+ drm_version.minor = -1;
+ drm_version.patch = -1;
+ }
+
+ if (newlyopened && !DRIAuthConnection(pScreen, magic)) {
+ LogMessage(X_ERROR, "AIGLX error: DRIAuthConnection failed\n");
+ goto handle_error;
+ }
+
+ /* Get device name (like "tdfx") and the ddx version numbers.
+ * We'll check the version in each DRI driver's "createNewScreen"
+ * function. */
+ if (!DRIGetClientDriverName(pScreen,
+ &ddx_version.major,
+ &ddx_version.minor,
+ &ddx_version.patch,
+ &driverName)) {
+ LogMessage(X_ERROR, "AIGLX error: DRIGetClientDriverName failed\n");
+ goto handle_error;
+ }
+
+ snprintf(filename, sizeof filename, "%s/%s_dri.so",
+ dri_driver_path, driverName);
+
+ screen->driver = dlopen(filename, RTLD_LAZY | RTLD_LOCAL);
+ if (screen->driver == NULL) {
+ LogMessage(X_ERROR, "AIGLX error: dlopen of %s failed (%s)\n",
+ filename, dlerror());
+ goto handle_error;
+ }
+
+ extensions = dlsym(screen->driver, __DRI_DRIVER_EXTENSIONS);
+ if (extensions == NULL) {
+ LogMessage(X_ERROR, "AIGLX error: %s exports no extensions (%s)\n",
+ driverName, dlerror());
+ goto handle_error;
+ }
+
+ for (i = 0; extensions[i]; i++) {
+ if (strcmp(extensions[i]->name, __DRI_CORE) == 0 &&
+ extensions[i]->version >= __DRI_CORE_VERSION) {
+ screen->core = (__DRIcoreExtension *) extensions[i];
+ }
+
+ if (strcmp(extensions[i]->name, __DRI_LEGACY) == 0 &&
+ extensions[i]->version >= __DRI_LEGACY_VERSION) {
+ screen->legacy = (__DRIlegacyExtension *) extensions[i];
+ }
+ }
+
+ if (screen->core == NULL || screen->legacy == NULL) {
+ LogMessage(X_ERROR,
+ "AIGLX error: %s does not export required DRI extension\n",
+ driverName);
+ goto handle_error;
+ }
+
+ /*
+ * Get device-specific info. pDevPriv will point to a struct
+ * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) that
+ * has information about the screen size, depth, pitch, ancilliary
+ * buffers, DRM mmap handles, etc.
+ */
+ if (!DRIGetDeviceInfo(pScreen, &hFB, &junk,
+ &framebuffer.size, &framebuffer.stride,
+ &framebuffer.dev_priv_size, &framebuffer.dev_priv)) {
+ LogMessage(X_ERROR, "AIGLX error: XF86DRIGetDeviceInfo failed");
+ goto handle_error;
+ }
+
+ framebuffer.width = pScreen->width;
+ framebuffer.height = pScreen->height;
+
+ /* Map the framebuffer region. */
+ status = drmMap(fd, hFB, framebuffer.size,
+ (drmAddressPtr)&framebuffer.base);
+ if (status != 0) {
+ LogMessage(X_ERROR, "AIGLX error: drmMap of framebuffer failed (%s)",
+ strerror(-status));
+ goto handle_error;
+ }
+
+ /* Map the SAREA region. Further mmap regions may be setup in
+ * each DRI driver's "createNewScreen" function.
+ */
+ status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA);
+ if (status != 0) {
+ LogMessage(X_ERROR, "AIGLX error: drmMap of SAREA failed (%s)",
+ strerror(-status));
+ goto handle_error;
+ }
+
+ screen->driScreen =
+ (*screen->legacy->createNewScreen)(pScreen->myNum,
+ &ddx_version,
+ &dri_version,
+ &drm_version,
+ &framebuffer,
+ pSAREA,
+ fd,
+ loader_extensions,
+ &driConfigs,
+ screen);
+
+ if (screen->driScreen == NULL) {
+ LogMessage(X_ERROR, "AIGLX error: Calling driver entry point failed");
+ goto handle_error;
+ }
+
+ screen->base.fbconfigs = glxConvertConfigs(screen->core, driConfigs);
+
+ initializeExtensions(screen);
+
+ DRIGetTexOffsetFuncs(pScreen, &screen->texOffsetStart,
+ &screen->texOffsetFinish);
+
+ __glXScreenInit(&screen->base, pScreen);
+
+ buffer_size = __glXGetExtensionString(screen->glx_enable_bits, NULL);
+ if (buffer_size > 0) {
+ if (screen->base.GLXextensions != NULL) {
+ xfree(screen->base.GLXextensions);
+ }
+
+ screen->base.GLXextensions = xnfalloc(buffer_size);
+ (void) __glXGetExtensionString(screen->glx_enable_bits,
+ screen->base.GLXextensions);
+ }
+
+ __glXsetEnterLeaveServerFuncs(__glXDRIenterServer, __glXDRIleaveServer);
+
+ screen->enterVT = pScrn->EnterVT;
+ pScrn->EnterVT = glxDRIEnterVT;
+ screen->leaveVT = pScrn->LeaveVT;
+ pScrn->LeaveVT = glxDRILeaveVT;
+
+ LogMessage(X_INFO,
+ "AIGLX: Loaded and initialized %s\n", filename);
+
+ return &screen->base;
+
+ handle_error:
+ if (pSAREA != NULL)
+ drmUnmap(pSAREA, SAREA_MAX);
+
+ if (framebuffer.base != NULL)
+ drmUnmap((drmAddress)framebuffer.base, framebuffer.size);
+
+ if (fd >= 0)
+ drmCloseOnce(fd);
+
+ DRICloseConnection(pScreen);
+
+ if (screen->driver)
+ dlclose(screen->driver);
+
+ xfree(screen);
+
+ LogMessage(X_ERROR, "AIGLX: reverting to software rendering\n");
+
+ return NULL;
+}
+
+__GLXprovider __glXDRIProvider = {
+ __glXDRIscreenProbe,
+ "DRI",
+ NULL
+};