xserver-multidpi/glx/glxdri.c
Søren Sandmann Pedersen 61a92a78cd Add RegionInitBoxes(), and fix some buggy callers of RegionInit().
The interface to RegionInit():

    RegionInit (RegionPtr pReg, BoxPtr rect, int size);

is very confusing because it doesn't take a list of boxes, it takes
*one* box, but if that box is NULL, it initializes an empty region
with 'size' rectangles preallocated.

Most callers of this function were correctly passing either NULL or
just one box, but there were three confused cases, where the code
seems to expect a region to be created from a list of boxes.

This patch adds a new function RegionInitBoxes() and fixes those
instances to call that instead.

And yes, the pixman function to initialize a region from a list of
boxes is called init_rects() because pixman is also awesome.

V2: Make RegionInitBoxes() return a Bool indicating whether the call
    succeeded, and fix the callers to check this return value.

Reviewed-by: Keith Packard <keithp@keithp.com>
Signed-off-by: Søren Sandmann <ssp@redhat.com>
2011-04-22 21:39:31 -04:00

1169 lines
30 KiB
C

/*
* Copyright © 2006 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 <sys/time.h>
#include <dlfcn.h>
#include <drm.h>
#include <GL/gl.h>
#include <GL/internal/dri_interface.h>
#include <GL/glxtokens.h>
#include <windowstr.h>
#include <os.h>
#include <damage.h>
#define _XF86DRI_SERVER_
#include <drm_sarea.h>
#include <xf86drm.h>
#include <X11/dri/xf86driproto.h>
#include <xf86str.h>
#include <xf86.h>
#include <dri.h>
#include "servermd.h"
#define DRI_NEW_INTERFACE_ONLY
#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"
typedef struct __GLXDRIscreen __GLXDRIscreen;
typedef struct __GLXDRIcontext __GLXDRIcontext;
typedef struct __GLXDRIdrawable __GLXDRIdrawable;
struct __GLXDRIscreen {
__GLXscreen base;
__DRIscreen *driScreen;
void *driver;
xf86EnterVTProc *enterVT;
xf86LeaveVTProc *leaveVT;
const __DRIcoreExtension *core;
const __DRIlegacyExtension *legacy;
const __DRIcopySubBufferExtension *copySubBuffer;
const __DRIswapControlExtension *swapControl;
#ifdef __DRI_TEX_OFFSET
const __DRItexOffsetExtension *texOffset;
DRITexOffsetStartProcPtr texOffsetStart;
DRITexOffsetFinishProcPtr texOffsetFinish;
__GLXDRIdrawable *texOffsetOverride[16];
GLuint lastTexOffsetOverride;
#endif
unsigned char glx_enable_bits[__GLX_EXT_BYTES];
};
struct __GLXDRIcontext {
__GLXcontext base;
__DRIcontext *driContext;
XID hwContextID;
};
struct __GLXDRIdrawable {
__GLXdrawable base;
__DRIdrawable *driDrawable;
/* Pulled in from old __GLXpixmap */
#ifdef __DRI_TEX_OFFSET
GLint texname;
__GLXDRIcontext *ctx;
unsigned long long offset;
DamagePtr pDamage;
#endif
};
static void
__glXDRIleaveServer(GLboolean rendering)
{
int i;
for (i = 0; rendering && i < screenInfo.numScreens; i++) {
__GLXDRIscreen * const screen =
(__GLXDRIscreen *) glxGetScreen(screenInfo.screens[i]);
GLuint lastOverride = screen->lastTexOffsetOverride;
if (lastOverride) {
__GLXDRIdrawable **texOffsetOverride = screen->texOffsetOverride;
int j;
for (j = 0; j < lastOverride; j++) {
__GLXDRIdrawable *pGlxPix = texOffsetOverride[j];
if (pGlxPix && pGlxPix->texname) {
pGlxPix->offset =
screen->texOffsetStart((PixmapPtr)pGlxPix->base.pDraw);
}
}
}
}
DRIBlockHandler(NULL, NULL, NULL);
for (i = 0; rendering && i < screenInfo.numScreens; i++) {
__GLXDRIscreen * const screen =
(__GLXDRIscreen *) glxGetScreen(screenInfo.screens[i]);
GLuint lastOverride = screen->lastTexOffsetOverride;
if (lastOverride) {
__GLXDRIdrawable **texOffsetOverride = screen->texOffsetOverride;
int j;
for (j = 0; j < lastOverride; j++) {
__GLXDRIdrawable *pGlxPix = texOffsetOverride[j];
if (pGlxPix && pGlxPix->texname) {
screen->texOffset->setTexOffset(pGlxPix->ctx->driContext,
pGlxPix->texname,
pGlxPix->offset,
pGlxPix->base.pDraw->depth,
((PixmapPtr)pGlxPix->base.pDraw)->devKind);
}
}
}
}
}
static void
__glXDRIenterServer(GLboolean rendering)
{
int i;
for (i = 0; rendering && i < screenInfo.numScreens; i++) {
__GLXDRIscreen * const screen = (__GLXDRIscreen *)
glxGetScreen(screenInfo.screens[i]);
if (screen->lastTexOffsetOverride) {
CALL_Flush(GET_DISPATCH(), ());
break;
}
}
DRIWakeupHandler(NULL, 0, NULL);
}
static void
__glXDRIdoReleaseTexImage(__GLXDRIscreen *screen, __GLXDRIdrawable *drawable)
{
GLuint lastOverride = screen->lastTexOffsetOverride;
if (lastOverride) {
__GLXDRIdrawable **texOffsetOverride = screen->texOffsetOverride;
int i;
for (i = 0; i < lastOverride; i++) {
if (texOffsetOverride[i] == drawable) {
if (screen->texOffsetFinish)
screen->texOffsetFinish((PixmapPtr)drawable->base.pDraw);
texOffsetOverride[i] = NULL;
if (i + 1 == lastOverride) {
lastOverride = 0;
while (i--) {
if (texOffsetOverride[i]) {
lastOverride = i + 1;
break;
}
}
screen->lastTexOffsetOverride = lastOverride;
break;
}
}
}
}
}
static void
__glXDRIdrawableDestroy(__GLXdrawable *drawable)
{
__GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable;
__GLXDRIscreen *screen;
int i;
for (i = 0; i < screenInfo.numScreens; i++) {
screen = (__GLXDRIscreen *) glxGetScreen(screenInfo.screens[i]);
__glXDRIdoReleaseTexImage(screen, private);
}
/* If the X window was destroyed, the dri DestroyWindow hook will
* aready have taken care of this, so only call if pDraw isn't NULL. */
if (drawable->pDraw != NULL) {
screen = (__GLXDRIscreen *) glxGetScreen(drawable->pDraw->pScreen);
(*screen->core->destroyDrawable)(private->driDrawable);
__glXenterServer(GL_FALSE);
DRIDestroyDrawable(drawable->pDraw->pScreen,
serverClient, drawable->pDraw);
__glXleaveServer(GL_FALSE);
}
__glXDrawableRelease(drawable);
free(private);
}
static GLboolean
__glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable *basePrivate)
{
__GLXDRIdrawable *private = (__GLXDRIdrawable *) basePrivate;
__GLXDRIscreen *screen =
(__GLXDRIscreen *) glxGetScreen(basePrivate->pDraw->pScreen);
(*screen->core->swapBuffers)(private->driDrawable);
return TRUE;
}
static int
__glXDRIdrawableSwapInterval(__GLXdrawable *baseDrawable, int interval)
{
__GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseDrawable;
__GLXDRIscreen *screen =
(__GLXDRIscreen *) glxGetScreen(baseDrawable->pDraw->pScreen);
if (screen->swapControl)
screen->swapControl->setSwapInterval(draw->driDrawable, interval);
return 0;
}
static void
__glXDRIdrawableCopySubBuffer(__GLXdrawable *basePrivate,
int x, int y, int w, int h)
{
__GLXDRIdrawable *private = (__GLXDRIdrawable *) basePrivate;
__GLXDRIscreen *screen = (__GLXDRIscreen *)
glxGetScreen(basePrivate->pDraw->pScreen);
if (screen->copySubBuffer)
screen->copySubBuffer->copySubBuffer(private->driDrawable, x, y, w, h);
}
static void
__glXDRIcontextDestroy(__GLXcontext *baseContext)
{
__GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
__GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
Bool retval;
screen->core->destroyContext(context->driContext);
__glXenterServer(GL_FALSE);
retval = DRIDestroyContext(baseContext->pGlxScreen->pScreen,
context->hwContextID);
__glXleaveServer(GL_FALSE);
__glXContextDestroy(&context->base);
free(context);
}
static int
__glXDRIcontextMakeCurrent(__GLXcontext *baseContext)
{
__GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
__GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
__GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv;
__GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv;
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 void
glxFillAlphaChannel (CARD32 *pixels, CARD32 rowstride, int width, int height)
{
int i;
CARD32 *p, *end;
rowstride /= 4;
for (i = 0; i < height; i++)
{
p = pixels;
end = p + width;
while (p < end)
*p++ |= 0xFF000000;
pixels += rowstride;
}
}
static Bool
testTexOffset(__GLXDRIscreen * const screen, PixmapPtr pPixmap)
{
Bool ret;
if (!screen->texOffsetStart || !screen->texOffset)
return FALSE;
__glXenterServer(GL_FALSE);
ret = screen->texOffsetStart(pPixmap) != ~0ULL;
__glXleaveServer(GL_FALSE);
return ret;
}
/*
* (sticking this here for lack of a better place)
* Known issues with the GLX_EXT_texture_from_pixmap implementation:
* - In general we ignore the fbconfig, lots of examples follow
* - No fbconfig handling for multiple mipmap levels
* - No fbconfig handling for 1D textures
* - No fbconfig handling for TEXTURE_TARGET
* - No fbconfig exposure of Y inversion state
* - No GenerateMipmapEXT support (due to no FBO support)
* - No support for anything but 16bpp and 32bpp-sparse pixmaps
*/
static int
__glXDRIbindTexImage(__GLXcontext *baseContext,
int buffer,
__GLXdrawable *glxPixmap)
{
RegionPtr pRegion = NULL;
PixmapPtr pixmap;
int bpp, override = 0, texname;
GLenum format, type;
ScreenPtr pScreen = glxPixmap->pDraw->pScreen;
__GLXDRIdrawable *driDraw = (__GLXDRIdrawable *) glxPixmap;
__GLXDRIscreen * const screen = (__GLXDRIscreen *) glxGetScreen(pScreen);
CALL_GetIntegerv(GET_DISPATCH(), (glxPixmap->target == GL_TEXTURE_2D ?
GL_TEXTURE_BINDING_2D :
GL_TEXTURE_BINDING_RECTANGLE_NV,
&texname));
if (!texname)
return __glXError(GLXBadContextState);
pixmap = (PixmapPtr) glxPixmap->pDraw;
if (testTexOffset(screen, pixmap)) {
__GLXDRIdrawable **texOffsetOverride = screen->texOffsetOverride;
int i, firstEmpty = 16;
for (i = 0; i < 16; i++) {
if (texOffsetOverride[i] == driDraw)
goto alreadyin;
if (firstEmpty == 16 && !texOffsetOverride[i])
firstEmpty = i;
}
if (firstEmpty == 16) {
ErrorF("%s: Failed to register texture offset override\n", __func__);
goto nooverride;
}
if (firstEmpty >= screen->lastTexOffsetOverride)
screen->lastTexOffsetOverride = firstEmpty + 1;
texOffsetOverride[firstEmpty] = driDraw;
alreadyin:
override = 1;
driDraw->ctx = (__GLXDRIcontext*)baseContext;
if (texname == driDraw->texname)
return Success;
driDraw->texname = texname;
screen->texOffset->setTexOffset(driDraw->ctx->driContext, texname, 0,
pixmap->drawable.depth,
pixmap->devKind);
}
nooverride:
if (!driDraw->pDamage) {
if (!override) {
driDraw->pDamage = DamageCreate(NULL, NULL, DamageReportNone,
TRUE, pScreen, NULL);
if (!driDraw->pDamage)
return BadAlloc;
DamageRegister ((DrawablePtr) pixmap, driDraw->pDamage);
}
pRegion = NULL;
} else {
pRegion = DamageRegion(driDraw->pDamage);
if (RegionNil(pRegion))
return Success;
}
/* XXX 24bpp packed, 8, etc */
if (pixmap->drawable.depth >= 24) {
bpp = 4;
format = GL_BGRA;
type =
#if X_BYTE_ORDER == X_BIG_ENDIAN
!override ? GL_UNSIGNED_INT_8_8_8_8_REV :
#endif
GL_UNSIGNED_BYTE;
} else {
bpp = 2;
format = GL_RGB;
type = GL_UNSIGNED_SHORT_5_6_5;
}
if (pRegion == NULL)
{
void *data = NULL;
if (!override) {
unsigned pitch = PixmapBytePad(pixmap->drawable.width,
pixmap->drawable.depth);
data = malloc(pitch * pixmap->drawable.height);
__glXenterServer(GL_FALSE);
pScreen->GetImage(&pixmap->drawable, 0 /*pixmap->drawable.x*/,
0 /*pixmap->drawable.y*/, pixmap->drawable.width,
pixmap->drawable.height, ZPixmap, ~0, data);
__glXleaveServer(GL_FALSE);
if (pixmap->drawable.depth == 24)
glxFillAlphaChannel(data,
pitch,
pixmap->drawable.width,
pixmap->drawable.height);
CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_ROW_LENGTH,
pitch / bpp) );
CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_SKIP_PIXELS, 0) );
CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_SKIP_ROWS, 0) );
}
CALL_TexImage2D( GET_DISPATCH(),
(glxPixmap->target,
0,
bpp == 4 ? 4 : 3,
pixmap->drawable.width,
pixmap->drawable.height,
0,
format,
type,
data) );
free(data);
} else if (!override) {
int i, numRects;
BoxPtr p;
numRects = RegionNumRects (pRegion);
p = RegionRects (pRegion);
CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_SKIP_PIXELS, 0) );
CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_SKIP_ROWS, 0) );
for (i = 0; i < numRects; i++)
{
unsigned pitch = PixmapBytePad(p[i].x2 - p[i].x1,
pixmap->drawable.depth);
void *data = malloc(pitch * (p[i].y2 - p[i].y1));
__glXenterServer(GL_FALSE);
pScreen->GetImage(&pixmap->drawable, /*pixmap->drawable.x +*/ p[i].x1,
/*pixmap->drawable.y*/ + p[i].y1, p[i].x2 - p[i].x1,
p[i].y2 - p[i].y1, ZPixmap, ~0, data);
__glXleaveServer(GL_FALSE);
if (pixmap->drawable.depth == 24)
glxFillAlphaChannel(data,
pitch,
p[i].x2 - p[i].x1,
p[i].y2 - p[i].y1);
CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_ROW_LENGTH,
pitch / bpp) );
CALL_TexSubImage2D( GET_DISPATCH(),
(glxPixmap->target,
0,
p[i].x1, p[i].y1,
p[i].x2 - p[i].x1, p[i].y2 - p[i].y1,
format,
type,
data) );
free(data);
}
}
if (!override)
DamageEmpty(driDraw->pDamage);
return Success;
}
static int
__glXDRIreleaseTexImage(__GLXcontext *baseContext,
int buffer,
__GLXdrawable *pixmap)
{
__GLXDRIscreen *screen =
(__GLXDRIscreen *) glxGetScreen(pixmap->pDraw->pScreen);
__GLXDRIdrawable *drawable = (__GLXDRIdrawable *) pixmap;
__glXDRIdoReleaseTexImage(screen, drawable);
return Success;
}
static __GLXtextureFromPixmap __glXDRItextureFromPixmap = {
__glXDRIbindTexImage,
__glXDRIreleaseTexImage
};
static void
__glXDRIscreenDestroy(__GLXscreen *baseScreen)
{
__GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen;
screen->core->destroyScreen(screen->driScreen);
dlclose(screen->driver);
__glXScreenDestroy(baseScreen);
free(screen);
}
static __GLXcontext *
__glXDRIscreenCreateContext(__GLXscreen *baseScreen,
__GLXconfig *glxConfig,
__GLXcontext *baseShareContext)
{
__GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen;
__GLXDRIcontext *context, *shareContext;
__GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig;
VisualPtr visual;
int i;
GLboolean retval;
__DRIcontext *driShare;
drm_context_t hwContext;
ScreenPtr pScreen = baseScreen->pScreen;
shareContext = (__GLXDRIcontext *) baseShareContext;
if (shareContext)
driShare = shareContext->driContext;
else
driShare = NULL;
if (baseShareContext && baseShareContext->isDirect)
return 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;
/* Find the requested X visual */
visual = pScreen->visuals;
for (i = 0; i < pScreen->numVisuals; i++, visual++)
if (visual->vid == glxConfig->visualID)
break;
if (i == pScreen->numVisuals)
return NULL;
context->hwContextID = FakeClientID(0);
__glXenterServer(GL_FALSE);
retval = DRICreateContext(baseScreen->pScreen, visual,
context->hwContextID, &hwContext);
__glXleaveServer(GL_FALSE);
if (!retval)
return NULL;
context->driContext =
screen->legacy->createNewContext(screen->driScreen,
config->driConfig,
0, /* render type */
driShare,
hwContext,
context);
if (context->driContext == NULL) {
__glXenterServer(GL_FALSE);
retval = DRIDestroyContext(baseScreen->pScreen, context->hwContextID);
__glXleaveServer(GL_FALSE);
free(context);
return NULL;
}
return &context->base;
}
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;
GLboolean retval;
drm_drawable_t hwDrawable;
private = calloc(1, sizeof *private);
if (private == NULL)
return NULL;
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.waitX = NULL;
private->base.waitGL = NULL;
__glXenterServer(GL_FALSE);
retval = DRICreateDrawable(screen->pScreen, serverClient,
pDraw, &hwDrawable);
__glXleaveServer(GL_FALSE);
if (!retval) {
free(private);
return NULL;
}
/* The last argument is 'attrs', which is used with pbuffers which
* we currently don't support. */
private->driDrawable =
(driScreen->legacy->createNewDrawable)(driScreen->driScreen,
config->driConfig,
hwDrawable, 0, NULL, private);
if (private->driDrawable == NULL) {
__glXenterServer(GL_FALSE);
DRIDestroyDrawable(screen->pScreen, serverClient, pDraw);
__glXleaveServer(GL_FALSE);
free(private);
return NULL;
}
return &private->base;
}
static GLboolean
getDrawableInfo(__DRIdrawable *driDrawable,
unsigned int *index, unsigned int *stamp,
int *x, int *y, int *width, int *height,
int *numClipRects, drm_clip_rect_t **ppClipRects,
int *backX, int *backY,
int *numBackClipRects, drm_clip_rect_t **ppBackClipRects,
void *data)
{
__GLXDRIdrawable *drawable = data;
ScreenPtr pScreen;
drm_clip_rect_t *pClipRects, *pBackClipRects;
GLboolean retval;
size_t size;
/* If the X window has been destroyed, give up here. */
if (drawable->base.pDraw == NULL)
return GL_FALSE;
pScreen = drawable->base.pDraw->pScreen;
__glXenterServer(GL_FALSE);
retval = DRIGetDrawableInfo(pScreen, drawable->base.pDraw, index, stamp,
x, y, width, height,
numClipRects, &pClipRects,
backX, backY,
numBackClipRects, &pBackClipRects);
__glXleaveServer(GL_FALSE);
if (retval && *numClipRects > 0) {
size = sizeof (drm_clip_rect_t) * *numClipRects;
*ppClipRects = malloc(size);
/* Clip cliprects to screen dimensions (redirected windows) */
if (*ppClipRects != NULL) {
int i, j;
for (i = 0, j = 0; i < *numClipRects; i++) {
(*ppClipRects)[j].x1 = max(pClipRects[i].x1, 0);
(*ppClipRects)[j].y1 = max(pClipRects[i].y1, 0);
(*ppClipRects)[j].x2 = min(pClipRects[i].x2, pScreen->width);
(*ppClipRects)[j].y2 = min(pClipRects[i].y2, pScreen->height);
if ((*ppClipRects)[j].x1 < (*ppClipRects)[j].x2 &&
(*ppClipRects)[j].y1 < (*ppClipRects)[j].y2) {
j++;
}
}
if (*numClipRects != j) {
*numClipRects = j;
*ppClipRects = realloc(*ppClipRects,
sizeof (drm_clip_rect_t) *
*numClipRects);
}
} else
*numClipRects = 0;
}
else {
*ppClipRects = NULL;
*numClipRects = 0;
}
if (retval && *numBackClipRects > 0) {
size = sizeof (drm_clip_rect_t) * *numBackClipRects;
*ppBackClipRects = malloc(size);
if (*ppBackClipRects != NULL)
memcpy (*ppBackClipRects, pBackClipRects, size);
else
*numBackClipRects = 0;
}
else {
*ppBackClipRects = NULL;
*numBackClipRects = 0;
}
return retval;
}
static void __glXReportDamage(__DRIdrawable *driDraw,
int x, int y,
drm_clip_rect_t *rects, int num_rects,
GLboolean front_buffer,
void *data)
{
__GLXDRIdrawable *drawable = data;
DrawablePtr pDraw = drawable->base.pDraw;
RegionRec region;
__glXenterServer(GL_FALSE);
if (RegionInitBoxes(&region, (BoxPtr) rects, num_rects)) {
RegionTranslate(&region, pDraw->x, pDraw->y);
DamageDamageRegion(pDraw, &region);
RegionUninit(&region);
}
else {
while (num_rects--) {
RegionInit (&region, (BoxPtr) rects++, 1);
RegionTranslate(&region, pDraw->x, pDraw->y);
DamageDamageRegion(pDraw, &region);
RegionUninit(&region);
}
}
__glXleaveServer(GL_FALSE);
}
static const __DRIgetDrawableInfoExtension getDrawableInfoExtension = {
{ __DRI_GET_DRAWABLE_INFO, __DRI_GET_DRAWABLE_INFO_VERSION },
getDrawableInfo
};
static const __DRIdamageExtension damageExtension = {
{ __DRI_DAMAGE, __DRI_DAMAGE_VERSION },
__glXReportDamage,
};
static const __DRIextension *loader_extensions[] = {
&systemTimeExtension.base,
&getDrawableInfoExtension.base,
&damageExtension.base,
NULL
};
static Bool
glxDRIEnterVT (int index, int flags)
{
ScrnInfoPtr scrn = xf86Screens[index];
Bool ret;
__GLXDRIscreen *screen = (__GLXDRIscreen *)
glxGetScreen(screenInfo.screens[index]);
LogMessage(X_INFO, "AIGLX: Resuming AIGLX clients after VT switch\n");
scrn->EnterVT = screen->enterVT;
ret = scrn->EnterVT (index, flags);
screen->enterVT = scrn->EnterVT;
scrn->EnterVT = glxDRIEnterVT;
if (!ret)
return FALSE;
glxResumeClients();
return TRUE;
}
static void
glxDRILeaveVT (int index, int flags)
{
ScrnInfoPtr scrn = xf86Screens[index];
__GLXDRIscreen *screen = (__GLXDRIscreen *)
glxGetScreen(screenInfo.screens[index]);
LogMessage(X_INFO, "AIGLX: Suspending AIGLX clients for VT switch\n");
glxSuspendClients();
scrn->LeaveVT = screen->leaveVT;
(*screen->leaveVT) (index, flags);
screen->leaveVT = scrn->LeaveVT;
scrn->LeaveVT = glxDRILeaveVT;
}
static void
initializeExtensions(__GLXDRIscreen *screen)
{
const __DRIextension **extensions;
int i;
extensions = screen->core->getExtensions(screen->driScreen);
for (i = 0; extensions[i]; i++) {
#ifdef __DRI_READ_DRAWABLE
if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) {
__glXEnableExtension(screen->glx_enable_bits,
"GLX_SGI_make_current_read");
LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_make_current_read\n");
}
#endif
#ifdef __DRI_COPY_SUB_BUFFER
if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) {
screen->copySubBuffer = (__DRIcopySubBufferExtension *) extensions[i];
__glXEnableExtension(screen->glx_enable_bits,
"GLX_MESA_copy_sub_buffer");
LogMessage(X_INFO, "AIGLX: enabled GLX_MESA_copy_sub_buffer\n");
}
#endif
#ifdef __DRI_SWAP_CONTROL
if (strcmp(extensions[i]->name, __DRI_SWAP_CONTROL) == 0) {
screen->swapControl = (__DRIswapControlExtension *) extensions[i];
__glXEnableExtension(screen->glx_enable_bits,
"GLX_SGI_swap_control");
__glXEnableExtension(screen->glx_enable_bits,
"GLX_MESA_swap_control");
LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_swap_control and GLX_MESA_swap_control\n");
}
#endif
#ifdef __DRI_TEX_OFFSET
if (strcmp(extensions[i]->name, __DRI_TEX_OFFSET) == 0) {
screen->texOffset = (__DRItexOffsetExtension *) extensions[i];
LogMessage(X_INFO, "AIGLX: enabled GLX_texture_from_pixmap with driver support\n");
}
#endif
/* Ignore unknown extensions */
}
}
static __GLXscreen *
__glXDRIscreenProbe(ScreenPtr pScreen)
{
drm_handle_t hSAREA;
drmAddress pSAREA = NULL;
char *BusID;
__DRIversion ddx_version;
__DRIversion dri_version;
__DRIversion drm_version;
__DRIframebuffer framebuffer;
int fd = -1;
int status;
drm_magic_t magic;
drmVersionPtr version;
int newlyopened;
char *driverName;
drm_handle_t hFB;
int junk;
__GLXDRIscreen *screen;
Bool isCapable;
size_t buffer_size;
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
const __DRIconfig **driConfigs;
if (!xf86LoaderCheckSymbol("DRIQueryDirectRenderingCapable") ||
!DRIQueryDirectRenderingCapable(pScreen, &isCapable) ||
!isCapable) {
LogMessage(X_INFO,
"AIGLX: Screen %d is not DRI capable\n", pScreen->myNum);
return NULL;
}
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 = __glXDRIdrawableSwapInterval;
screen->base.pScreen = pScreen;
__glXInitExtensionEnableBits(screen->glx_enable_bits);
/* DRI protocol version. */
dri_version.major = XF86DRI_MAJOR_VERSION;
dri_version.minor = XF86DRI_MINOR_VERSION;
dri_version.patch = XF86DRI_PATCH_VERSION;
if (!DRIOpenConnection(pScreen, &hSAREA, &BusID)) {
LogMessage(X_ERROR, "AIGLX error: DRIOpenConnection failed\n");
goto handle_error;
}
fd = drmOpenOnce(NULL, BusID, &newlyopened);
if (fd < 0) {
LogMessage(X_ERROR, "AIGLX error: drmOpenOnce failed (%s)\n",
strerror(-fd));
goto handle_error;
}
if (drmGetMagic(fd, &magic)) {
LogMessage(X_ERROR, "AIGLX error: drmGetMagic failed\n");
goto handle_error;
}
version = drmGetVersion(fd);
if (version) {
drm_version.major = version->version_major;
drm_version.minor = version->version_minor;
drm_version.patch = version->version_patchlevel;
drmFreeVersion(version);
}
else {
drm_version.major = -1;
drm_version.minor = -1;
drm_version.patch = -1;
}
if (newlyopened && !DRIAuthConnection(pScreen, magic)) {
LogMessage(X_ERROR, "AIGLX error: DRIAuthConnection failed\n");
goto handle_error;
}
/* Get device name (like "tdfx") and the ddx version numbers.
* We'll check the version in each DRI driver's "createNewScreen"
* function. */
if (!DRIGetClientDriverName(pScreen,
&ddx_version.major,
&ddx_version.minor,
&ddx_version.patch,
&driverName)) {
LogMessage(X_ERROR, "AIGLX error: DRIGetClientDriverName failed\n");
goto handle_error;
}
screen->driver = glxProbeDriver(driverName,
(void **)&screen->core,
__DRI_CORE, __DRI_CORE_VERSION,
(void **)&screen->legacy,
__DRI_LEGACY, __DRI_LEGACY_VERSION);
if (screen->driver == NULL) {
goto handle_error;
}
/*
* Get device-specific info. pDevPriv will point to a struct
* (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) that
* has information about the screen size, depth, pitch, ancilliary
* buffers, DRM mmap handles, etc.
*/
if (!DRIGetDeviceInfo(pScreen, &hFB, &junk,
&framebuffer.size, &framebuffer.stride,
&framebuffer.dev_priv_size, &framebuffer.dev_priv)) {
LogMessage(X_ERROR, "AIGLX error: XF86DRIGetDeviceInfo failed\n");
goto handle_error;
}
framebuffer.width = pScreen->width;
framebuffer.height = pScreen->height;
/* Map the framebuffer region. */
status = drmMap(fd, hFB, framebuffer.size,
(drmAddressPtr)&framebuffer.base);
if (status != 0) {
LogMessage(X_ERROR, "AIGLX error: drmMap of framebuffer failed (%s)\n",
strerror(-status));
goto handle_error;
}
/* Map the SAREA region. Further mmap regions may be setup in
* each DRI driver's "createNewScreen" function.
*/
status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA);
if (status != 0) {
LogMessage(X_ERROR, "AIGLX error: drmMap of SAREA failed (%s)\n",
strerror(-status));
goto handle_error;
}
screen->driScreen =
(*screen->legacy->createNewScreen)(pScreen->myNum,
&ddx_version,
&dri_version,
&drm_version,
&framebuffer,
pSAREA,
fd,
loader_extensions,
&driConfigs,
screen);
if (screen->driScreen == NULL) {
LogMessage(X_ERROR,
"AIGLX error: Calling driver entry point failed\n");
goto handle_error;
}
screen->base.fbconfigs = glxConvertConfigs(screen->core,
driConfigs, GLX_WINDOW_BIT);
initializeExtensions(screen);
DRIGetTexOffsetFuncs(pScreen, &screen->texOffsetStart,
&screen->texOffsetFinish);
__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);
}
__glXsetEnterLeaveServerFuncs(__glXDRIenterServer, __glXDRIleaveServer);
screen->enterVT = pScrn->EnterVT;
pScrn->EnterVT = glxDRIEnterVT;
screen->leaveVT = pScrn->LeaveVT;
pScrn->LeaveVT = glxDRILeaveVT;
LogMessage(X_INFO,
"AIGLX: Loaded and initialized %s\n", driverName);
return &screen->base;
handle_error:
if (pSAREA != NULL)
drmUnmap(pSAREA, SAREA_MAX);
if (framebuffer.base != NULL)
drmUnmap((drmAddress)framebuffer.base, framebuffer.size);
if (fd >= 0)
drmCloseOnce(fd);
DRICloseConnection(pScreen);
if (screen->driver)
dlclose(screen->driver);
free(screen);
LogMessage(X_ERROR, "AIGLX: reverting to software rendering\n");
return NULL;
}
_X_EXPORT __GLXprovider __glXDRIProvider = {
__glXDRIscreenProbe,
"DRI",
NULL
};