/** * 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 #include #include #include #include #include #include #include #include #include #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; __DRIscreen *psp; pDRIScreen = __eglFindDRIScreen(ndpy, screen); if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) { return GL_FALSE; } psp = (__DRIscreen *) 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; __DRIscreen *psp; pDRIScreen = __glXFindDRIScreen(dpy, screen); if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) { return GL_FALSE; } psp = (__DRIscreen *) 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; __DRIscreen *psp; pDRIScreen = __eglFindDRIScreen(ndpy, screen); if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) { return GL_FALSE; } psp = (__DRIscreen *) 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; __DRIscreen *psp; pDRIScreen = __eglFindDRIScreen(ndpy, screen); if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) { return GL_FALSE; } psp = (__DRIscreen *) 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; __DRIscreen *psp; pDRIScreen = __eglFindDRIScreen(ndpy, screen); if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) { return GL_FALSE; } psp = (__DRIscreen *) 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; __DRIscreen *psp; driSurface *surf = Lookup_driSurface((EGLSurface) drawable); pDRIScreen = __eglFindDRIScreen(ndpy, screen); if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) { return GL_FALSE; } psp = (__DRIscreen *) 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; __DRIcontext *pcp = (__DRIcontext *)CurrentContext->driContext.private; if (drawable == 0) { return GL_FALSE; } cliprect = (drm_clip_rect_t*) 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; }