/* * 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 #endif #include #include #include #include #include #include #include #include #include #include #include #include #define _XF86DRI_SERVER_ #include #include #include #include #include #include #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 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) { if (screen->texOffsetFinish) screen->texOffsetFinish((PixmapPtr)drawable->base.pDraw); 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); } __glXDrawableRelease(drawable); xfree(private); } static GLboolean __glXDRIdrawableSwapBuffers(ClientPtr client, __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; } } static Bool testTexOffset(__GLXDRIscreen * const screen, PixmapPtr pPixmap) { Bool ret; if (!screen->texOffsetStart || !screen->texOffset) return FALSE; __glXenterServer(GL_FALSE); ret = screen->texOffsetStart(pPixmap) != ~0ULL; __glXleaveServer(GL_FALSE); return ret; } /* * (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 (testTexOffset(screen, pixmap)) { __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); __glXenterServer(GL_FALSE); pScreen->GetImage(&pixmap->drawable, 0 /*pixmap->drawable.x*/, 0 /*pixmap->drawable.y*/, pixmap->drawable.width, pixmap->drawable.height, ZPixmap, ~0, data); __glXleaveServer(GL_FALSE); 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)); __glXenterServer(GL_FALSE); 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); __glXleaveServer(GL_FALSE); 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 = xcalloc(1, sizeof *context); if (context == NULL) return NULL; 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 NULL; context->hwContextID = FakeClientID(0); __glXenterServer(GL_FALSE); retval = DRICreateContext(baseScreen->pScreen, visual, context->hwContextID, &hwContext); __glXleaveServer(GL_FALSE); if (!retval) return NULL; 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(ClientPtr client, __GLXscreen *screen, DrawablePtr pDraw, XID drawId, int type, XID glxDrawId, __GLXconfig *glxConfig) { __GLXDRIscreen *driScreen = (__GLXDRIscreen *) screen; __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig; __GLXDRIdrawable *private; GLboolean retval; drm_drawable_t hwDrawable; private = xcalloc(1, sizeof *private); if (private == NULL) return NULL; if (!__glXDrawableInit(&private->base, screen, pDraw, type, glxDrawId, glxConfig)) { xfree(private); return NULL; } private->base.destroy = __glXDRIdrawableDestroy; private->base.swapBuffers = __glXDRIdrawableSwapBuffers; private->base.copySubBuffer = __glXDRIdrawableCopySubBuffer; private->base.waitX = NULL; private->base.waitGL = NULL; __glXenterServer(GL_FALSE); retval = DRICreateDrawable(screen->pScreen, serverClient, pDraw, &hwDrawable); __glXleaveServer(GL_FALSE); if (!retval) { xfree(private); return NULL; } /* 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 (retval && *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; *numClipRects = 0; } if (retval && *numBackClipRects > 0) { size = sizeof (drm_clip_rect_t) * *numBackClipRects; *ppBackClipRects = xalloc (size); if (*ppBackClipRects != NULL) memcpy (*ppBackClipRects, pBackClipRects, size); else *numBackClipRects = 0; } else { *ppBackClipRects = NULL; *numBackClipRects = 0; } 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, ®ion, (BoxPtr) rects, num_rects); REGION_TRANSLATE(pScreen, ®ion, pDraw->x, pDraw->y); DamageRegionAppend(pDraw, ®ion); /* This is wrong, this needs a seperate function. */ DamageRegionProcessPending(pDraw); REGION_UNINIT(pDraw->pScreen, ®ion); __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_READ_DRAWABLE if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) { __glXEnableExtension(screen->glx_enable_bits, "GLX_SGI_make_current_read"); LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_make_current_read\n"); } #endif #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 = xcalloc(1, sizeof *screen); if (screen == NULL) return NULL; 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\n"); 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)\n", 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)\n", 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\n"); goto handle_error; } screen->base.fbconfigs = glxConvertConfigs(screen->core, driConfigs); initializeExtensions(screen); DRIGetTexOffsetFuncs(pScreen, &screen->texOffsetStart, &screen->texOffsetFinish); __glXScreenInit(&screen->base, pScreen); /* The first call simply determines the length of the extension string. * This allows us to allocate some memory to hold the extension string, * but it requires that we call __glXGetExtensionString a second time. */ 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; } _X_EXPORT __GLXprovider __glXDRIProvider = { __glXDRIscreenProbe, "DRI", NULL };