/* * Copyright © 2008 George Sapountzis * Copyright © 2008 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 the * copyright holders not be used in advertising or publicity * pertaining to distribution of the software without specific, * written prior permission. The copyright holders make no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied * warranty. * * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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 "scrnintstr.h" #include "pixmapstr.h" #include "gcstruct.h" #include "os.h" #include "glxserver.h" #include "glxutil.h" #include "glxdricommon.h" #include "extension_string.h" /* RTLD_LOCAL is not defined on Cygwin */ #ifdef __CYGWIN__ #ifndef RTLD_LOCAL #define RTLD_LOCAL 0 #endif #endif typedef struct __GLXDRIscreen __GLXDRIscreen; typedef struct __GLXDRIcontext __GLXDRIcontext; typedef struct __GLXDRIdrawable __GLXDRIdrawable; struct __GLXDRIscreen { __GLXscreen base; __DRIscreen *driScreen; void *driver; const __DRIcoreExtension *core; const __DRIswrastExtension *swrast; const __DRIcopySubBufferExtension *copySubBuffer; const __DRItexBufferExtension *texBuffer; const __DRIconfig **driConfigs; unsigned char glx_enable_bits[__GLX_EXT_BYTES]; }; struct __GLXDRIcontext { __GLXcontext base; __DRIcontext *driContext; }; struct __GLXDRIdrawable { __GLXdrawable base; __DRIdrawable *driDrawable; __GLXDRIscreen *screen; GCPtr gc; /* scratch GC for span drawing */ GCPtr swapgc; /* GC for swapping the color buffers */ }; static void __glXDRIdrawableDestroy(__GLXdrawable * drawable) { __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; const __DRIcoreExtension *core = private->screen->core; (*core->destroyDrawable) (private->driDrawable); FreeGC(private->gc, (GContext) 0); FreeGC(private->swapgc, (GContext) 0); __glXDrawableRelease(drawable); free(private); } static GLboolean __glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable * drawable) { __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; const __DRIcoreExtension *core = private->screen->core; (*core->swapBuffers) (private->driDrawable); return TRUE; } static void __glXDRIdrawableCopySubBuffer(__GLXdrawable * basePrivate, int x, int y, int w, int h) { __GLXDRIdrawable *private = (__GLXDRIdrawable *) basePrivate; const __DRIcopySubBufferExtension *copySubBuffer = private->screen->copySubBuffer; if (copySubBuffer) (*copySubBuffer->copySubBuffer) (private->driDrawable, x, y, w, h); } 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 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 __DRI_TEX_BUFFER_VERSION >= 2 if (texBuffer->base.version >= 2 && texBuffer->setTexBuffer2 != NULL) { (*texBuffer->setTexBuffer2) (context->driContext, glxPixmap->target, glxPixmap->format, drawable->driDrawable); } else #endif 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 void __glXDRIscreenDestroy(__GLXscreen * baseScreen) { int i; __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); } free(screen); } 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; const __DRIcoreExtension *core = screen->core; __DRIcontext *driShare; /* DRISWRAST won't support createContextAttribs, so these parameters will * never be used. */ (void) num_attribs; (void) attribs; (void) error; shareContext = (__GLXDRIcontext *) baseShareContext; if (shareContext) driShare = shareContext->driContext; else driShare = NULL; context = calloc(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.textureFromPixmap = &__glXDRItextureFromPixmap; context->driContext = (*core->createNewContext) (screen->driScreen, config->driConfig, driShare, context); return &context->base; } static __GLXdrawable * __glXDRIscreenCreateDrawable(ClientPtr client, __GLXscreen * screen, DrawablePtr pDraw, XID drawId, int type, XID glxDrawId, __GLXconfig * glxConfig) { XID gcvals[2]; int status; __GLXDRIscreen *driScreen = (__GLXDRIscreen *) screen; __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig; __GLXDRIdrawable *private; 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; gcvals[0] = GXcopy; private->gc = CreateGC(pDraw, GCFunction, gcvals, &status, (XID) 0, serverClient); gcvals[1] = FALSE; private->swapgc = CreateGC(pDraw, GCFunction | GCGraphicsExposures, gcvals, &status, (XID) 0, serverClient); private->driDrawable = (*driScreen->swrast->createNewDrawable) (driScreen->driScreen, config->driConfig, private); return &private->base; } static void swrastGetDrawableInfo(__DRIdrawable * draw, int *x, int *y, int *w, int *h, void *loaderPrivate) { __GLXDRIdrawable *drawable = loaderPrivate; DrawablePtr pDraw = drawable->base.pDraw; *x = pDraw->x; *y = pDraw->y; *w = pDraw->width; *h = pDraw->height; } static void swrastPutImage(__DRIdrawable * draw, int op, int x, int y, int w, int h, char *data, void *loaderPrivate) { __GLXDRIdrawable *drawable = loaderPrivate; DrawablePtr pDraw = drawable->base.pDraw; GCPtr gc; __GLXcontext *cx = lastGLContext; switch (op) { case __DRI_SWRAST_IMAGE_OP_DRAW: gc = drawable->gc; break; case __DRI_SWRAST_IMAGE_OP_SWAP: gc = drawable->swapgc; break; default: return; } ValidateGC(pDraw, gc); gc->ops->PutImage(pDraw, gc, pDraw->depth, x, y, w, h, 0, ZPixmap, data); if (cx != lastGLContext) { lastGLContext = cx; cx->makeCurrent(cx); } } static void swrastGetImage(__DRIdrawable * draw, int x, int y, int w, int h, char *data, void *loaderPrivate) { __GLXDRIdrawable *drawable = loaderPrivate; DrawablePtr pDraw = drawable->base.pDraw; ScreenPtr pScreen = pDraw->pScreen; __GLXcontext *cx = lastGLContext; pScreen->GetImage(pDraw, x, y, w, h, ZPixmap, ~0L, data); if (cx != lastGLContext) { lastGLContext = cx; cx->makeCurrent(cx); } } static const __DRIswrastLoaderExtension swrastLoaderExtension = { {__DRI_SWRAST_LOADER, 1}, swrastGetDrawableInfo, swrastPutImage, swrastGetImage }; static const __DRIextension *loader_extensions[] = { &systemTimeExtension.base, &swrastLoaderExtension.base, NULL }; static void initializeExtensions(__GLXDRIscreen * screen) { const __DRIextension **extensions; int i; __glXEnableExtension(screen->glx_enable_bits, "GLX_MESA_copy_sub_buffer"); LogMessage(X_INFO, "AIGLX: enabled GLX_MESA_copy_sub_buffer\n"); if (screen->swrast->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"); } /* these are harmless to enable unconditionally */ __glXEnableExtension(screen->glx_enable_bits, "GLX_EXT_framebuffer_sRGB"); __glXEnableExtension(screen->glx_enable_bits, "GLX_ARB_fbconfig_float"); __glXEnableExtension(screen->glx_enable_bits, "GLX_EXT_fbconfig_packed_float"); __glXEnableExtension(screen->glx_enable_bits, "GLX_SGI_make_current_read"); extensions = screen->core->getExtensions(screen->driScreen); for (i = 0; extensions[i]; i++) { if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) { screen->copySubBuffer = (const __DRIcopySubBufferExtension *) extensions[i]; } if (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0) { screen->texBuffer = (const __DRItexBufferExtension *) extensions[i]; /* GLX_EXT_texture_from_pixmap is always enabled. */ } #ifdef __DRI2_FLUSH_CONTROL if (strcmp(extensions[i]->name, __DRI2_FLUSH_CONTROL) == 0) { __glXEnableExtension(screen->glx_enable_bits, "GLX_ARB_context_flush_control\n"); } #endif } } /* white lie */ extern glx_func_ptr glXGetProcAddressARB(const char *); static __GLXscreen * __glXDRIscreenProbe(ScreenPtr pScreen) { const char *driverName = "swrast"; __GLXDRIscreen *screen; size_t buffer_size; screen = calloc(1, sizeof *screen); if (screen == NULL) return NULL; screen->base.destroy = __glXDRIscreenDestroy; screen->base.createContext = __glXDRIscreenCreateContext; screen->base.createDrawable = __glXDRIscreenCreateDrawable; screen->base.swapInterval = NULL; screen->base.pScreen = pScreen; __glXInitExtensionEnableBits(screen->glx_enable_bits); screen->driver = glxProbeDriver(driverName, (void **) &screen->core, __DRI_CORE, 1, (void **) &screen->swrast, __DRI_SWRAST, 1); if (screen->driver == NULL) { goto handle_error; } screen->driScreen = (*screen->swrast->createNewScreen) (pScreen->myNum, 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); screen->base.fbconfigs = glxConvertConfigs(screen->core, screen->driConfigs, GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT); __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) { free(screen->base.GLXextensions); screen->base.GLXextensions = xnfalloc(buffer_size); (void) __glXGetExtensionString(screen->glx_enable_bits, screen->base.GLXextensions); } screen->base.GLXmajor = 1; screen->base.GLXminor = 4; __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, "GLX: could not load software renderer\n"); return NULL; } _X_EXPORT __GLXprovider __glXDRISWRastProvider = { __glXDRIscreenProbe, "DRISWRAST", NULL };