blob: 9e400be6248b805b0f445703a88953eb79cc3b00 [file] [log] [blame]
/**
* Generic EGL driver for DRI. This is basically an "adaptor" driver
* that allows libEGL to load/use regular DRI drivers.
*
* This file contains all the code needed to interface DRI-based drivers
* with libEGL.
*
* There's a lot of dependencies on fbdev and the /sys/ filesystem.
*/
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <linux/fb.h>
#include <assert.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/time.h>
#include "egldriver.h"
#include "egldisplay.h"
#include "eglcontext.h"
#include "eglconfig.h"
#include "eglconfigutil.h"
#include "eglsurface.h"
#include "eglscreen.h"
#include "eglglobals.h"
#include "egllog.h"
#include "eglmode.h"
#include "egldri.h"
const char *sysfs = "/sys/class";
static const int empty_attribute_list[1] = { None };
/**
* Given a card number, return the name of the DRI driver to use.
* This generally means reading the contents of
* /sys/class/drm/cardX/dri_library_name, where X is the card number
*/
static EGLBoolean
driver_name_from_card_number(int card, char *driverName, int maxDriverName)
{
char path[2000];
FILE *f;
int length;
snprintf(path, sizeof(path), "%s/drm/card%d/dri_library_name", sysfs, card);
f = fopen(path, "r");
if (!f)
return EGL_FALSE;
fgets(driverName, maxDriverName, f);
fclose(f);
if ((length = strlen(driverName)) > 1) {
/* remove the trailing newline from sysfs */
driverName[length - 1] = '\0';
strncat(driverName, "_dri", maxDriverName);
return EGL_TRUE;
}
else {
return EGL_FALSE;
}
}
/**
* The bootstrap function.
* Return a new driDriver object and plug in API functions.
* This function, in turn, loads a specific DRI driver (ex: r200_dri.so).
*/
_EGLDriver *
_eglMain(_EGLDisplay *dpy, const char *args)
{
#if 1
const int card = args ? atoi(args) : 0;
_EGLDriver *driver = NULL;
char driverName[1000];
if (!driver_name_from_card_number(card, driverName, sizeof(driverName))) {
_eglLog(_EGL_WARNING,
"Unable to determine driver name for card %d\n", card);
return NULL;
}
_eglLog(_EGL_DEBUG, "Driver name: %s\n", driverName);
driver = _eglOpenDriver(dpy, driverName, args);
return driver;
#else
int length;
char path[NAME_MAX];
struct dirent *dirent;
#if 1
FILE *file;
#endif
DIR *dir;
_EGLDriver *driver = NULL;;
snprintf(path, sizeof(path), "%s/drm", sysfs);
if (!(dir = opendir(path))) {
_eglLog(_EGL_WARNING, "%s DRM devices not found.", path);
return EGL_FALSE;
}
/* loop over dir entries looking for cardX where "X" is in the
* dpy->DriverName ":X" string.
*/
while ((dirent = readdir(dir))) {
if (strncmp(&dirent->d_name[0], "card", 4) != 0)
continue;
if (strcmp(&dirent->d_name[4], &driverName[1]) != 0)
continue;
snprintf(path, sizeof(path), "%s/drm/card%s/dri_library_name",
sysfs, &driverName[1]);
_eglLog(_EGL_INFO, "Opening %s", path);
#if 1
file = fopen(path, "r");
if (!file) {
_eglLog(_EGL_WARNING, "Failed to open %s", path);
return NULL;
}
fgets(path, sizeof(path), file);
fclose(file);
#else
strcpy(path, "r200\n");
#endif
if ((length = strlen(path)) > 0)
path[length - 1] = '\0'; /* remove the trailing newline from sysfs */
strncat(path, "_dri", sizeof(path));
driver = _eglOpenDriver(dpy, path);
break;
}
closedir(dir);
return driver;
#endif
}
/**
* Called by eglCreateContext via drv->API.CreateContext().
*/
static EGLContext
_eglDRICreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
EGLContext share_list, const EGLint *attrib_list)
{
driDisplay *disp = Lookup_driDisplay(dpy);
driContext *c, *share;
void *sharePriv;
_EGLConfig *conf;
__GLcontextModes visMode;
c = (driContext *) calloc(1, sizeof(*c));
if (!c)
return EGL_NO_CONTEXT;
conf = _eglLookupConfig(drv, dpy, config);
assert(conf);
if (!_eglInitContext(drv, &c->Base, conf, attrib_list)) {
free(c);
return EGL_NO_CONTEXT;
}
if (share_list != EGL_NO_CONTEXT) {
_EGLContext *shareCtx = _eglLookupContext(share_list);
if (!shareCtx) {
_eglError(EGL_BAD_CONTEXT, "eglCreateContext(share_list)");
return EGL_FALSE;
}
}
share = Lookup_driContext(share_list);
if (share)
sharePriv = share->driContext.private;
else
sharePriv = NULL;
_eglConfigToContextModesRec(conf, &visMode);
c->driContext.private = disp->driScreen.createNewContext(disp, &visMode,
GLX_WINDOW_BIT, sharePriv, &c->driContext);
if (!c->driContext.private) {
free(c);
return EGL_FALSE;
}
/* link to display */
_eglLinkContext(&c->Base, &disp->Base);
return _eglGetContextHandle(&c->Base);
}
static EGLBoolean
_eglDRIMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw,
EGLSurface read, EGLContext context)
{
driDisplay *disp = Lookup_driDisplay(dpy);
driContext *ctx = Lookup_driContext(context);
EGLBoolean b;
__DRIid drawBuf = (__DRIid) draw;
__DRIid readBuf = (__DRIid) read;
b = _eglMakeCurrent(drv, dpy, draw, read, context);
if (!b)
return EGL_FALSE;
if (ctx) {
ctx->driContext.bindContext(disp, 0, drawBuf, readBuf, &ctx->driContext);
}
else {
/* what's this??? */
/* _mesa_make_current( NULL, NULL, NULL );*/
}
return EGL_TRUE;
}
static EGLSurface
_eglDRICreatePbufferSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
const EGLint *attrib_list)
{
driSurface *surf;
_EGLConfig *conf;
conf = _eglLookupConfig(drv, dpy, config);
assert(conf);
surf = (driSurface *) calloc(1, sizeof(*surf));
if (!surf) {
return EGL_NO_SURFACE;
}
if (!_eglInitSurface(drv, &surf->Base, EGL_PBUFFER_BIT,
conf, attrib_list)) {
free(surf);
return EGL_NO_SURFACE;
}
/* create software-based pbuffer */
{
#if 0
GLcontext *ctx = NULL; /* this _should_ be OK */
#endif
__GLcontextModes visMode;
_EGLConfig *conf = _eglLookupConfig(drv, dpy, config);
assert(conf); /* bad config should be caught earlier */
_eglConfigToContextModesRec(conf, &visMode);
#if 0
surf->mesa_framebuffer = _mesa_create_framebuffer(&visMode);
_mesa_add_soft_renderbuffers(surf->mesa_framebuffer,
GL_TRUE, /* color bufs */
visMode.haveDepthBuffer,
visMode.haveStencilBuffer,
visMode.haveAccumBuffer,
GL_FALSE, /* alpha */
GL_FALSE /* aux */ );
/* set pbuffer/framebuffer size */
_mesa_resize_framebuffer(ctx, surf->mesa_framebuffer,
surf->Base.Width, surf->Base.Height);
#endif
}
_eglLinkSurface(&surf->Base, _eglLookupDisplay(dpy));
return surf->Base.Handle;
}
static EGLBoolean
_eglDRIDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
{
driDisplay *disp = Lookup_driDisplay(dpy);
driSurface *fs = Lookup_driSurface(surface);
_eglUnlinkSurface(&fs->Base);
fs->drawable.destroyDrawable(disp, fs->drawable.private);
if (!_eglIsSurfaceBound(&fs->Base))
free(fs);
return EGL_TRUE;
}
static EGLBoolean
_eglDRIDestroyContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext context)
{
driDisplay *disp = Lookup_driDisplay(dpy);
driContext *fc = Lookup_driContext(context);
_eglUnlinkContext(&fc->Base);
fc->driContext.destroyContext(disp, 0, fc->driContext.private);
if (!_eglIsContextBound(&fc->Base))
free(fc);
return EGL_TRUE;
}
/**
* Create a drawing surface which can be directly displayed on a screen.
*/
static EGLSurface
_eglDRICreateScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLConfig cfg,
const EGLint *attrib_list)
{
_EGLConfig *config = _eglLookupConfig(drv, dpy, cfg);
driDisplay *disp = Lookup_driDisplay(dpy);
driSurface *surface;
__GLcontextModes visMode;
__DRIid drawBuf;
surface = (driSurface *) calloc(1, sizeof(*surface));
if (!surface) {
return EGL_NO_SURFACE;
}
/* init base class, do error checking, etc. */
if (!_eglInitSurface(drv, &surface->Base, EGL_SCREEN_BIT_MESA,
config, attrib_list)) {
free(surface);
return EGL_NO_SURFACE;
}
_eglLinkSurface(&surface->Base &disp->Base);
/*
* XXX this is where we should allocate video memory for the surface!
*/
/* convert EGLConfig to GLvisual */
_eglConfigToContextModesRec(config, &visMode);
drawBuf = (__DRIid) _eglGetSurfaceHandle(&surface->Base);
/* Create a new DRI drawable */
if (!disp->driScreen.createNewDrawable(disp, &visMode, drawBuf,
&surface->drawable, GLX_WINDOW_BIT,
empty_attribute_list)) {
_eglUnlinkSurface(&surface->Base);
free(surface);
return EGL_NO_SURFACE;
}
return surface->Base.Handle;
}
/**
* Set the fbdev colormap to a simple linear ramp.
*/
static void
_eglDRILoadColormap(driScreen *scrn)
{
char path[ NAME_MAX ];
char *buffer;
int i, fd;
/* cmap attribute uses 256 lines of 16 bytes.
* Allocate one extra char for the \0 added by sprintf()
*/
if ( !( buffer = malloc( 256 * 16 + 1 ) ) ) {
_eglLog(_EGL_WARNING, "Out of memory in _eglDRILoadColormap");
return;
}
/* cmap attribute uses 256 lines of 16 bytes */
for ( i = 0; i < 256; i++ ) {
int c = (i << 8) | i; /* expand to 16-bit value */
sprintf(&buffer[i * 16], "%02x%c%04x%04x%04x\n", i, ' ', c, c, c);
}
snprintf(path, sizeof(path), "%s/graphics/%s/color_map", sysfs, scrn->fb);
if ( !( fd = open( path, O_RDWR ) ) ) {
_eglLog(_EGL_WARNING, "Unable to open %s to set colormap", path);
return;
}
write( fd, buffer, 256 * 16 );
close( fd );
free( buffer );
}
/**
* Show the given surface on the named screen.
* If surface is EGL_NO_SURFACE, disable the screen's output.
* Called via eglShowSurfaceMESA().
*/
EGLBoolean
_eglDRIShowScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy,
EGLScreenMESA screen,
EGLSurface surface, EGLModeMESA m)
{
driDisplay *display = Lookup_driDisplay(dpy);
driScreen *scrn = Lookup_driScreen(dpy, screen);
driSurface *surf = Lookup_driSurface(surface);
_EGLMode *mode = _eglLookupMode(dpy, m);
FILE *file;
char fname[NAME_MAX], buffer[1000];
int temp;
_eglLog(_EGL_DEBUG, "Enter _eglDRIShowScreenSurface");
/* This will check that surface, screen, and mode are valid.
* Also, it checks that the surface is large enough for the mode, etc.
*/
if (!_eglShowScreenSurfaceMESA(drv, dpy, screen, surface, m))
return EGL_FALSE;
assert(surface == EGL_NO_SURFACE || surf);
assert(m == EGL_NO_MODE_MESA || mode);
assert(scrn);
/*
* Blank/unblank screen depending on if m == EGL_NO_MODE_MESA
*/
snprintf(fname, sizeof(fname), "%s/graphics/%s/blank", sysfs, scrn->fb);
file = fopen(fname, "r+");
if (!file) {
_eglLog(_EGL_WARNING, "kernel patch?? chown all fb sysfs attrib to allow"
" write - %s\n", fname);
return EGL_FALSE;
}
snprintf(buffer, sizeof(buffer), "%d",
(m == EGL_NO_MODE_MESA ? VESA_POWERDOWN : VESA_VSYNC_SUSPEND));
fputs(buffer, file);
fclose(file);
if (m == EGL_NO_MODE_MESA) {
/* all done! */
return EGL_TRUE;
}
_eglLog(_EGL_INFO, "Setting display mode to %d x %d, %d bpp",
mode->Width, mode->Height, display->bpp);
/*
* Set the display mode
*/
snprintf(fname, sizeof(fname), "%s/graphics/%s/mode", sysfs, scrn->fb);
file = fopen(fname, "r+");
if (!file) {
_eglLog(_EGL_WARNING, "Failed to open %s to set mode", fname);
return EGL_FALSE;
}
/* note: nothing happens without the \n! */
snprintf(buffer, sizeof(buffer), "%s\n", mode->Name);
fputs(buffer, file);
fclose(file);
_eglLog(_EGL_INFO, "Set mode to %s in %s", mode->Name, fname);
/*
* Set display bpp
*/
snprintf(fname, sizeof(fname), "%s/graphics/%s/bits_per_pixel",
sysfs, scrn->fb);
file = fopen(fname, "r+");
if (!file) {
_eglLog(_EGL_WARNING, "Failed to open %s to set bpp", fname);
return EGL_FALSE;
}
display->bpp = GET_CONFIG_ATTRIB(surf->Base.Config, EGL_BUFFER_SIZE);
display->cpp = display->bpp / 8;
snprintf(buffer, sizeof(buffer), "%d", display->bpp);
fputs(buffer, file);
fclose(file);
/*
* Unblank display
*/
snprintf(fname, sizeof(fname), "%s/graphics/%s/blank", sysfs, scrn->fb);
file = fopen(fname, "r+");
if (!file) {
_eglLog(_EGL_WARNING, "Failed to open %s", fname);
return EGL_FALSE;
}
snprintf(buffer, sizeof(buffer), "%d", VESA_NO_BLANKING);
fputs(buffer, file);
fclose(file);
/*
* Set fbdev buffer virtual size to surface's size.
*/
snprintf(fname, sizeof(fname), "%s/graphics/%s/virtual_size", sysfs, scrn->fb);
file = fopen(fname, "r+");
snprintf(buffer, sizeof(buffer), "%d,%d", surf->Base.Width, surf->Base.Height);
fputs(buffer, file);
rewind(file);
fgets(buffer, sizeof(buffer), file);
sscanf(buffer, "%d,%d", &display->virtualWidth, &display->virtualHeight);
fclose(file);
/*
* round up pitch as needed
*/
temp = display->virtualWidth;
switch (display->bpp / 8) {
case 1: temp = (display->virtualWidth + 127) & ~127; break;
case 2: temp = (display->virtualWidth + 31) & ~31; break;
case 3:
case 4: temp = (display->virtualWidth + 15) & ~15; break;
default:
_eglLog(_EGL_WARNING, "Bad display->bpp = %d in _eglDRIShowScreenSurface");
}
display->virtualWidth = temp;
/*
* sanity check
*/
if (surf->Base.Width < display->virtualWidth ||
surf->Base.Height < display->virtualHeight) {
/* this case _should_ have been caught at the top of this function */
_eglLog(_EGL_WARNING, "too small of surface in _eglDRIShowScreenSurfaceMESA "
"%d x %d < %d x %d",
surf->Base.Width,
surf->Base.Height,
display->virtualWidth,
display->virtualHeight);
/*
return EGL_FALSE;
*/
}
/* This used to be done in the _eglDRICreateScreens routine. */
_eglDRILoadColormap(scrn);
return EGL_TRUE;
}
/**
* Called by eglSwapBuffers via the drv->API.SwapBuffers() pointer.
*
* If the backbuffer is on a videocard, this is extraordinarily slow!
*/
static EGLBoolean
_eglDRISwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
{
driSurface *drawable = Lookup_driSurface(draw);
/* this does error checking */
if (!_eglSwapBuffers(drv, dpy, draw))
return EGL_FALSE;
drawable->drawable.swapBuffers(NULL, drawable->drawable.private);
return EGL_TRUE;
}
EGLBoolean
_eglDRIGetDisplayInfo(driDisplay *dpy)
{
char path[ NAME_MAX ];
FILE *file;
int i, rc;
drmSetVersion sv;
drm_magic_t magic;
snprintf( path, sizeof( path ), "%s/graphics/fb%d/device/device", sysfs, dpy->minor );
file = fopen( path, "r" );
if (!file) {
_eglLog(_EGL_WARNING, "Unable to open %s", path);
return EGL_FALSE;
}
fgets( path, sizeof( path ), file );
sscanf( path, "%x", &dpy->chipset );
fclose( file );
sprintf(path, DRM_DEV_NAME, DRM_DIR_NAME, dpy->minor);
if ( ( dpy->drmFD = open(path, O_RDWR, 0) ) < 0 ) {
_eglLog(_EGL_WARNING, "drmOpen failed.");
return EGL_FALSE;
}
/* Set the interface version, asking for 1.2 */
sv.drm_di_major = 1;
sv.drm_di_minor = 2;
sv.drm_dd_major = -1;
if ((rc = drmSetInterfaceVersion(dpy->drmFD, &sv)))
return EGL_FALSE;
/* self authorize */
if (drmGetMagic(dpy->drmFD, &magic))
return EGL_FALSE;
if (drmAuthMagic(dpy->drmFD, magic))
return EGL_FALSE;
/* Map framebuffer and SAREA */
for (i = 0; ; i++) {
drm_handle_t handle, offset;
drmSize size;
drmMapType type;
drmMapFlags flags;
int mtrr;
if (drmGetMap(dpy->drmFD, i, &offset, &size, &type, &flags,
&handle, &mtrr))
break;
if (type == DRM_FRAME_BUFFER) {
rc = drmMap( dpy->drmFD, offset, size, (drmAddressPtr) &dpy->pFB);
if (rc < 0) {
_eglLog(_EGL_WARNING, "drmMap DRM_FAME_BUFFER failed");
return EGL_FALSE;
}
dpy->fbSize = size;
_eglLog(_EGL_INFO, "Found framebuffer size: %d", dpy->fbSize);
}
else if (type == DRM_SHM) {
rc = drmMap(dpy->drmFD, offset, size, (drmAddressPtr) &dpy->pSAREA);
if (rc < 0 ) {
_eglLog(_EGL_WARNING, "drmMap DRM_SHM failed.");
return EGL_FALSE;
}
dpy->SAREASize = SAREA_MAX;
_eglLog(_EGL_DEBUG, "mapped SAREA 0x%08lx to %p, size %d",
(unsigned long) offset, dpy->pSAREA, dpy->SAREASize );
}
}
if (!dpy->pFB) {
_eglLog(_EGL_WARNING, "failed to map framebuffer");
return EGL_FALSE;
}
if (!dpy->pSAREA) {
/* if this happens, make sure you're using the most recent DRM modules */
_eglLog(_EGL_WARNING, "failed to map SAREA");
return EGL_FALSE;
}
memset( dpy->pSAREA, 0, dpy->SAREASize );
return EGL_TRUE;
}
/* Return the DRI per screen structure */
static __DRIscreen *
__eglFindDRIScreen(__DRInativeDisplay *ndpy, int scrn)
{
driDisplay *disp = (driDisplay *)ndpy;
return &disp->driScreen;
}
static GLboolean
__eglCreateContextWithConfig(__DRInativeDisplay* ndpy, int screen,
int configID, void* context,
drm_context_t * hHWContext)
{
__DRIscreen *pDRIScreen;
__DRIscreenPrivate *psp;
pDRIScreen = __eglFindDRIScreen(ndpy, screen);
if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
return GL_FALSE;
}
psp = (__DRIscreenPrivate *) pDRIScreen->private;
if (psp->fd) {
if (drmCreateContext(psp->fd, hHWContext)) {
_eglLog(_EGL_WARNING, "drmCreateContext failed.");
return GL_FALSE;
}
*(void**)context = (void*) *hHWContext;
}
#if 0
__DRIscreen *pDRIScreen;
__DRIscreenPrivate *psp;
pDRIScreen = __glXFindDRIScreen(dpy, screen);
if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
return GL_FALSE;
}
psp = (__DRIscreenPrivate *) pDRIScreen->private;
if (psp->fd) {
if (drmCreateContext(psp->fd, hHWContext)) {
_eglLog(_EGL_WARNING, "drmCreateContext failed.");
return GL_FALSE;
}
*(void**)contextID = (void*) *hHWContext;
}
#endif
return GL_TRUE;
}
static GLboolean
__eglDestroyContext( __DRInativeDisplay * ndpy, int screen, __DRIid context )
{
__DRIscreen *pDRIScreen;
__DRIscreenPrivate *psp;
pDRIScreen = __eglFindDRIScreen(ndpy, screen);
if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
return GL_FALSE;
}
psp = (__DRIscreenPrivate *) pDRIScreen->private;
if (psp->fd)
drmDestroyContext(psp->fd, context);
return GL_TRUE;
}
static GLboolean
__eglCreateDrawable(__DRInativeDisplay * ndpy, int screen,
__DRIid drawable, drm_drawable_t * hHWDrawable)
{
__DRIscreen *pDRIScreen;
__DRIscreenPrivate *psp;
pDRIScreen = __eglFindDRIScreen(ndpy, screen);
if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
return GL_FALSE;
}
psp = (__DRIscreenPrivate *) pDRIScreen->private;
if (psp->fd) {
if (drmCreateDrawable(psp->fd, hHWDrawable)) {
_eglLog(_EGL_WARNING, "drmCreateDrawable failed.");
return GL_FALSE;
}
}
return GL_TRUE;
}
static GLboolean
__eglDestroyDrawable( __DRInativeDisplay * ndpy, int screen, __DRIid drawable )
{
__DRIscreen *pDRIScreen;
__DRIscreenPrivate *psp;
pDRIScreen = __eglFindDRIScreen(ndpy, screen);
if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
return GL_FALSE;
}
psp = (__DRIscreenPrivate *) pDRIScreen->private;
if (psp->fd)
drmDestroyDrawable(psp->fd, drawable);
return GL_TRUE;
}
static GLboolean
__eglGetDrawableInfo(__DRInativeDisplay * ndpy, int screen, __DRIid 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 )
{
__DRIscreen *pDRIScreen;
__DRIscreenPrivate *psp;
driSurface *surf = Lookup_driSurface((EGLSurface) drawable);
pDRIScreen = __eglFindDRIScreen(ndpy, screen);
if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
return GL_FALSE;
}
psp = (__DRIscreenPrivate *) pDRIScreen->private;
*X = 0;
*Y = 0;
*W = surf->Base.Width;
*H = surf->Base.Height;
*backX = 0;
*backY = 0;
*numBackClipRects = 0;
*pBackClipRects = NULL;
*numClipRects = 1;
*pClipRects = malloc(sizeof(**pClipRects));
**pClipRects = (drm_clip_rect_t){0, 0, surf->Base.Width, surf->Base.Height};
psp->pSAREA->drawableTable[0].stamp = 1;
*stamp = 1;
#if 0
GLXDrawable drawable = (GLXDrawable) draw;
drm_clip_rect_t * cliprect;
Display* display = (Display*)dpy;
__DRIcontextPrivate *pcp = (__DRIcontextPrivate *)CurrentContext->driContext.private;
if (drawable == 0) {
return GL_FALSE;
}
cliprect = (drm_clip_rect_t*) _mesa_malloc(sizeof(drm_clip_rect_t));
cliprect->x1 = drawable->x;
cliprect->y1 = drawable->y;
cliprect->x2 = drawable->x + drawable->w;
cliprect->y2 = drawable->y + drawable->h;
/* the drawable index is by client id */
*index = display->clientID;
*stamp = pcp->driScreenPriv->pSAREA->drawableTable[display->clientID].stamp;
*x = drawable->x;
*y = drawable->y;
*width = drawable->w;
*height = drawable->h;
*numClipRects = 1;
*pClipRects = cliprect;
*backX = drawable->x;
*backY = drawable->y;
*numBackClipRects = 0;
*pBackClipRects = 0;
#endif
return GL_TRUE;
}
/**
* Implement \c __DRIinterfaceMethods::getProcAddress.
*/
static __DRIfuncPtr
get_proc_address(const char * proc_name)
{
return NULL;
}
/**
* Destroy a linked list of \c __GLcontextModes structures created by
* \c _gl_context_modes_create.
*
* \param modes Linked list of structures to be destroyed. All structres
* in the list will be freed.
*/
static void
__egl_context_modes_destroy(__GLcontextModes *modes)
{
while ( modes != NULL ) {
__GLcontextModes * const next = modes->next;
free( modes );
modes = next;
}
}
/**
* Allocate a linked list of \c __GLcontextModes structures. The fields of
* each structure will be initialized to "reasonable" default values. In
* most cases this is the default value defined by table 3.4 of the GLX
* 1.3 specification. This means that most values are either initialized to
* zero or \c GLX_DONT_CARE (which is -1). As support for additional
* extensions is added, the new values will be initialized to appropriate
* values from the extension specification.
*
* \param count Number of structures to allocate.
* \param minimum_size Minimum size of a structure to allocate. This allows
* for differences in the version of the
* \c __GLcontextModes stucture used in libGL and in a
* DRI-based driver.
* \returns A pointer to the first element in a linked list of \c count
* stuctures on success, or \c NULL on failure.
*
* \warning Use of \c minimum_size does \b not guarantee binary compatibility.
* The fundamental assumption is that if the \c minimum_size
* specified by the driver and the size of the \c __GLcontextModes
* structure in libGL is the same, then the meaning of each byte in
* the structure is the same in both places. \b Be \b careful!
* Basically this means that fields have to be added in libGL and
* then propagated to drivers. Drivers should \b never arbitrarilly
* extend the \c __GLcontextModes data-structure.
*/
static __GLcontextModes *
__egl_context_modes_create(unsigned count, size_t minimum_size)
{
const size_t size = (minimum_size > sizeof( __GLcontextModes ))
? minimum_size : sizeof( __GLcontextModes );
__GLcontextModes * base = NULL;
__GLcontextModes ** next;
unsigned i;
next = & base;
for ( i = 0 ; i < count ; i++ ) {
*next = (__GLcontextModes *) malloc( size );
if ( *next == NULL ) {
__egl_context_modes_destroy( base );
base = NULL;
break;
}
(void) memset( *next, 0, size );
(*next)->visualID = GLX_DONT_CARE;
(*next)->visualType = GLX_DONT_CARE;
(*next)->visualRating = GLX_NONE;
(*next)->transparentPixel = GLX_NONE;
(*next)->transparentRed = GLX_DONT_CARE;
(*next)->transparentGreen = GLX_DONT_CARE;
(*next)->transparentBlue = GLX_DONT_CARE;
(*next)->transparentAlpha = GLX_DONT_CARE;
(*next)->transparentIndex = GLX_DONT_CARE;
(*next)->xRenderable = GLX_DONT_CARE;
(*next)->fbconfigID = GLX_DONT_CARE;
(*next)->swapMethod = GLX_SWAP_UNDEFINED_OML;
next = & ((*next)->next);
}
return base;
}
static GLboolean
__eglWindowExists(__DRInativeDisplay *dpy, __DRIid draw)
{
return EGL_TRUE;
}
/**
* Get the unadjusted system time (UST). Currently, the UST is measured in
* microseconds since Epoc. The actual resolution of the UST may vary from
* system to system, and the units may vary from release to release.
* Drivers should not call this function directly. They should instead use
* \c glXGetProcAddress to obtain a pointer to the function.
*
* \param ust Location to store the 64-bit UST
* \returns Zero on success or a negative errno value on failure.
*
* \sa glXGetProcAddress, PFNGLXGETUSTPROC
*
* \since Internal API version 20030317.
*/
static int
__eglGetUST(int64_t *ust)
{
struct timeval tv;
if ( ust == NULL ) {
return -EFAULT;
}
if ( gettimeofday( & tv, NULL ) == 0 ) {
ust[0] = (tv.tv_sec * 1000000) + tv.tv_usec;
return 0;
}
else {
return -errno;
}
}
/**
* Determine the refresh rate of the specified drawable and display.
*
* \param dpy Display whose refresh rate is to be determined.
* \param drawable Drawable whose refresh rate is to be determined.
* \param numerator Numerator of the refresh rate.
* \param demoninator Denominator of the refresh rate.
* \return If the refresh rate for the specified display and drawable could
* be calculated, True is returned. Otherwise False is returned.
*
* \note This function is implemented entirely client-side. A lot of other
* functionality is required to export GLX_OML_sync_control, so on
* XFree86 this function can be called for direct-rendering contexts
* when GLX_OML_sync_control appears in the client extension string.
*/
static GLboolean
__eglGetMSCRate(__DRInativeDisplay * dpy, __DRIid drawable,
int32_t * numerator, int32_t * denominator)
{
return EGL_TRUE;
}
/**
* Table of functions exported by the loader to the driver.
*/
static const __DRIinterfaceMethods interface_methods = {
get_proc_address,
__egl_context_modes_create,
__egl_context_modes_destroy,
__eglFindDRIScreen,
__eglWindowExists,
__eglCreateContextWithConfig,
__eglDestroyContext,
__eglCreateDrawable,
__eglDestroyDrawable,
__eglGetDrawableInfo,
__eglGetUST,
__eglGetMSCRate,
};
static int
__glXGetInternalVersion(void)
{
return 20050725;
}
static const char createNewScreenName[] = "__driCreateNewScreen_20050727";
/**
* Do per-display initialization.
*/
EGLBoolean
_eglDRICreateDisplay(driDisplay *dpy, __DRIframebuffer *framebuffer)
{
PFNCREATENEWSCREENFUNC createNewScreen;
int api_ver = __glXGetInternalVersion();
__DRIversion ddx_version;
__DRIversion dri_version;
__DRIversion drm_version;
drmVersionPtr version;
version = drmGetVersion( dpy->drmFD );
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;
}
/*
* Get device name (like "tdfx") and the ddx version numbers.
* We'll check the version in each DRI driver's "createScreen"
* function.
*/
ddx_version.major = 4;
ddx_version.minor = 0;
ddx_version.patch = 0;
/*
* Get the DRI X extension version.
*/
dri_version.major = 4;
dri_version.minor = 0;
dri_version.patch = 0;
createNewScreen = ( PFNCREATENEWSCREENFUNC ) dlsym( dpy->Base.Driver->LibHandle, createNewScreenName );
if ( !createNewScreen ) {
_eglLog(_EGL_WARNING, "Couldn't find %s function in the driver.",
createNewScreenName );
return EGL_FALSE;
}
dpy->driScreen.private = createNewScreen( dpy, 0, &dpy->driScreen, NULL,
&ddx_version, &dri_version,
&drm_version, framebuffer,
dpy->pSAREA, dpy->drmFD,
api_ver,
& interface_methods,
NULL);
if (!dpy->driScreen.private) {
_eglLog(_EGL_WARNING, "egldri.c: DRI create new screen failed");
return EGL_FALSE;
}
DRM_UNLOCK( dpy->drmFD, dpy->pSAREA, dpy->serverContext );
return EGL_TRUE;
}
/**
* Create all the EGL screens for the given display.
*/
EGLBoolean
_eglDRICreateScreens(driDisplay *dpy)
{
const int numScreens = 1; /* XXX fix this someday */
int i;
for (i = 0; i < numScreens; i++) {
char path[ NAME_MAX ];
FILE *file;
driScreen *s;
/* Create a screen */
if ( !( s = ( driScreen * ) calloc( 1, sizeof( *s ) ) ) )
return EGL_FALSE;
snprintf( s->fb, NAME_MAX, "fb%d", dpy->minor );
_eglInitScreen( &s->Base );
_eglAddScreen( &dpy->Base, &s->Base );
/* Create the screen's mode list */
snprintf( path, sizeof( path ), "%s/graphics/%s/modes", sysfs, s->fb );
file = fopen( path, "r" );
while ( fgets( path, sizeof( path ), file ) ) {
unsigned int x, y, r;
char c;
path[ strlen( path ) - 1 ] = '\0'; /* strip off \n from sysfs */
sscanf( path, "%c:%ux%u-%u", &c, &x, &y, &r );
_eglAddNewMode( &s->Base, x, y, r * 1000, path );
}
fclose( file );
/*
* NOTE: we used to set the colormap here, but that didn't work reliably.
* Some entries near the start of the table would get corrupted by later
* mode changes.
*/
}
return EGL_TRUE;
}
EGLBoolean
_eglDRIInitialize(_EGLDriver *drv, EGLDisplay dpy,
EGLint *major, EGLint *minor)
{
_EGLDisplay *disp = _eglLookupDisplay(dpy);
driDisplay *display;
const char *driverName = (const char *) disp->NativeDisplay;
assert(disp);
/* Create new driDisplay object to replace the _EGLDisplay that was
* previously created.
*/
display = calloc(1, sizeof(*display));
display->Base = *disp;
_eglSaveDisplay(&display->Base);
free(disp);
*major = 1;
*minor = 0;
sscanf(driverName + 1, "%d", &display->minor);
drv->Initialized = EGL_TRUE;
return EGL_TRUE;
}
static EGLBoolean
_eglDRITerminate(_EGLDriver *drv, EGLDisplay dpy)
{
driDisplay *display = Lookup_driDisplay(dpy);
_eglCleanupDisplay(&display->Base);/*rename that function*/
free(display);
free(drv);
return EGL_TRUE;
}
/**
* Plug in the DRI-specific functions into the driver's dispatch table.
* Also, enable some EGL extensions.
*/
void
_eglDRIInitDriverFallbacks(_EGLDriver *drv)
{
_eglInitDriverFallbacks(drv);
drv->API.Initialize = _eglDRIInitialize;
drv->API.Terminate = _eglDRITerminate;
drv->API.CreateContext = _eglDRICreateContext;
drv->API.MakeCurrent = _eglDRIMakeCurrent;
drv->API.CreatePbufferSurface = _eglDRICreatePbufferSurface;
drv->API.DestroySurface = _eglDRIDestroySurface;
drv->API.DestroyContext = _eglDRIDestroyContext;
drv->API.CreateScreenSurfaceMESA = _eglDRICreateScreenSurfaceMESA;
drv->API.ShowScreenSurfaceMESA = _eglDRIShowScreenSurfaceMESA;
drv->API.SwapBuffers = _eglDRISwapBuffers;
/* enable supported extensions */
drv->Extensions.MESA_screen_surface = EGL_TRUE;
drv->Extensions.MESA_copy_context = EGL_TRUE;
}