515 lines
15 KiB
C
515 lines
15 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;
|
|
|
|
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 */
|
|
};
|
|
|
|
/* white lie */
|
|
extern glx_func_ptr glXGetProcAddressARB(const char *);
|
|
|
|
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 __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.config = glxConfig;
|
|
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(__GLXscreen * screen)
|
|
{
|
|
const __DRIextension **extensions;
|
|
__GLXDRIscreen *dri = (__GLXDRIscreen *)screen;
|
|
int i;
|
|
|
|
__glXEnableExtension(screen->glx_enable_bits, "GLX_MESA_copy_sub_buffer");
|
|
LogMessage(X_INFO, "IGLX: enabled GLX_MESA_copy_sub_buffer\n");
|
|
|
|
if (dri->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_EXT_texture_from_pixmap");
|
|
|
|
extensions = dri->core->getExtensions(dri->driScreen);
|
|
|
|
for (i = 0; extensions[i]; i++) {
|
|
if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) {
|
|
dri->copySubBuffer =
|
|
(const __DRIcopySubBufferExtension *) extensions[i];
|
|
}
|
|
|
|
if (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0) {
|
|
dri->texBuffer = (const __DRItexBufferExtension *) extensions[i];
|
|
}
|
|
|
|
#ifdef __DRI2_FLUSH_CONTROL
|
|
if (strcmp(extensions[i]->name, __DRI2_FLUSH_CONTROL) == 0) {
|
|
__glXEnableExtension(screen->glx_enable_bits,
|
|
"GLX_ARB_context_flush_control");
|
|
}
|
|
#endif
|
|
|
|
}
|
|
}
|
|
|
|
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 __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;
|
|
|
|
__glXInitExtensionEnableBits(screen->base.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, "IGLX error: Calling driver entry point failed\n");
|
|
goto handle_error;
|
|
}
|
|
|
|
initializeExtensions(&screen->base);
|
|
|
|
screen->base.fbconfigs = glxConvertConfigs(screen->core,
|
|
screen->driConfigs);
|
|
|
|
#if !defined(XQUARTZ) && !defined(WIN32)
|
|
screen->base.glvnd = strdup("mesa");
|
|
#endif
|
|
__glXScreenInit(&screen->base, pScreen);
|
|
|
|
__glXsetGetProcAddress(glXGetProcAddressARB);
|
|
|
|
LogMessage(X_INFO, "IGLX: 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
|
|
};
|