#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
#include <X11/Xlib.h>
#include <X11/extensions/Xfixes.h>
#include <X11/extensions/Xdamage.h>
#include "glxclient.h"
#include "xf86dri.h"
#include "dri2.h"
#include "sarea.h"
#include <dlfcn.h>
#include <sys/types.h>
#include <sys/mman.h>
#include "xf86drm.h"
#include "dri_common.h"
typedef struct __GLXDRIdisplayPrivateRec __GLXDRIdisplayPrivate;
typedef struct __GLXDRIcontextPrivateRec __GLXDRIcontextPrivate;
struct __GLXDRIdisplayPrivateRec
{
__GLXDRIdisplay base;
int driMajor;
int driMinor;
int driPatch;
};
struct __GLXDRIcontextPrivateRec
{
__GLXDRIcontext base;
__DRIcontext *driContext;
XID hwContextID;
__GLXscreenConfigs *psc;
};
static Bool
driGetDriverName(Display * dpy, int scrNum, char **driverName)
{
int directCapable;
Bool b;
int event, error;
int driverMajor, driverMinor, driverPatch;
*driverName = NULL;
if (XF86DRIQueryExtension(dpy, &event, &error)) {
if (!XF86DRIQueryDirectRenderingCapable(dpy, scrNum, &directCapable)) {
ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
return False;
}
if (!directCapable) {
ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
return False;
}
b = XF86DRIGetClientDriverName(dpy, scrNum, &driverMajor, &driverMinor,
&driverPatch, driverName);
if (!b) {
ErrorMessageF("Cannot determine driver name for screen %d\n",
scrNum);
return False;
}
InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
driverMajor, driverMinor, driverPatch, *driverName,
scrNum);
return True;
}
else if (DRI2QueryExtension(dpy, &event, &error)) {
char *dev;
Bool ret = DRI2Connect(dpy, RootWindow(dpy, scrNum), driverName, &dev);
if (ret)
Xfree(dev);
return ret;
}
return False;
}
PUBLIC const char *
glXGetScreenDriver(Display * dpy, int scrNum)
{
static char ret[32];
char *driverName;
if (driGetDriverName(dpy, scrNum, &driverName)) {
int len;
if (!driverName)
return NULL;
len = strlen(driverName);
if (len >= 31)
return NULL;
memcpy(ret, driverName, len + 1);
Xfree(driverName);
return ret;
}
return NULL;
}
PUBLIC const char *
glXGetDriverConfig(const char *driverName)
{
void *handle = driOpenDriver(driverName);
if (handle)
return dlsym(handle, "__driConfigOptions");
else
return NULL;
}
#ifdef XDAMAGE_1_1_INTERFACE
static GLboolean
has_damage_post(Display * dpy)
{
static GLboolean inited = GL_FALSE;
static GLboolean has_damage;
if (!inited) {
int major, minor;
if (XDamageQueryVersion(dpy, &major, &minor) &&
major == 1 && minor >= 1) {
has_damage = GL_TRUE;
}
else {
has_damage = GL_FALSE;
}
inited = GL_TRUE;
}
return has_damage;
}
static void
__glXReportDamage(__DRIdrawable * driDraw,
int x, int y,
drm_clip_rect_t * rects, int num_rects,
GLboolean front_buffer, void *loaderPrivate)
{
XRectangle *xrects;
XserverRegion region;
int i;
int x_off, y_off;
__GLXDRIdrawable *glxDraw = loaderPrivate;
__GLXscreenConfigs *psc = glxDraw->psc;
Display *dpy = psc->dpy;
Drawable drawable;
if (!has_damage_post(dpy))
return;
if (front_buffer) {
x_off = x;
y_off = y;
drawable = RootWindow(dpy, psc->scr);
}
else {
x_off = 0;
y_off = 0;
drawable = glxDraw->xDrawable;
}
xrects = malloc(sizeof(XRectangle) * num_rects);
if (xrects == NULL)
return;
for (i = 0; i < num_rects; i++) {
xrects[i].x = rects[i].x1 + x_off;
xrects[i].y = rects[i].y1 + y_off;
xrects[i].width = rects[i].x2 - rects[i].x1;
xrects[i].height = rects[i].y2 - rects[i].y1;
}
region = XFixesCreateRegion(dpy, xrects, num_rects);
free(xrects);
XDamageAdd(dpy, drawable, region);
XFixesDestroyRegion(dpy, region);
}
static const __DRIdamageExtension damageExtension = {
{__DRI_DAMAGE, __DRI_DAMAGE_VERSION},
__glXReportDamage,
};
#endif
static GLboolean
__glXDRIGetDrawableInfo(__DRIdrawable * drawable,
unsigned int *index, unsigned int *stamp,
int *X, int *Y, int *W, int *H,
int *numClipRects, drm_clip_rect_t ** pClipRects,
int *backX, int *backY,
int *numBackClipRects,
drm_clip_rect_t ** pBackClipRects,
void *loaderPrivate)
{
__GLXDRIdrawable *glxDraw = loaderPrivate;
__GLXscreenConfigs *psc = glxDraw->psc;
Display *dpy = psc->dpy;
return XF86DRIGetDrawableInfo(dpy, psc->scr, glxDraw->drawable,
index, stamp, X, Y, W, H,
numClipRects, pClipRects,
backX, backY,
numBackClipRects, pBackClipRects);
}
static const __DRIgetDrawableInfoExtension getDrawableInfoExtension = {
{__DRI_GET_DRAWABLE_INFO, __DRI_GET_DRAWABLE_INFO_VERSION},
__glXDRIGetDrawableInfo
};
static const __DRIextension *loader_extensions[] = {
&systemTimeExtension.base,
&getDrawableInfoExtension.base,
#ifdef XDAMAGE_1_1_INTERFACE
&damageExtension.base,
#endif
NULL
};
static void *
CallCreateNewScreen(Display * dpy, int scrn, __GLXscreenConfigs * psc,
__GLXDRIdisplayPrivate * driDpy)
{
void *psp = NULL;
drm_handle_t hSAREA;
drmAddress pSAREA = MAP_FAILED;
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;
const __DRIconfig **driver_configs;
__GLcontextModes *visual;
dri_version.major = driDpy->driMajor;
dri_version.minor = driDpy->driMinor;
dri_version.patch = driDpy->driPatch;
framebuffer.base = MAP_FAILED;
framebuffer.dev_priv = NULL;
framebuffer.size = 0;
if (!XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) {
ErrorMessageF("XF86DRIOpenConnection failed\n");
goto handle_error;
}
fd = drmOpenOnce(NULL, BusID, &newlyopened);
Xfree(BusID);
if (fd < 0) {
ErrorMessageF("drmOpenOnce failed (%s)\n", strerror(-fd));
goto handle_error;
}
if (drmGetMagic(fd, &magic)) {
ErrorMessageF("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 && !XF86DRIAuthConnection(dpy, scrn, magic)) {
ErrorMessageF("XF86DRIAuthConnection failed\n");
goto handle_error;
}
if (!XF86DRIGetClientDriverName(dpy, scrn,
&ddx_version.major,
&ddx_version.minor,
&ddx_version.patch, &driverName)) {
ErrorMessageF("XF86DRIGetClientDriverName failed\n");
goto handle_error;
}
Xfree(driverName);
if (!XF86DRIGetDeviceInfo(dpy, scrn, &hFB, &junk,
&framebuffer.size, &framebuffer.stride,
&framebuffer.dev_priv_size,
&framebuffer.dev_priv)) {
ErrorMessageF("XF86DRIGetDeviceInfo failed");
goto handle_error;
}
framebuffer.width = DisplayWidth(dpy, scrn);
framebuffer.height = DisplayHeight(dpy, scrn);
status = drmMap(fd, hFB, framebuffer.size,
(drmAddressPtr) & framebuffer.base);
if (status != 0) {
ErrorMessageF("drmMap of framebuffer failed (%s)", strerror(-status));
goto handle_error;
}
status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA);
if (status != 0) {
ErrorMessageF("drmMap of SAREA failed (%s)", strerror(-status));
goto handle_error;
}
psp = (*psc->legacy->createNewScreen) (scrn,
&ddx_version,
&dri_version,
&drm_version,
&framebuffer,
pSAREA,
fd,
loader_extensions,
&driver_configs, psc);
if (psp == NULL) {
ErrorMessageF("Calling driver entry point failed");
goto handle_error;
}
psc->configs = driConvertConfigs(psc->core, psc->configs, driver_configs);
psc->visuals = driConvertConfigs(psc->core, psc->visuals, driver_configs);
psc->driver_configs = driver_configs;
for (visual = psc->visuals; visual; visual = visual->next) {
XVisualInfo template;
XVisualInfo *visuals;
int num_visuals;
long mask;
template.visualid = visual->visualID;
mask = VisualIDMask;
visuals = XGetVisualInfo(dpy, mask, &template, &num_visuals);
if (visuals) {
if (num_visuals > 0 && visuals->depth != DefaultDepth(dpy, scrn))
visual->visualRating = GLX_NON_CONFORMANT_CONFIG;
XFree(visuals);
}
}
return psp;
handle_error:
if (pSAREA != MAP_FAILED)
drmUnmap(pSAREA, SAREA_MAX);
if (framebuffer.base != MAP_FAILED)
drmUnmap((drmAddress) framebuffer.base, framebuffer.size);
if (framebuffer.dev_priv != NULL)
Xfree(framebuffer.dev_priv);
if (fd >= 0)
drmCloseOnce(fd);
XF86DRICloseConnection(dpy, scrn);
ErrorMessageF("reverting to software direct rendering\n");
return NULL;
}
static void
driDestroyContext(__GLXDRIcontext * context,
__GLXscreenConfigs * psc, Display * dpy)
{
__GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
(*psc->core->destroyContext) (pcp->driContext);
XF86DRIDestroyContext(psc->dpy, psc->scr, pcp->hwContextID);
Xfree(pcp);
}
static Bool
driBindContext(__GLXDRIcontext * context,
__GLXDRIdrawable * draw, __GLXDRIdrawable * read)
{
__GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
const __DRIcoreExtension *core = pcp->psc->core;
return (*core->bindContext) (pcp->driContext,
draw->driDrawable, read->driDrawable);
}
static void
driUnbindContext(__GLXDRIcontext * context)
{
__GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
const __DRIcoreExtension *core = pcp->psc->core;
(*core->unbindContext) (pcp->driContext);
}
static __GLXDRIcontext *
driCreateContext(__GLXscreenConfigs * psc,
const __GLcontextModes * mode,
GLXContext gc, GLXContext shareList, int renderType)
{
__GLXDRIcontextPrivate *pcp, *pcp_shared;
drm_context_t hwContext;
__DRIcontext *shared = NULL;
__GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) mode;
if (!psc || !psc->driScreen)
return NULL;
if (shareList) {
pcp_shared = (__GLXDRIcontextPrivate *) shareList->driContext;
shared = pcp_shared->driContext;
}
pcp = Xmalloc(sizeof *pcp);
if (pcp == NULL)
return NULL;
pcp->psc = psc;
if (!XF86DRICreateContextWithConfig(psc->dpy, psc->scr,
mode->visualID,
&pcp->hwContextID, &hwContext)) {
Xfree(pcp);
return NULL;
}
pcp->driContext =
(*psc->legacy->createNewContext) (psc->__driScreen,
config->driConfig,
renderType, shared, hwContext, pcp);
if (pcp->driContext == NULL) {
XF86DRIDestroyContext(psc->dpy, psc->scr, pcp->hwContextID);
Xfree(pcp);
return NULL;
}
pcp->base.destroyContext = driDestroyContext;
pcp->base.bindContext = driBindContext;
pcp->base.unbindContext = driUnbindContext;
return &pcp->base;
}
static void
driDestroyDrawable(__GLXDRIdrawable * pdraw)
{
__GLXscreenConfigs *psc = pdraw->psc;
(*psc->core->destroyDrawable) (pdraw->driDrawable);
XF86DRIDestroyDrawable(psc->dpy, psc->scr, pdraw->drawable);
Xfree(pdraw);
}
static __GLXDRIdrawable *
driCreateDrawable(__GLXscreenConfigs * psc,
XID xDrawable,
GLXDrawable drawable, const __GLcontextModes * modes)
{
__GLXDRIdrawable *pdraw;
drm_drawable_t hwDrawable;
void *empty_attribute_list = NULL;
__GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes;
if (xDrawable != drawable)
return NULL;
pdraw = Xmalloc(sizeof(*pdraw));
if (!pdraw)
return NULL;
pdraw->drawable = drawable;
pdraw->psc = psc;
if (!XF86DRICreateDrawable(psc->dpy, psc->scr, drawable, &hwDrawable)) {
Xfree(pdraw);
return NULL;
}
pdraw->driDrawable =
(*psc->legacy->createNewDrawable) (psc->__driScreen,
config->driConfig,
hwDrawable,
GLX_WINDOW_BIT,
empty_attribute_list, pdraw);
if (!pdraw->driDrawable) {
XF86DRIDestroyDrawable(psc->dpy, psc->scr, drawable);
Xfree(pdraw);
return NULL;
}
pdraw->destroyDrawable = driDestroyDrawable;
return pdraw;
}
static int64_t
driSwapBuffers(__GLXDRIdrawable * pdraw, int64_t unused1, int64_t unused2,
int64_t unused3)
{
(*pdraw->psc->core->swapBuffers) (pdraw->driDrawable);
return 0;
}
static void
driCopySubBuffer(__GLXDRIdrawable * pdraw,
int x, int y, int width, int height)
{
(*pdraw->psc->driCopySubBuffer->copySubBuffer) (pdraw->driDrawable,
x, y, width, height);
}
static void
driDestroyScreen(__GLXscreenConfigs * psc)
{
if (psc->__driScreen)
(*psc->core->destroyScreen) (psc->__driScreen);
psc->__driScreen = NULL;
if (psc->driver)
dlclose(psc->driver);
}
static __GLXDRIscreen *
driCreateScreen(__GLXscreenConfigs * psc, int screen,
__GLXdisplayPrivate * priv)
{
__GLXDRIdisplayPrivate *pdp;
__GLXDRIscreen *psp;
const __DRIextension **extensions;
char *driverName;
int i;
psp = Xcalloc(1, sizeof *psp);
if (psp == NULL)
return NULL;
if (!driGetDriverName(priv->dpy, screen, &driverName)) {
Xfree(psp);
return NULL;
}
psc->driver = driOpenDriver(driverName);
Xfree(driverName);
if (psc->driver == NULL) {
Xfree(psp);
return NULL;
}
extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
if (extensions == NULL) {
ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
Xfree(psp);
return NULL;
}
for (i = 0; extensions[i]; i++) {
if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
psc->core = (__DRIcoreExtension *) extensions[i];
if (strcmp(extensions[i]->name, __DRI_LEGACY) == 0)
psc->legacy = (__DRIlegacyExtension *) extensions[i];
}
if (psc->core == NULL || psc->legacy == NULL) {
Xfree(psp);
return NULL;
}
pdp = (__GLXDRIdisplayPrivate *) priv->driDisplay;
psc->__driScreen = CallCreateNewScreen(psc->dpy, screen, psc, pdp);
if (psc->__driScreen == NULL) {
dlclose(psc->driver);
Xfree(psp);
return NULL;
}
driBindExtensions(psc);
driBindCommonExtensions(psc);
if (psc->driCopySubBuffer)
psp->copySubBuffer = driCopySubBuffer;
psp->destroyScreen = driDestroyScreen;
psp->createContext = driCreateContext;
psp->createDrawable = driCreateDrawable;
psp->swapBuffers = driSwapBuffers;
psp->waitX = NULL;
psp->waitGL = NULL;
return psp;
}
static void
driDestroyDisplay(__GLXDRIdisplay * dpy)
{
Xfree(dpy);
}
_X_HIDDEN __GLXDRIdisplay *
driCreateDisplay(Display * dpy)
{
__GLXDRIdisplayPrivate *pdpyp;
int eventBase, errorBase;
int major, minor, patch;
if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
return NULL;
}
if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) {
return NULL;
}
pdpyp = Xmalloc(sizeof *pdpyp);
if (!pdpyp) {
return NULL;
}
pdpyp->driMajor = major;
pdpyp->driMinor = minor;
pdpyp->driPatch = patch;
pdpyp->base.destroyDisplay = driDestroyDisplay;
pdpyp->base.createScreen = driCreateScreen;
return &pdpyp->base;
}
#endif