499 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			499 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * Copyright © 2008 George Sapountzis <gsap7@yahoo.gr>
 | |
|  * 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 <dix-config.h>
 | |
| #endif
 | |
| 
 | |
| #include <stdint.h>
 | |
| #include <stdio.h>
 | |
| #include <string.h>
 | |
| #include <errno.h>
 | |
| #include <sys/time.h>
 | |
| #include <dlfcn.h>
 | |
| 
 | |
| #include <GL/gl.h>
 | |
| #include <GL/internal/dri_interface.h>
 | |
| #include <GL/glxtokens.h>
 | |
| 
 | |
| #include "scrnintstr.h"
 | |
| #include "pixmapstr.h"
 | |
| #include "gcstruct.h"
 | |
| #include "os.h"
 | |
| 
 | |
| #include "glxserver.h"
 | |
| #include "glxutil.h"
 | |
| #include "glxdricommon.h"
 | |
| 
 | |
| #include "glapitable.h"
 | |
| #include "glapi.h"
 | |
| #include "glthread.h"
 | |
| #include "dispatch.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;
 | |
| };
 | |
| 
 | |
| 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);
 | |
| }
 | |
| 
 | |
| #ifdef __DRI_TEX_BUFFER
 | |
| 
 | |
| 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;
 | |
| }
 | |
| 
 | |
| #else
 | |
| 
 | |
| static int
 | |
| __glXDRIbindTexImage(__GLXcontext * baseContext,
 | |
|                      int buffer, __GLXdrawable * glxPixmap)
 | |
| {
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| static int
 | |
| __glXDRIreleaseTexImage(__GLXcontext * baseContext,
 | |
|                         int buffer, __GLXdrawable * pixmap)
 | |
| {
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 | |
| 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->x;
 | |
|     *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;
 | |
| 
 | |
|     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);
 | |
| }
 | |
| 
 | |
| 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;
 | |
| 
 | |
|     pScreen->GetImage(pDraw, x, y, w, h, ZPixmap, ~0L, data);
 | |
| }
 | |
| 
 | |
| static const __DRIswrastLoaderExtension swrastLoaderExtension = {
 | |
|     {__DRI_SWRAST_LOADER, __DRI_SWRAST_LOADER_VERSION},
 | |
|     swrastGetDrawableInfo,
 | |
|     swrastPutImage,
 | |
|     swrastGetImage
 | |
| };
 | |
| 
 | |
| static const __DRIextension *loader_extensions[] = {
 | |
|     &systemTimeExtension.base,
 | |
|     &swrastLoaderExtension.base,
 | |
|     NULL
 | |
| };
 | |
| 
 | |
| 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 =
 | |
|                 (const __DRIcopySubBufferExtension *) extensions[i];
 | |
|             /* GLX_MESA_copy_sub_buffer is always enabled. */
 | |
|         }
 | |
| #endif
 | |
| 
 | |
| #ifdef __DRI_TEX_BUFFER
 | |
|         if (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0) {
 | |
|             screen->texBuffer = (const __DRItexBufferExtension *) extensions[i];
 | |
|             /* GLX_EXT_texture_from_pixmap is always enabled. */
 | |
|         }
 | |
| #endif
 | |
|         /* Ignore unknown extensions */
 | |
|     }
 | |
| }
 | |
| 
 | |
| static __GLXscreen *
 | |
| __glXDRIscreenProbe(ScreenPtr pScreen)
 | |
| {
 | |
|     const char *driverName = "swrast";
 | |
|     __GLXDRIscreen *screen;
 | |
| 
 | |
|     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;
 | |
| 
 | |
|     screen->driver = glxProbeDriver(driverName,
 | |
|                                     (void **) &screen->core,
 | |
|                                     __DRI_CORE, __DRI_CORE_VERSION,
 | |
|                                     (void **) &screen->swrast,
 | |
|                                     __DRI_SWRAST, __DRI_SWRAST_VERSION);
 | |
|     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);
 | |
| 
 | |
|     screen->base.GLXmajor = 1;
 | |
|     screen->base.GLXminor = 4;
 | |
| 
 | |
|     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
 | |
| };
 |