1a66cad3fb
Tested by bru@, jsg@ and others
1038 lines
31 KiB
C
1038 lines
31 KiB
C
/*
|
|
* 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 <dix-config.h>
|
|
#endif
|
|
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <dlfcn.h>
|
|
|
|
#include <GL/gl.h>
|
|
#include <GL/internal/dri_interface.h>
|
|
#include <GL/glxtokens.h>
|
|
|
|
#include <windowstr.h>
|
|
#include <os.h>
|
|
|
|
#define _XF86DRI_SERVER_
|
|
#include <xf86.h>
|
|
#include <dri2.h>
|
|
|
|
#include "glxserver.h"
|
|
#include "glxutil.h"
|
|
#include "glxdricommon.h"
|
|
#include <GL/glxtokens.h>
|
|
|
|
#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.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\n");
|
|
}
|
|
#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
|
|
};
|