/* * Copyright © 2007 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 #define _XF86DRI_SERVER_ #include #include #include "glxserver.h" #include "glxutil.h" #include "glxdricommon.h" #include #include "extension_string.h" typedef struct __GLXDRIscreen __GLXDRIscreen; typedef struct __GLXDRIcontext __GLXDRIcontext; typedef struct __GLXDRIdrawable __GLXDRIdrawable; #define ALL_DRI_CTX_FLAGS (__DRI_CTX_FLAG_DEBUG \ | __DRI_CTX_FLAG_FORWARD_COMPATIBLE \ | __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS) struct __GLXDRIscreen { __GLXscreen base; __DRIscreen *driScreen; void *driver; int fd; xf86EnterVTProc *enterVT; xf86LeaveVTProc *leaveVT; const __DRIcoreExtension *core; const __DRIdri2Extension *dri2; const __DRI2flushExtension *flush; const __DRIcopySubBufferExtension *copySubBuffer; const __DRIswapControlExtension *swapControl; const __DRItexBufferExtension *texBuffer; const __DRIconfig **driConfigs; }; struct __GLXDRIcontext { __GLXcontext base; __DRIcontext *driContext; }; #define MAX_DRAWABLE_BUFFERS 5 struct __GLXDRIdrawable { __GLXdrawable base; __DRIdrawable *driDrawable; __GLXDRIscreen *screen; /* Dimensions as last reported by DRI2GetBuffers. */ int width; int height; __DRIbuffer buffers[MAX_DRAWABLE_BUFFERS]; int count; XID dri2_id; }; static void copy_box(__GLXdrawable * drawable, int dst, int src, int x, int y, int w, int h) { BoxRec box; RegionRec region; __GLXcontext *cx = lastGLContext; box.x1 = x; box.y1 = y; box.x2 = x + w; box.y2 = y + h; RegionInit(®ion, &box, 0); DRI2CopyRegion(drawable->pDraw, ®ion, dst, src); if (cx != lastGLContext) { lastGLContext = cx; cx->makeCurrent(cx); } } /* white lie */ extern glx_func_ptr glXGetProcAddressARB(const char *); static void __glXDRIdrawableDestroy(__GLXdrawable * drawable) { __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; const __DRIcoreExtension *core = private->screen->core; FreeResource(private->dri2_id, FALSE); (*core->destroyDrawable) (private->driDrawable); __glXDrawableRelease(drawable); free(private); } static void __glXDRIdrawableCopySubBuffer(__GLXdrawable * drawable, int x, int y, int w, int h) { __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; copy_box(drawable, x, private->height - y - h, w, h, DRI2BufferFrontLeft, DRI2BufferBackLeft); } static void __glXDRIdrawableWaitX(__GLXdrawable * drawable) { __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; copy_box(drawable, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft, 0, 0, private->width, private->height); } static void __glXDRIdrawableWaitGL(__GLXdrawable * drawable) { __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; copy_box(drawable, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft, 0, 0, private->width, private->height); } static void __glXdriSwapEvent(ClientPtr client, void *data, int type, CARD64 ust, CARD64 msc, CARD32 sbc) { __GLXdrawable *drawable = data; int glx_type; switch (type) { case DRI2_EXCHANGE_COMPLETE: glx_type = GLX_EXCHANGE_COMPLETE_INTEL; break; default: /* unknown swap completion type, * BLIT is a reasonable default, so * fall through ... */ case DRI2_BLIT_COMPLETE: glx_type = GLX_BLIT_COMPLETE_INTEL; break; case DRI2_FLIP_COMPLETE: glx_type = GLX_FLIP_COMPLETE_INTEL; break; } __glXsendSwapEvent(drawable, glx_type, ust, msc, sbc); } /* * Copy or flip back to front, honoring the swap interval if possible. * * If the kernel supports it, we request an event for the frame when the * swap should happen, then perform the copy when we receive it. */ static GLboolean __glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable * drawable) { __GLXDRIdrawable *priv = (__GLXDRIdrawable *) drawable; __GLXDRIscreen *screen = priv->screen; CARD64 unused; __GLXcontext *cx = lastGLContext; int status; if (screen->flush) { (*screen->flush->flush) (priv->driDrawable); (*screen->flush->invalidate) (priv->driDrawable); } status = DRI2SwapBuffers(client, drawable->pDraw, 0, 0, 0, &unused, __glXdriSwapEvent, drawable); if (cx != lastGLContext) { lastGLContext = cx; cx->makeCurrent(cx); } return status == Success; } static int __glXDRIdrawableSwapInterval(__GLXdrawable * drawable, int interval) { __GLXcontext *cx = lastGLContext; if (interval <= 0) /* || interval > BIGNUM? */ return GLX_BAD_VALUE; DRI2SwapInterval(drawable->pDraw, interval); if (cx != lastGLContext) { lastGLContext = cx; cx->makeCurrent(cx); } return 0; } static void __glXDRIcontextDestroy(__GLXcontext * baseContext) { __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; (*screen->core->destroyContext) (context->driContext); __glXContextDestroy(&context->base); free(context); } static int __glXDRIcontextMakeCurrent(__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 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 Bool __glXDRIcontextWait(__GLXcontext * baseContext, __GLXclientState * cl, int *error) { __GLXcontext *cx = lastGLContext; Bool ret; ret = DRI2WaitSwap(cl->client, baseContext->drawPriv->pDraw); if (cx != lastGLContext) { lastGLContext = cx; cx->makeCurrent(cx); } if (ret) { *error = -1; return TRUE; } return FALSE; } static int __glXDRIbindTexImage(__GLXcontext * baseContext, int buffer, __GLXdrawable * glxPixmap) { __GLXDRIdrawable *drawable = (__GLXDRIdrawable *) glxPixmap; const __DRItexBufferExtension *texBuffer = drawable->screen->texBuffer; __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; if (texBuffer == NULL) return Success; if (texBuffer->base.version >= 2 && texBuffer->setTexBuffer2 != NULL) { (*texBuffer->setTexBuffer2) (context->driContext, glxPixmap->target, glxPixmap->format, drawable->driDrawable); } else { texBuffer->setTexBuffer(context->driContext, glxPixmap->target, drawable->driDrawable); } return Success; } static int __glXDRIreleaseTexImage(__GLXcontext * baseContext, int buffer, __GLXdrawable * pixmap) { /* FIXME: Just unbind the texture? */ return Success; } static __GLXtextureFromPixmap __glXDRItextureFromPixmap = { __glXDRIbindTexImage, __glXDRIreleaseTexImage }; static Bool dri2_convert_glx_attribs(__GLXDRIscreen *screen, unsigned num_attribs, const uint32_t *attribs, unsigned *major_ver, unsigned *minor_ver, uint32_t *flags, int *api, int *reset, unsigned *error) { unsigned i; if (num_attribs == 0) return True; if (attribs == NULL) { *error = BadImplementation; return False; } *major_ver = 1; *minor_ver = 0; *reset = __DRI_CTX_RESET_NO_NOTIFICATION; for (i = 0; i < num_attribs; i++) { switch (attribs[i * 2]) { case GLX_CONTEXT_MAJOR_VERSION_ARB: *major_ver = attribs[i * 2 + 1]; break; case GLX_CONTEXT_MINOR_VERSION_ARB: *minor_ver = attribs[i * 2 + 1]; break; case GLX_CONTEXT_FLAGS_ARB: *flags = attribs[i * 2 + 1]; break; case GLX_RENDER_TYPE: break; case GLX_CONTEXT_PROFILE_MASK_ARB: switch (attribs[i * 2 + 1]) { case GLX_CONTEXT_CORE_PROFILE_BIT_ARB: *api = __DRI_API_OPENGL_CORE; break; case GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB: *api = __DRI_API_OPENGL; break; case GLX_CONTEXT_ES2_PROFILE_BIT_EXT: *api = __DRI_API_GLES2; break; default: *error = __glXError(GLXBadProfileARB); return False; } break; case GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB: if (screen->dri2->base.version >= 4) { *error = BadValue; return False; } switch (attribs[i * 2 + 1]) { case GLX_NO_RESET_NOTIFICATION_ARB: *reset = __DRI_CTX_RESET_NO_NOTIFICATION; break; case GLX_LOSE_CONTEXT_ON_RESET_ARB: *reset = __DRI_CTX_RESET_LOSE_CONTEXT; break; default: *error = BadValue; return False; } break; default: /* If an unknown attribute is received, fail. */ *error = BadValue; return False; } } /* Unknown flag value. */ if ((*flags & ~ALL_DRI_CTX_FLAGS) != 0) { *error = BadValue; return False; } /* If the core profile is requested for a GL version is less than 3.2, * request the non-core profile from the DRI driver. The core profile * only makes sense for GL versions >= 3.2, and many DRI drivers that * don't support OpenGL 3.2 may fail the request for a core profile. */ if (*api == __DRI_API_OPENGL_CORE && (*major_ver < 3 || (*major_ver == 3 && *minor_ver < 2))) { *api = __DRI_API_OPENGL; } *error = Success; return True; } static void create_driver_context(__GLXDRIcontext * context, __GLXDRIscreen * screen, __GLXDRIconfig * config, __DRIcontext * driShare, unsigned num_attribs, const uint32_t *attribs, int *error) { context->driContext = NULL; if (screen->dri2->base.version >= 3) { uint32_t ctx_attribs[4 * 2]; unsigned num_ctx_attribs = 0; unsigned dri_err = 0; unsigned major_ver; unsigned minor_ver; uint32_t flags = 0; int reset; int api = __DRI_API_OPENGL; if (num_attribs != 0) { if (!dri2_convert_glx_attribs(screen, num_attribs, attribs, &major_ver, &minor_ver, &flags, &api, &reset, (unsigned *) error)) return; ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION; ctx_attribs[num_ctx_attribs++] = major_ver; ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION; ctx_attribs[num_ctx_attribs++] = minor_ver; if (flags != 0) { ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS; /* The current __DRI_CTX_FLAG_* values are identical to the * GLX_CONTEXT_*_BIT values. */ ctx_attribs[num_ctx_attribs++] = flags; } if (reset != __DRI_CTX_RESET_NO_NOTIFICATION) { ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_RESET_STRATEGY; ctx_attribs[num_ctx_attribs++] = reset; } assert(num_ctx_attribs <= ARRAY_SIZE(ctx_attribs)); } context->driContext = (*screen->dri2->createContextAttribs)(screen->driScreen, api, config->driConfig, driShare, num_ctx_attribs / 2, ctx_attribs, &dri_err, context); switch (dri_err) { case __DRI_CTX_ERROR_SUCCESS: *error = Success; break; case __DRI_CTX_ERROR_NO_MEMORY: *error = BadAlloc; break; case __DRI_CTX_ERROR_BAD_API: *error = __glXError(GLXBadProfileARB); break; case __DRI_CTX_ERROR_BAD_VERSION: case __DRI_CTX_ERROR_BAD_FLAG: *error = __glXError(GLXBadFBConfig); break; case __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE: case __DRI_CTX_ERROR_UNKNOWN_FLAG: default: *error = BadValue; break; } return; } if (num_attribs != 0) { *error = BadValue; return; } context->driContext = (*screen->dri2->createNewContext) (screen->driScreen, config->driConfig, driShare, context); } static __GLXcontext * __glXDRIscreenCreateContext(__GLXscreen * baseScreen, __GLXconfig * glxConfig, __GLXcontext * baseShareContext, unsigned num_attribs, const uint32_t *attribs, int *error) { __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen; __GLXDRIcontext *context, *shareContext; __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig; __DRIcontext *driShare; shareContext = (__GLXDRIcontext *) baseShareContext; if (shareContext) driShare = shareContext->driContext; else driShare = NULL; context = calloc(1, sizeof *context); if (context == NULL) { *error = BadAlloc; return NULL; } context->base.config = glxConfig; context->base.destroy = __glXDRIcontextDestroy; context->base.makeCurrent = __glXDRIcontextMakeCurrent; context->base.loseCurrent = __glXDRIcontextLoseCurrent; context->base.copy = __glXDRIcontextCopy; context->base.textureFromPixmap = &__glXDRItextureFromPixmap; context->base.wait = __glXDRIcontextWait; create_driver_context(context, screen, config, driShare, num_attribs, attribs, error); if (context->driContext == NULL) { free(context); return NULL; } return &context->base; } static void __glXDRIinvalidateBuffers(DrawablePtr pDraw, void *priv, XID id) { __GLXDRIdrawable *private = priv; __GLXDRIscreen *screen = private->screen; if (screen->flush) (*screen->flush->invalidate) (private->driDrawable); } 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; __GLXcontext *cx = lastGLContext; Bool ret; private = calloc(1, sizeof *private); if (private == NULL) return NULL; private->screen = driScreen; if (!__glXDrawableInit(&private->base, screen, pDraw, type, glxDrawId, glxConfig)) { free(private); return NULL; } private->base.destroy = __glXDRIdrawableDestroy; private->base.swapBuffers = __glXDRIdrawableSwapBuffers; private->base.copySubBuffer = __glXDRIdrawableCopySubBuffer; private->base.waitGL = __glXDRIdrawableWaitGL; private->base.waitX = __glXDRIdrawableWaitX; ret = DRI2CreateDrawable2(client, pDraw, drawId, __glXDRIinvalidateBuffers, private, &private->dri2_id); if (cx != lastGLContext) { lastGLContext = cx; cx->makeCurrent(cx); } if (ret) { free(private); return NULL; } private->driDrawable = (*driScreen->dri2->createNewDrawable) (driScreen->driScreen, config->driConfig, private); return &private->base; } static __DRIbuffer * dri2GetBuffers(__DRIdrawable * driDrawable, int *width, int *height, unsigned int *attachments, int count, int *out_count, void *loaderPrivate) { __GLXDRIdrawable *private = loaderPrivate; DRI2BufferPtr *buffers; int i; int j; __GLXcontext *cx = lastGLContext; buffers = DRI2GetBuffers(private->base.pDraw, width, height, attachments, count, out_count); if (cx != lastGLContext) { lastGLContext = cx; cx->makeCurrent(cx); /* If DRI2GetBuffers() changed the GL context, it may also have * invalidated the DRI2 buffers, so let's get them again */ buffers = DRI2GetBuffers(private->base.pDraw, width, height, attachments, count, out_count); assert(lastGLContext == cx); } if (*out_count > MAX_DRAWABLE_BUFFERS) { *out_count = 0; return NULL; } private->width = *width; private->height = *height; /* This assumes the DRI2 buffer attachment tokens matches the * __DRIbuffer tokens. */ j = 0; for (i = 0; i < *out_count; i++) { /* Do not send the real front buffer of a window to the client. */ if ((private->base.pDraw->type == DRAWABLE_WINDOW) && (buffers[i]->attachment == DRI2BufferFrontLeft)) { continue; } private->buffers[j].attachment = buffers[i]->attachment; private->buffers[j].name = buffers[i]->name; private->buffers[j].pitch = buffers[i]->pitch; private->buffers[j].cpp = buffers[i]->cpp; private->buffers[j].flags = buffers[i]->flags; j++; } *out_count = j; return private->buffers; } static __DRIbuffer * dri2GetBuffersWithFormat(__DRIdrawable * driDrawable, int *width, int *height, unsigned int *attachments, int count, int *out_count, void *loaderPrivate) { __GLXDRIdrawable *private = loaderPrivate; DRI2BufferPtr *buffers; int i; int j = 0; __GLXcontext *cx = lastGLContext; buffers = DRI2GetBuffersWithFormat(private->base.pDraw, width, height, attachments, count, out_count); if (cx != lastGLContext) { lastGLContext = cx; cx->makeCurrent(cx); /* If DRI2GetBuffersWithFormat() changed the GL context, it may also have * invalidated the DRI2 buffers, so let's get them again */ buffers = DRI2GetBuffersWithFormat(private->base.pDraw, width, height, attachments, count, out_count); assert(lastGLContext == cx); } if (*out_count > MAX_DRAWABLE_BUFFERS) { *out_count = 0; return NULL; } private->width = *width; private->height = *height; /* This assumes the DRI2 buffer attachment tokens matches the * __DRIbuffer tokens. */ for (i = 0; i < *out_count; i++) { /* Do not send the real front buffer of a window to the client. */ if ((private->base.pDraw->type == DRAWABLE_WINDOW) && (buffers[i]->attachment == DRI2BufferFrontLeft)) { continue; } private->buffers[j].attachment = buffers[i]->attachment; private->buffers[j].name = buffers[i]->name; private->buffers[j].pitch = buffers[i]->pitch; private->buffers[j].cpp = buffers[i]->cpp; private->buffers[j].flags = buffers[i]->flags; j++; } *out_count = j; return private->buffers; } static void dri2FlushFrontBuffer(__DRIdrawable * driDrawable, void *loaderPrivate) { __GLXDRIdrawable *private = (__GLXDRIdrawable *) loaderPrivate; (void) driDrawable; copy_box(loaderPrivate, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft, 0, 0, private->width, private->height); } static const __DRIdri2LoaderExtension loaderExtension = { {__DRI_DRI2_LOADER, 3}, dri2GetBuffers, dri2FlushFrontBuffer, dri2GetBuffersWithFormat, }; static const __DRIuseInvalidateExtension dri2UseInvalidate = { {__DRI_USE_INVALIDATE, 1} }; static const __DRIextension *loader_extensions[] = { &systemTimeExtension.base, &loaderExtension.base, &dri2UseInvalidate.base, NULL }; static Bool glxDRIEnterVT(ScrnInfoPtr scrn) { Bool ret; __GLXDRIscreen *screen = (__GLXDRIscreen *) glxGetScreen(xf86ScrnToScreen(scrn)); LogMessage(X_INFO, "AIGLX: Resuming AIGLX clients after VT switch\n"); scrn->EnterVT = screen->enterVT; ret = scrn->EnterVT(scrn); screen->enterVT = scrn->EnterVT; scrn->EnterVT = glxDRIEnterVT; if (!ret) return FALSE; glxResumeClients(); return TRUE; } static void glxDRILeaveVT(ScrnInfoPtr scrn) { __GLXDRIscreen *screen = (__GLXDRIscreen *) glxGetScreen(xf86ScrnToScreen(scrn)); LogMessageVerbSigSafe(X_INFO, -1, "AIGLX: Suspending AIGLX clients for VT switch\n"); glxSuspendClients(); scrn->LeaveVT = screen->leaveVT; (*screen->leaveVT) (scrn); screen->leaveVT = scrn->LeaveVT; scrn->LeaveVT = glxDRILeaveVT; } /** * Initialize extension flags in glx_enable_bits when a new screen is created * * @param screen The screen where glx_enable_bits are to be set. */ static void initializeExtensions(__GLXscreen * screen) { ScreenPtr pScreen = screen->pScreen; __GLXDRIscreen *dri = (__GLXDRIscreen *)screen; const __DRIextension **extensions; int i; extensions = dri->core->getExtensions(dri->driScreen); __glXEnableExtension(screen->glx_enable_bits, "GLX_MESA_copy_sub_buffer"); LogMessage(X_INFO, "AIGLX: enabled GLX_MESA_copy_sub_buffer\n"); if (dri->dri2->base.version >= 3) { __glXEnableExtension(screen->glx_enable_bits, "GLX_ARB_create_context"); __glXEnableExtension(screen->glx_enable_bits, "GLX_ARB_create_context_profile"); __glXEnableExtension(screen->glx_enable_bits, "GLX_EXT_create_context_es_profile"); __glXEnableExtension(screen->glx_enable_bits, "GLX_EXT_create_context_es2_profile"); LogMessage(X_INFO, "AIGLX: enabled GLX_ARB_create_context\n"); LogMessage(X_INFO, "AIGLX: enabled GLX_ARB_create_context_profile\n"); LogMessage(X_INFO, "AIGLX: enabled GLX_EXT_create_context_es{,2}_profile\n"); } if (DRI2HasSwapControl(pScreen)) { __glXEnableExtension(screen->glx_enable_bits, "GLX_INTEL_swap_event"); __glXEnableExtension(screen->glx_enable_bits, "GLX_SGI_swap_control"); LogMessage(X_INFO, "AIGLX: enabled GLX_INTEL_swap_event\n"); LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_swap_control\n"); } /* enable EXT_framebuffer_sRGB extension (even if there are no sRGB capable fbconfigs) */ { __glXEnableExtension(screen->glx_enable_bits, "GLX_EXT_framebuffer_sRGB"); LogMessage(X_INFO, "AIGLX: enabled GLX_EXT_framebuffer_sRGB\n"); } /* enable ARB_fbconfig_float extension (even if there are no float fbconfigs) */ { __glXEnableExtension(screen->glx_enable_bits, "GLX_ARB_fbconfig_float"); LogMessage(X_INFO, "AIGLX: enabled GLX_ARB_fbconfig_float\n"); } /* enable EXT_fbconfig_packed_float (even if there are no packed float fbconfigs) */ { __glXEnableExtension(screen->glx_enable_bits, "GLX_EXT_fbconfig_packed_float"); LogMessage(X_INFO, "AIGLX: enabled GLX_EXT_fbconfig_packed_float\n"); } for (i = 0; extensions[i]; i++) { if (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0) { dri->texBuffer = (const __DRItexBufferExtension *) extensions[i]; __glXEnableExtension(screen->glx_enable_bits, "GLX_EXT_texture_from_pixmap"); LogMessage(X_INFO, "AIGLX: GLX_EXT_texture_from_pixmap backed by buffer objects\n"); } if (strcmp(extensions[i]->name, __DRI2_FLUSH) == 0 && extensions[i]->version >= 3) { dri->flush = (__DRI2flushExtension *) extensions[i]; } if (strcmp(extensions[i]->name, __DRI2_ROBUSTNESS) == 0 && dri->dri2->base.version >= 3) { __glXEnableExtension(screen->glx_enable_bits, "GLX_ARB_create_context_robustness"); LogMessage(X_INFO, "AIGLX: enabled GLX_ARB_create_context_robustness\n"); } #ifdef __DRI2_FLUSH_CONTROL if (strcmp(extensions[i]->name, __DRI2_FLUSH_CONTROL) == 0) { __glXEnableExtension(screen->glx_enable_bits, "GLX_ARB_context_flush_control"); } #endif /* Ignore unknown extensions */ } } static void __glXDRIscreenDestroy(__GLXscreen * baseScreen) { int i; ScrnInfoPtr pScrn = xf86ScreenToScrn(baseScreen->pScreen); __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen; (*screen->core->destroyScreen) (screen->driScreen); dlclose(screen->driver); __glXScreenDestroy(baseScreen); if (screen->driConfigs) { for (i = 0; screen->driConfigs[i] != NULL; i++) free((__DRIconfig **) screen->driConfigs[i]); free(screen->driConfigs); } pScrn->EnterVT = screen->enterVT; pScrn->LeaveVT = screen->leaveVT; free(screen); } enum { GLXOPT_VENDOR_LIBRARY, }; static const OptionInfoRec GLXOptions[] = { { GLXOPT_VENDOR_LIBRARY, "GlxVendorLibrary", OPTV_STRING, {0}, FALSE }, { -1, NULL, OPTV_NONE, {0}, FALSE }, }; static __GLXscreen * __glXDRIscreenProbe(ScreenPtr pScreen) { const char *driverName, *deviceName; __GLXDRIscreen *screen; ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); const char *glvnd = NULL; OptionInfoPtr options; screen = calloc(1, sizeof *screen); if (screen == NULL) return NULL; if (!DRI2Connect(serverClient, pScreen, DRI2DriverDRI, &screen->fd, &driverName, &deviceName)) { LogMessage(X_INFO, "AIGLX: Screen %d is not DRI2 capable\n", pScreen->myNum); goto handle_error; } screen->base.destroy = __glXDRIscreenDestroy; screen->base.createContext = __glXDRIscreenCreateContext; screen->base.createDrawable = __glXDRIscreenCreateDrawable; screen->base.swapInterval = __glXDRIdrawableSwapInterval; screen->base.pScreen = pScreen; __glXInitExtensionEnableBits(screen->base.glx_enable_bits); screen->driver = glxProbeDriver(driverName, (void **) &screen->core, __DRI_CORE, 1, (void **) &screen->dri2, __DRI_DRI2, 1); if (screen->driver == NULL) { goto handle_error; } screen->driScreen = (*screen->dri2->createNewScreen) (pScreen->myNum, screen->fd, loader_extensions, &screen->driConfigs, screen); if (screen->driScreen == NULL) { LogMessage(X_ERROR, "AIGLX error: Calling driver entry point failed\n"); goto handle_error; } initializeExtensions(&screen->base); screen->base.fbconfigs = glxConvertConfigs(screen->core, screen->driConfigs); options = xnfalloc(sizeof(GLXOptions)); memcpy(options, GLXOptions, sizeof(GLXOptions)); xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, options); glvnd = xf86GetOptValString(options, GLXOPT_VENDOR_LIBRARY); if (glvnd) screen->base.glvnd = xnfstrdup(glvnd); free(options); if (!screen->base.glvnd) screen->base.glvnd = strdup("mesa"); __glXScreenInit(&screen->base, pScreen); screen->enterVT = pScrn->EnterVT; pScrn->EnterVT = glxDRIEnterVT; screen->leaveVT = pScrn->LeaveVT; pScrn->LeaveVT = glxDRILeaveVT; __glXsetGetProcAddress(glXGetProcAddressARB); LogMessage(X_INFO, "AIGLX: Loaded and initialized %s\n", driverName); return &screen->base; handle_error: if (screen->driver) dlclose(screen->driver); free(screen); LogMessage(X_ERROR, "AIGLX: reverting to software rendering\n"); return NULL; } _X_EXPORT __GLXprovider __glXDRI2Provider = { __glXDRIscreenProbe, "DRI2", NULL };