xserver-multidpi/glx/glxdriswrast.c
Adam Jackson be6680967a glx: convert to direct GL dispatch (v2)
We now expect to be linked against something that provides the GL API,
instead of manually grubbing about in the DRI driver's dispatch table.
Since the GLX we expose calls GL functions that are meant to be looked
up dynamically, also add a way to thunk through to GetProcAddress.

This includes a refresh of the generated sources, which requires a
correspondingly new Mesa.

The GetProcAddress stubs are at the moment merely enough to make this
link against Mesa 9.2, but should really be provided for everything not
in the OpenGL 1.2 ABI.

v2: Explicitly hide the GetProcAddress stubs so we can't conflict with
libGL symbols; fix leading tab/space issues [anholt]

Reviewed-by: Keith Packard <keithp@keithp.com>
Signed-off-by: Adam Jackson <ajax@redhat.com>
2013-10-29 12:29:16 -04:00

495 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 "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
};