Merge branch 'mesa_7_7_branch'
[mesa.git] / src / egl / drivers / dri / egldri.c
1 /**
2 * Generic EGL driver for DRI. This is basically an "adaptor" driver
3 * that allows libEGL to load/use regular DRI drivers.
4 *
5 * This file contains all the code needed to interface DRI-based drivers
6 * with libEGL.
7 *
8 * There's a lot of dependencies on fbdev and the /sys/ filesystem.
9 */
10
11
12 #include <dirent.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <linux/fb.h>
16 #include <assert.h>
17 #include <dlfcn.h>
18 #include <fcntl.h>
19 #include <unistd.h>
20 #include <errno.h>
21 #include <sys/time.h>
22
23 #include "egldriver.h"
24 #include "egldisplay.h"
25 #include "eglcontext.h"
26 #include "eglconfig.h"
27 #include "eglconfigutil.h"
28 #include "eglsurface.h"
29 #include "eglscreen.h"
30 #include "eglglobals.h"
31 #include "egllog.h"
32 #include "eglmode.h"
33
34 #include "egldri.h"
35
36 const char *sysfs = "/sys/class";
37
38 static const int empty_attribute_list[1] = { None };
39
40
41
42 /**
43 * Given a card number, return the name of the DRI driver to use.
44 * This generally means reading the contents of
45 * /sys/class/drm/cardX/dri_library_name, where X is the card number
46 */
47 static EGLBoolean
48 driver_name_from_card_number(int card, char *driverName, int maxDriverName)
49 {
50 char path[2000];
51 FILE *f;
52 int length;
53
54 snprintf(path, sizeof(path), "%s/drm/card%d/dri_library_name", sysfs, card);
55
56 f = fopen(path, "r");
57 if (!f)
58 return EGL_FALSE;
59
60 fgets(driverName, maxDriverName, f);
61 fclose(f);
62
63 if ((length = strlen(driverName)) > 1) {
64 /* remove the trailing newline from sysfs */
65 driverName[length - 1] = '\0';
66 strncat(driverName, "_dri", maxDriverName);
67 return EGL_TRUE;
68 }
69 else {
70 return EGL_FALSE;
71 }
72 }
73
74
75
76 /**
77 * The bootstrap function.
78 * Return a new driDriver object and plug in API functions.
79 * This function, in turn, loads a specific DRI driver (ex: r200_dri.so).
80 */
81 _EGLDriver *
82 _eglMain(_EGLDisplay *dpy, const char *args)
83 {
84 #if 1
85 const int card = args ? atoi(args) : 0;
86 _EGLDriver *driver = NULL;
87 char driverName[1000];
88
89 if (!driver_name_from_card_number(card, driverName, sizeof(driverName))) {
90 _eglLog(_EGL_WARNING,
91 "Unable to determine driver name for card %d\n", card);
92 return NULL;
93 }
94
95 _eglLog(_EGL_DEBUG, "Driver name: %s\n", driverName);
96
97 driver = _eglOpenDriver(dpy, driverName, args);
98
99 return driver;
100
101 #else
102
103 int length;
104 char path[NAME_MAX];
105 struct dirent *dirent;
106 #if 1
107 FILE *file;
108 #endif
109 DIR *dir;
110 _EGLDriver *driver = NULL;;
111
112 snprintf(path, sizeof(path), "%s/drm", sysfs);
113 if (!(dir = opendir(path))) {
114 _eglLog(_EGL_WARNING, "%s DRM devices not found.", path);
115 return EGL_FALSE;
116 }
117
118 /* loop over dir entries looking for cardX where "X" is in the
119 * dpy->DriverName ":X" string.
120 */
121 while ((dirent = readdir(dir))) {
122
123 if (strncmp(&dirent->d_name[0], "card", 4) != 0)
124 continue;
125 if (strcmp(&dirent->d_name[4], &driverName[1]) != 0)
126 continue;
127
128 snprintf(path, sizeof(path), "%s/drm/card%s/dri_library_name",
129 sysfs, &driverName[1]);
130 _eglLog(_EGL_INFO, "Opening %s", path);
131 #if 1
132 file = fopen(path, "r");
133 if (!file) {
134 _eglLog(_EGL_WARNING, "Failed to open %s", path);
135 return NULL;
136 }
137 fgets(path, sizeof(path), file);
138 fclose(file);
139 #else
140 strcpy(path, "r200\n");
141 #endif
142 if ((length = strlen(path)) > 0)
143 path[length - 1] = '\0'; /* remove the trailing newline from sysfs */
144 strncat(path, "_dri", sizeof(path));
145
146 driver = _eglOpenDriver(dpy, path);
147
148 break;
149 }
150 closedir(dir);
151
152 return driver;
153 #endif
154 }
155
156
157 /**
158 * Called by eglCreateContext via drv->API.CreateContext().
159 */
160 static EGLContext
161 _eglDRICreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
162 EGLContext share_list, const EGLint *attrib_list)
163 {
164 driDisplay *disp = Lookup_driDisplay(dpy);
165 driContext *c, *share;
166 void *sharePriv;
167 _EGLConfig *conf;
168 __GLcontextModes visMode;
169
170 c = (driContext *) calloc(1, sizeof(*c));
171 if (!c)
172 return EGL_NO_CONTEXT;
173
174 conf = _eglLookupConfig(drv, dpy, config);
175 assert(conf);
176
177 if (!_eglInitContext(drv, &c->Base, conf, attrib_list)) {
178 free(c);
179 return EGL_NO_CONTEXT;
180 }
181
182 if (share_list != EGL_NO_CONTEXT) {
183 _EGLContext *shareCtx = _eglLookupContext(share_list);
184 if (!shareCtx) {
185 _eglError(EGL_BAD_CONTEXT, "eglCreateContext(share_list)");
186 return EGL_FALSE;
187 }
188 }
189 share = Lookup_driContext(share_list);
190 if (share)
191 sharePriv = share->driContext.private;
192 else
193 sharePriv = NULL;
194
195 _eglConfigToContextModesRec(conf, &visMode);
196
197 c->driContext.private = disp->driScreen.createNewContext(disp, &visMode,
198 GLX_WINDOW_BIT, sharePriv, &c->driContext);
199 if (!c->driContext.private) {
200 free(c);
201 return EGL_FALSE;
202 }
203
204 /* link to display */
205 _eglLinkContext(&c->Base, &disp->Base);
206
207 return _eglGetContextHandle(&c->Base);
208 }
209
210
211 static EGLBoolean
212 _eglDRIMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw,
213 EGLSurface read, EGLContext context)
214 {
215 driDisplay *disp = Lookup_driDisplay(dpy);
216 driContext *ctx = Lookup_driContext(context);
217 EGLBoolean b;
218 __DRIid drawBuf = (__DRIid) draw;
219 __DRIid readBuf = (__DRIid) read;
220
221 b = _eglMakeCurrent(drv, dpy, draw, read, context);
222 if (!b)
223 return EGL_FALSE;
224
225 if (ctx) {
226 ctx->driContext.bindContext(disp, 0, drawBuf, readBuf, &ctx->driContext);
227 }
228 else {
229 /* what's this??? */
230 /* _mesa_make_current( NULL, NULL, NULL );*/
231 }
232 return EGL_TRUE;
233 }
234
235
236 static EGLSurface
237 _eglDRICreatePbufferSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
238 const EGLint *attrib_list)
239 {
240 driSurface *surf;
241 _EGLConfig *conf;
242
243 conf = _eglLookupConfig(drv, dpy, config);
244 assert(conf);
245
246 surf = (driSurface *) calloc(1, sizeof(*surf));
247 if (!surf) {
248 return EGL_NO_SURFACE;
249 }
250
251 if (!_eglInitSurface(drv, &surf->Base, EGL_PBUFFER_BIT,
252 conf, attrib_list)) {
253 free(surf);
254 return EGL_NO_SURFACE;
255 }
256
257 /* create software-based pbuffer */
258 {
259 #if 0
260 GLcontext *ctx = NULL; /* this _should_ be OK */
261 #endif
262 __GLcontextModes visMode;
263 _EGLConfig *conf = _eglLookupConfig(drv, dpy, config);
264 assert(conf); /* bad config should be caught earlier */
265 _eglConfigToContextModesRec(conf, &visMode);
266
267 #if 0
268 surf->mesa_framebuffer = _mesa_create_framebuffer(&visMode);
269 _mesa_add_soft_renderbuffers(surf->mesa_framebuffer,
270 GL_TRUE, /* color bufs */
271 visMode.haveDepthBuffer,
272 visMode.haveStencilBuffer,
273 visMode.haveAccumBuffer,
274 GL_FALSE, /* alpha */
275 GL_FALSE /* aux */ );
276
277 /* set pbuffer/framebuffer size */
278 _mesa_resize_framebuffer(ctx, surf->mesa_framebuffer,
279 surf->Base.Width, surf->Base.Height);
280 #endif
281 }
282
283 _eglLinkSurface(&surf->Base, _eglLookupDisplay(dpy));
284
285 return surf->Base.Handle;
286 }
287
288
289 static EGLBoolean
290 _eglDRIDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
291 {
292 driDisplay *disp = Lookup_driDisplay(dpy);
293 driSurface *fs = Lookup_driSurface(surface);
294
295 _eglUnlinkSurface(&fs->Base);
296
297 fs->drawable.destroyDrawable(disp, fs->drawable.private);
298
299 if (!_eglIsSurfaceBound(&fs->Base))
300 free(fs);
301 return EGL_TRUE;
302 }
303
304
305 static EGLBoolean
306 _eglDRIDestroyContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext context)
307 {
308 driDisplay *disp = Lookup_driDisplay(dpy);
309 driContext *fc = Lookup_driContext(context);
310
311 _eglUnlinkContext(&fc->Base);
312
313 fc->driContext.destroyContext(disp, 0, fc->driContext.private);
314
315 if (!_eglIsContextBound(&fc->Base))
316 free(fc);
317 return EGL_TRUE;
318 }
319
320
321 /**
322 * Create a drawing surface which can be directly displayed on a screen.
323 */
324 static EGLSurface
325 _eglDRICreateScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLConfig cfg,
326 const EGLint *attrib_list)
327 {
328 _EGLConfig *config = _eglLookupConfig(drv, dpy, cfg);
329 driDisplay *disp = Lookup_driDisplay(dpy);
330 driSurface *surface;
331 __GLcontextModes visMode;
332 __DRIid drawBuf;
333
334 surface = (driSurface *) calloc(1, sizeof(*surface));
335 if (!surface) {
336 return EGL_NO_SURFACE;
337 }
338
339 /* init base class, do error checking, etc. */
340 if (!_eglInitSurface(drv, &surface->Base, EGL_SCREEN_BIT_MESA,
341 config, attrib_list)) {
342 free(surface);
343 return EGL_NO_SURFACE;
344 }
345
346 _eglLinkSurface(&surface->Base &disp->Base);
347
348
349 /*
350 * XXX this is where we should allocate video memory for the surface!
351 */
352
353
354 /* convert EGLConfig to GLvisual */
355 _eglConfigToContextModesRec(config, &visMode);
356
357 drawBuf = (__DRIid) _eglGetSurfaceHandle(&surface->Base);
358
359 /* Create a new DRI drawable */
360 if (!disp->driScreen.createNewDrawable(disp, &visMode, drawBuf,
361 &surface->drawable, GLX_WINDOW_BIT,
362 empty_attribute_list)) {
363 _eglUnlinkSurface(&surface->Base);
364 free(surface);
365 return EGL_NO_SURFACE;
366 }
367
368 return surface->Base.Handle;
369 }
370
371
372 /**
373 * Set the fbdev colormap to a simple linear ramp.
374 */
375 static void
376 _eglDRILoadColormap(driScreen *scrn)
377 {
378 char path[ NAME_MAX ];
379 char *buffer;
380 int i, fd;
381
382 /* cmap attribute uses 256 lines of 16 bytes.
383 * Allocate one extra char for the \0 added by sprintf()
384 */
385 if ( !( buffer = malloc( 256 * 16 + 1 ) ) ) {
386 _eglLog(_EGL_WARNING, "Out of memory in _eglDRILoadColormap");
387 return;
388 }
389
390 /* cmap attribute uses 256 lines of 16 bytes */
391 for ( i = 0; i < 256; i++ ) {
392 int c = (i << 8) | i; /* expand to 16-bit value */
393 sprintf(&buffer[i * 16], "%02x%c%04x%04x%04x\n", i, ' ', c, c, c);
394 }
395
396 snprintf(path, sizeof(path), "%s/graphics/%s/color_map", sysfs, scrn->fb);
397 if ( !( fd = open( path, O_RDWR ) ) ) {
398 _eglLog(_EGL_WARNING, "Unable to open %s to set colormap", path);
399 return;
400 }
401 write( fd, buffer, 256 * 16 );
402 close( fd );
403
404 free( buffer );
405 }
406
407
408 /**
409 * Show the given surface on the named screen.
410 * If surface is EGL_NO_SURFACE, disable the screen's output.
411 * Called via eglShowSurfaceMESA().
412 */
413 EGLBoolean
414 _eglDRIShowScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy,
415 EGLScreenMESA screen,
416 EGLSurface surface, EGLModeMESA m)
417 {
418 driDisplay *display = Lookup_driDisplay(dpy);
419 driScreen *scrn = Lookup_driScreen(dpy, screen);
420 driSurface *surf = Lookup_driSurface(surface);
421 _EGLMode *mode = _eglLookupMode(dpy, m);
422 FILE *file;
423 char fname[NAME_MAX], buffer[1000];
424 int temp;
425
426 _eglLog(_EGL_DEBUG, "Enter _eglDRIShowScreenSurface");
427
428 /* This will check that surface, screen, and mode are valid.
429 * Also, it checks that the surface is large enough for the mode, etc.
430 */
431 if (!_eglShowScreenSurfaceMESA(drv, dpy, screen, surface, m))
432 return EGL_FALSE;
433
434 assert(surface == EGL_NO_SURFACE || surf);
435 assert(m == EGL_NO_MODE_MESA || mode);
436 assert(scrn);
437
438 /*
439 * Blank/unblank screen depending on if m == EGL_NO_MODE_MESA
440 */
441 snprintf(fname, sizeof(fname), "%s/graphics/%s/blank", sysfs, scrn->fb);
442 file = fopen(fname, "r+");
443 if (!file) {
444 _eglLog(_EGL_WARNING, "kernel patch?? chown all fb sysfs attrib to allow"
445 " write - %s\n", fname);
446 return EGL_FALSE;
447 }
448 snprintf(buffer, sizeof(buffer), "%d",
449 (m == EGL_NO_MODE_MESA ? VESA_POWERDOWN : VESA_VSYNC_SUSPEND));
450 fputs(buffer, file);
451 fclose(file);
452
453 if (m == EGL_NO_MODE_MESA) {
454 /* all done! */
455 return EGL_TRUE;
456 }
457
458 _eglLog(_EGL_INFO, "Setting display mode to %d x %d, %d bpp",
459 mode->Width, mode->Height, display->bpp);
460
461 /*
462 * Set the display mode
463 */
464 snprintf(fname, sizeof(fname), "%s/graphics/%s/mode", sysfs, scrn->fb);
465 file = fopen(fname, "r+");
466 if (!file) {
467 _eglLog(_EGL_WARNING, "Failed to open %s to set mode", fname);
468 return EGL_FALSE;
469 }
470 /* note: nothing happens without the \n! */
471 snprintf(buffer, sizeof(buffer), "%s\n", mode->Name);
472 fputs(buffer, file);
473 fclose(file);
474 _eglLog(_EGL_INFO, "Set mode to %s in %s", mode->Name, fname);
475
476 /*
477 * Set display bpp
478 */
479 snprintf(fname, sizeof(fname), "%s/graphics/%s/bits_per_pixel",
480 sysfs, scrn->fb);
481 file = fopen(fname, "r+");
482 if (!file) {
483 _eglLog(_EGL_WARNING, "Failed to open %s to set bpp", fname);
484 return EGL_FALSE;
485 }
486 display->bpp = GET_CONFIG_ATTRIB(surf->Base.Config, EGL_BUFFER_SIZE);
487 display->cpp = display->bpp / 8;
488 snprintf(buffer, sizeof(buffer), "%d", display->bpp);
489 fputs(buffer, file);
490 fclose(file);
491
492 /*
493 * Unblank display
494 */
495 snprintf(fname, sizeof(fname), "%s/graphics/%s/blank", sysfs, scrn->fb);
496 file = fopen(fname, "r+");
497 if (!file) {
498 _eglLog(_EGL_WARNING, "Failed to open %s", fname);
499 return EGL_FALSE;
500 }
501 snprintf(buffer, sizeof(buffer), "%d", VESA_NO_BLANKING);
502 fputs(buffer, file);
503 fclose(file);
504
505 /*
506 * Set fbdev buffer virtual size to surface's size.
507 */
508 snprintf(fname, sizeof(fname), "%s/graphics/%s/virtual_size", sysfs, scrn->fb);
509 file = fopen(fname, "r+");
510 snprintf(buffer, sizeof(buffer), "%d,%d", surf->Base.Width, surf->Base.Height);
511 fputs(buffer, file);
512 rewind(file);
513 fgets(buffer, sizeof(buffer), file);
514 sscanf(buffer, "%d,%d", &display->virtualWidth, &display->virtualHeight);
515 fclose(file);
516
517 /*
518 * round up pitch as needed
519 */
520 temp = display->virtualWidth;
521 switch (display->bpp / 8) {
522 case 1: temp = (display->virtualWidth + 127) & ~127; break;
523 case 2: temp = (display->virtualWidth + 31) & ~31; break;
524 case 3:
525 case 4: temp = (display->virtualWidth + 15) & ~15; break;
526 default:
527 _eglLog(_EGL_WARNING, "Bad display->bpp = %d in _eglDRIShowScreenSurface");
528 }
529 display->virtualWidth = temp;
530
531 /*
532 * sanity check
533 */
534 if (surf->Base.Width < display->virtualWidth ||
535 surf->Base.Height < display->virtualHeight) {
536 /* this case _should_ have been caught at the top of this function */
537 _eglLog(_EGL_WARNING, "too small of surface in _eglDRIShowScreenSurfaceMESA "
538 "%d x %d < %d x %d",
539 surf->Base.Width,
540 surf->Base.Height,
541 display->virtualWidth,
542 display->virtualHeight);
543 /*
544 return EGL_FALSE;
545 */
546 }
547
548 /* This used to be done in the _eglDRICreateScreens routine. */
549 _eglDRILoadColormap(scrn);
550
551 return EGL_TRUE;
552 }
553
554
555 /**
556 * Called by eglSwapBuffers via the drv->API.SwapBuffers() pointer.
557 *
558 * If the backbuffer is on a videocard, this is extraordinarily slow!
559 */
560 static EGLBoolean
561 _eglDRISwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
562 {
563 driSurface *drawable = Lookup_driSurface(draw);
564
565 /* this does error checking */
566 if (!_eglSwapBuffers(drv, dpy, draw))
567 return EGL_FALSE;
568
569 drawable->drawable.swapBuffers(NULL, drawable->drawable.private);
570
571 return EGL_TRUE;
572 }
573
574
575 EGLBoolean
576 _eglDRIGetDisplayInfo(driDisplay *dpy)
577 {
578 char path[ NAME_MAX ];
579 FILE *file;
580 int i, rc;
581 drmSetVersion sv;
582 drm_magic_t magic;
583
584 snprintf( path, sizeof( path ), "%s/graphics/fb%d/device/device", sysfs, dpy->minor );
585 file = fopen( path, "r" );
586 if (!file) {
587 _eglLog(_EGL_WARNING, "Unable to open %s", path);
588 return EGL_FALSE;
589 }
590 fgets( path, sizeof( path ), file );
591 sscanf( path, "%x", &dpy->chipset );
592 fclose( file );
593
594 sprintf(path, DRM_DEV_NAME, DRM_DIR_NAME, dpy->minor);
595 if ( ( dpy->drmFD = open(path, O_RDWR, 0) ) < 0 ) {
596 _eglLog(_EGL_WARNING, "drmOpen failed.");
597 return EGL_FALSE;
598 }
599
600 /* Set the interface version, asking for 1.2 */
601 sv.drm_di_major = 1;
602 sv.drm_di_minor = 2;
603 sv.drm_dd_major = -1;
604 if ((rc = drmSetInterfaceVersion(dpy->drmFD, &sv)))
605 return EGL_FALSE;
606
607 /* self authorize */
608 if (drmGetMagic(dpy->drmFD, &magic))
609 return EGL_FALSE;
610 if (drmAuthMagic(dpy->drmFD, magic))
611 return EGL_FALSE;
612
613 /* Map framebuffer and SAREA */
614 for (i = 0; ; i++) {
615 drm_handle_t handle, offset;
616 drmSize size;
617 drmMapType type;
618 drmMapFlags flags;
619 int mtrr;
620
621 if (drmGetMap(dpy->drmFD, i, &offset, &size, &type, &flags,
622 &handle, &mtrr))
623 break;
624
625 if (type == DRM_FRAME_BUFFER) {
626 rc = drmMap( dpy->drmFD, offset, size, (drmAddressPtr) &dpy->pFB);
627 if (rc < 0) {
628 _eglLog(_EGL_WARNING, "drmMap DRM_FAME_BUFFER failed");
629 return EGL_FALSE;
630 }
631 dpy->fbSize = size;
632 _eglLog(_EGL_INFO, "Found framebuffer size: %d", dpy->fbSize);
633 }
634 else if (type == DRM_SHM) {
635 rc = drmMap(dpy->drmFD, offset, size, (drmAddressPtr) &dpy->pSAREA);
636 if (rc < 0 ) {
637 _eglLog(_EGL_WARNING, "drmMap DRM_SHM failed.");
638 return EGL_FALSE;
639 }
640 dpy->SAREASize = SAREA_MAX;
641 _eglLog(_EGL_DEBUG, "mapped SAREA 0x%08lx to %p, size %d",
642 (unsigned long) offset, dpy->pSAREA, dpy->SAREASize );
643 }
644 }
645
646 if (!dpy->pFB) {
647 _eglLog(_EGL_WARNING, "failed to map framebuffer");
648 return EGL_FALSE;
649 }
650
651 if (!dpy->pSAREA) {
652 /* if this happens, make sure you're using the most recent DRM modules */
653 _eglLog(_EGL_WARNING, "failed to map SAREA");
654 return EGL_FALSE;
655 }
656
657 memset( dpy->pSAREA, 0, dpy->SAREASize );
658
659 return EGL_TRUE;
660 }
661
662
663 /* Return the DRI per screen structure */
664 static __DRIscreen *
665 __eglFindDRIScreen(__DRInativeDisplay *ndpy, int scrn)
666 {
667 driDisplay *disp = (driDisplay *)ndpy;
668 return &disp->driScreen;
669 }
670
671
672 static GLboolean
673 __eglCreateContextWithConfig(__DRInativeDisplay* ndpy, int screen,
674 int configID, void* context,
675 drm_context_t * hHWContext)
676 {
677 __DRIscreen *pDRIScreen;
678 __DRIscreen *psp;
679
680 pDRIScreen = __eglFindDRIScreen(ndpy, screen);
681 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
682 return GL_FALSE;
683 }
684 psp = (__DRIscreen *) pDRIScreen->private;
685 if (psp->fd) {
686 if (drmCreateContext(psp->fd, hHWContext)) {
687 _eglLog(_EGL_WARNING, "drmCreateContext failed.");
688 return GL_FALSE;
689 }
690 *(void**)context = (void*) *hHWContext;
691 }
692 #if 0
693 __DRIscreen *pDRIScreen;
694 __DRIscreen *psp;
695
696 pDRIScreen = __glXFindDRIScreen(dpy, screen);
697 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
698 return GL_FALSE;
699 }
700
701 psp = (__DRIscreen *) pDRIScreen->private;
702
703 if (psp->fd) {
704 if (drmCreateContext(psp->fd, hHWContext)) {
705 _eglLog(_EGL_WARNING, "drmCreateContext failed.");
706 return GL_FALSE;
707 }
708 *(void**)contextID = (void*) *hHWContext;
709 }
710 #endif
711 return GL_TRUE;
712 }
713
714
715 static GLboolean
716 __eglDestroyContext( __DRInativeDisplay * ndpy, int screen, __DRIid context )
717 {
718 __DRIscreen *pDRIScreen;
719 __DRIscreen *psp;
720
721 pDRIScreen = __eglFindDRIScreen(ndpy, screen);
722 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
723 return GL_FALSE;
724 }
725 psp = (__DRIscreen *) pDRIScreen->private;
726 if (psp->fd)
727 drmDestroyContext(psp->fd, context);
728
729 return GL_TRUE;
730 }
731
732
733 static GLboolean
734 __eglCreateDrawable(__DRInativeDisplay * ndpy, int screen,
735 __DRIid drawable, drm_drawable_t * hHWDrawable)
736 {
737 __DRIscreen *pDRIScreen;
738 __DRIscreen *psp;
739
740 pDRIScreen = __eglFindDRIScreen(ndpy, screen);
741 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
742 return GL_FALSE;
743 }
744 psp = (__DRIscreen *) pDRIScreen->private;
745 if (psp->fd) {
746 if (drmCreateDrawable(psp->fd, hHWDrawable)) {
747 _eglLog(_EGL_WARNING, "drmCreateDrawable failed.");
748 return GL_FALSE;
749 }
750 }
751 return GL_TRUE;
752 }
753
754
755 static GLboolean
756 __eglDestroyDrawable( __DRInativeDisplay * ndpy, int screen, __DRIid drawable )
757 {
758 __DRIscreen *pDRIScreen;
759 __DRIscreen *psp;
760
761 pDRIScreen = __eglFindDRIScreen(ndpy, screen);
762 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
763 return GL_FALSE;
764 }
765 psp = (__DRIscreen *) pDRIScreen->private;
766 if (psp->fd)
767 drmDestroyDrawable(psp->fd, drawable);
768
769 return GL_TRUE;
770 }
771
772 static GLboolean
773 __eglGetDrawableInfo(__DRInativeDisplay * ndpy, int screen, __DRIid drawable,
774 unsigned int* index, unsigned int* stamp,
775 int* X, int* Y, int* W, int* H,
776 int* numClipRects, drm_clip_rect_t ** pClipRects,
777 int* backX, int* backY,
778 int* numBackClipRects, drm_clip_rect_t ** pBackClipRects )
779 {
780 __DRIscreen *pDRIScreen;
781 __DRIscreen *psp;
782 driSurface *surf = Lookup_driSurface((EGLSurface) drawable);
783
784 pDRIScreen = __eglFindDRIScreen(ndpy, screen);
785
786 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
787 return GL_FALSE;
788 }
789 psp = (__DRIscreen *) pDRIScreen->private;
790 *X = 0;
791 *Y = 0;
792 *W = surf->Base.Width;
793 *H = surf->Base.Height;
794
795 *backX = 0;
796 *backY = 0;
797 *numBackClipRects = 0;
798 *pBackClipRects = NULL;
799
800 *numClipRects = 1;
801 *pClipRects = malloc(sizeof(**pClipRects));
802 **pClipRects = (drm_clip_rect_t){0, 0, surf->Base.Width, surf->Base.Height};
803
804 psp->pSAREA->drawableTable[0].stamp = 1;
805 *stamp = 1;
806 #if 0
807 GLXDrawable drawable = (GLXDrawable) draw;
808 drm_clip_rect_t * cliprect;
809 Display* display = (Display*)dpy;
810 __DRIcontext *pcp = (__DRIcontext *)CurrentContext->driContext.private;
811 if (drawable == 0) {
812 return GL_FALSE;
813 }
814
815 cliprect = (drm_clip_rect_t*) _mesa_malloc(sizeof(drm_clip_rect_t));
816 cliprect->x1 = drawable->x;
817 cliprect->y1 = drawable->y;
818 cliprect->x2 = drawable->x + drawable->w;
819 cliprect->y2 = drawable->y + drawable->h;
820
821 /* the drawable index is by client id */
822 *index = display->clientID;
823
824 *stamp = pcp->driScreenPriv->pSAREA->drawableTable[display->clientID].stamp;
825 *x = drawable->x;
826 *y = drawable->y;
827 *width = drawable->w;
828 *height = drawable->h;
829 *numClipRects = 1;
830 *pClipRects = cliprect;
831
832 *backX = drawable->x;
833 *backY = drawable->y;
834 *numBackClipRects = 0;
835 *pBackClipRects = 0;
836 #endif
837 return GL_TRUE;
838 }
839
840
841 /**
842 * Implement \c __DRIinterfaceMethods::getProcAddress.
843 */
844 static __DRIfuncPtr
845 get_proc_address(const char * proc_name)
846 {
847 return NULL;
848 }
849
850
851 /**
852 * Destroy a linked list of \c __GLcontextModes structures created by
853 * \c _gl_context_modes_create.
854 *
855 * \param modes Linked list of structures to be destroyed. All structres
856 * in the list will be freed.
857 */
858 static void
859 __egl_context_modes_destroy(__GLcontextModes *modes)
860 {
861 while ( modes != NULL ) {
862 __GLcontextModes * const next = modes->next;
863
864 free( modes );
865 modes = next;
866 }
867 }
868
869
870 /**
871 * Allocate a linked list of \c __GLcontextModes structures. The fields of
872 * each structure will be initialized to "reasonable" default values. In
873 * most cases this is the default value defined by table 3.4 of the GLX
874 * 1.3 specification. This means that most values are either initialized to
875 * zero or \c GLX_DONT_CARE (which is -1). As support for additional
876 * extensions is added, the new values will be initialized to appropriate
877 * values from the extension specification.
878 *
879 * \param count Number of structures to allocate.
880 * \param minimum_size Minimum size of a structure to allocate. This allows
881 * for differences in the version of the
882 * \c __GLcontextModes stucture used in libGL and in a
883 * DRI-based driver.
884 * \returns A pointer to the first element in a linked list of \c count
885 * stuctures on success, or \c NULL on failure.
886 *
887 * \warning Use of \c minimum_size does \b not guarantee binary compatibility.
888 * The fundamental assumption is that if the \c minimum_size
889 * specified by the driver and the size of the \c __GLcontextModes
890 * structure in libGL is the same, then the meaning of each byte in
891 * the structure is the same in both places. \b Be \b careful!
892 * Basically this means that fields have to be added in libGL and
893 * then propagated to drivers. Drivers should \b never arbitrarilly
894 * extend the \c __GLcontextModes data-structure.
895 */
896 static __GLcontextModes *
897 __egl_context_modes_create(unsigned count, size_t minimum_size)
898 {
899 const size_t size = (minimum_size > sizeof( __GLcontextModes ))
900 ? minimum_size : sizeof( __GLcontextModes );
901 __GLcontextModes * base = NULL;
902 __GLcontextModes ** next;
903 unsigned i;
904
905 next = & base;
906 for ( i = 0 ; i < count ; i++ ) {
907 *next = (__GLcontextModes *) malloc( size );
908 if ( *next == NULL ) {
909 __egl_context_modes_destroy( base );
910 base = NULL;
911 break;
912 }
913
914 (void) memset( *next, 0, size );
915 (*next)->visualID = GLX_DONT_CARE;
916 (*next)->visualType = GLX_DONT_CARE;
917 (*next)->visualRating = GLX_NONE;
918 (*next)->transparentPixel = GLX_NONE;
919 (*next)->transparentRed = GLX_DONT_CARE;
920 (*next)->transparentGreen = GLX_DONT_CARE;
921 (*next)->transparentBlue = GLX_DONT_CARE;
922 (*next)->transparentAlpha = GLX_DONT_CARE;
923 (*next)->transparentIndex = GLX_DONT_CARE;
924 (*next)->xRenderable = GLX_DONT_CARE;
925 (*next)->fbconfigID = GLX_DONT_CARE;
926 (*next)->swapMethod = GLX_SWAP_UNDEFINED_OML;
927
928 next = & ((*next)->next);
929 }
930
931 return base;
932 }
933
934
935 static GLboolean
936 __eglWindowExists(__DRInativeDisplay *dpy, __DRIid draw)
937 {
938 return EGL_TRUE;
939 }
940
941
942 /**
943 * Get the unadjusted system time (UST). Currently, the UST is measured in
944 * microseconds since Epoc. The actual resolution of the UST may vary from
945 * system to system, and the units may vary from release to release.
946 * Drivers should not call this function directly. They should instead use
947 * \c glXGetProcAddress to obtain a pointer to the function.
948 *
949 * \param ust Location to store the 64-bit UST
950 * \returns Zero on success or a negative errno value on failure.
951 *
952 * \sa glXGetProcAddress, PFNGLXGETUSTPROC
953 *
954 * \since Internal API version 20030317.
955 */
956 static int
957 __eglGetUST(int64_t *ust)
958 {
959 struct timeval tv;
960
961 if ( ust == NULL ) {
962 return -EFAULT;
963 }
964
965 if ( gettimeofday( & tv, NULL ) == 0 ) {
966 ust[0] = (tv.tv_sec * 1000000) + tv.tv_usec;
967 return 0;
968 }
969 else {
970 return -errno;
971 }
972 }
973
974 /**
975 * Determine the refresh rate of the specified drawable and display.
976 *
977 * \param dpy Display whose refresh rate is to be determined.
978 * \param drawable Drawable whose refresh rate is to be determined.
979 * \param numerator Numerator of the refresh rate.
980 * \param demoninator Denominator of the refresh rate.
981 * \return If the refresh rate for the specified display and drawable could
982 * be calculated, True is returned. Otherwise False is returned.
983 *
984 * \note This function is implemented entirely client-side. A lot of other
985 * functionality is required to export GLX_OML_sync_control, so on
986 * XFree86 this function can be called for direct-rendering contexts
987 * when GLX_OML_sync_control appears in the client extension string.
988 */
989 static GLboolean
990 __eglGetMSCRate(__DRInativeDisplay * dpy, __DRIid drawable,
991 int32_t * numerator, int32_t * denominator)
992 {
993 return EGL_TRUE;
994 }
995
996
997 /**
998 * Table of functions exported by the loader to the driver.
999 */
1000 static const __DRIinterfaceMethods interface_methods = {
1001 get_proc_address,
1002
1003 __egl_context_modes_create,
1004 __egl_context_modes_destroy,
1005
1006 __eglFindDRIScreen,
1007 __eglWindowExists,
1008
1009 __eglCreateContextWithConfig,
1010 __eglDestroyContext,
1011
1012 __eglCreateDrawable,
1013 __eglDestroyDrawable,
1014 __eglGetDrawableInfo,
1015
1016 __eglGetUST,
1017 __eglGetMSCRate,
1018 };
1019
1020
1021 static int
1022 __glXGetInternalVersion(void)
1023 {
1024 return 20050725;
1025 }
1026
1027 static const char createNewScreenName[] = "__driCreateNewScreen_20050727";
1028
1029
1030 /**
1031 * Do per-display initialization.
1032 */
1033 EGLBoolean
1034 _eglDRICreateDisplay(driDisplay *dpy, __DRIframebuffer *framebuffer)
1035 {
1036 PFNCREATENEWSCREENFUNC createNewScreen;
1037 int api_ver = __glXGetInternalVersion();
1038 __DRIversion ddx_version;
1039 __DRIversion dri_version;
1040 __DRIversion drm_version;
1041 drmVersionPtr version;
1042
1043 version = drmGetVersion( dpy->drmFD );
1044 if ( version ) {
1045 drm_version.major = version->version_major;
1046 drm_version.minor = version->version_minor;
1047 drm_version.patch = version->version_patchlevel;
1048 drmFreeVersion( version );
1049 }
1050 else {
1051 drm_version.major = -1;
1052 drm_version.minor = -1;
1053 drm_version.patch = -1;
1054 }
1055
1056 /*
1057 * Get device name (like "tdfx") and the ddx version numbers.
1058 * We'll check the version in each DRI driver's "createScreen"
1059 * function.
1060 */
1061 ddx_version.major = 4;
1062 ddx_version.minor = 0;
1063 ddx_version.patch = 0;
1064
1065 /*
1066 * Get the DRI X extension version.
1067 */
1068 dri_version.major = 4;
1069 dri_version.minor = 0;
1070 dri_version.patch = 0;
1071
1072 createNewScreen = ( PFNCREATENEWSCREENFUNC ) dlsym( dpy->Base.Driver->LibHandle, createNewScreenName );
1073 if ( !createNewScreen ) {
1074 _eglLog(_EGL_WARNING, "Couldn't find %s function in the driver.",
1075 createNewScreenName );
1076 return EGL_FALSE;
1077 }
1078
1079 dpy->driScreen.private = createNewScreen( dpy, 0, &dpy->driScreen, NULL,
1080 &ddx_version, &dri_version,
1081 &drm_version, framebuffer,
1082 dpy->pSAREA, dpy->drmFD,
1083 api_ver,
1084 & interface_methods,
1085 NULL);
1086 if (!dpy->driScreen.private) {
1087 _eglLog(_EGL_WARNING, "egldri.c: DRI create new screen failed");
1088 return EGL_FALSE;
1089 }
1090
1091 DRM_UNLOCK( dpy->drmFD, dpy->pSAREA, dpy->serverContext );
1092
1093 return EGL_TRUE;
1094 }
1095
1096
1097 /**
1098 * Create all the EGL screens for the given display.
1099 */
1100 EGLBoolean
1101 _eglDRICreateScreens(driDisplay *dpy)
1102 {
1103 const int numScreens = 1; /* XXX fix this someday */
1104 int i;
1105
1106 for (i = 0; i < numScreens; i++) {
1107 char path[ NAME_MAX ];
1108 FILE *file;
1109 driScreen *s;
1110
1111 /* Create a screen */
1112 if ( !( s = ( driScreen * ) calloc( 1, sizeof( *s ) ) ) )
1113 return EGL_FALSE;
1114
1115 snprintf( s->fb, NAME_MAX, "fb%d", dpy->minor );
1116 _eglInitScreen( &s->Base );
1117
1118 _eglAddScreen( &dpy->Base, &s->Base );
1119
1120 /* Create the screen's mode list */
1121 snprintf( path, sizeof( path ), "%s/graphics/%s/modes", sysfs, s->fb );
1122 file = fopen( path, "r" );
1123 while ( fgets( path, sizeof( path ), file ) ) {
1124 unsigned int x, y, r;
1125 char c;
1126 path[ strlen( path ) - 1 ] = '\0'; /* strip off \n from sysfs */
1127 sscanf( path, "%c:%ux%u-%u", &c, &x, &y, &r );
1128 _eglAddNewMode( &s->Base, x, y, r * 1000, path );
1129 }
1130 fclose( file );
1131
1132 /*
1133 * NOTE: we used to set the colormap here, but that didn't work reliably.
1134 * Some entries near the start of the table would get corrupted by later
1135 * mode changes.
1136 */
1137 }
1138
1139 return EGL_TRUE;
1140 }
1141
1142
1143 EGLBoolean
1144 _eglDRIInitialize(_EGLDriver *drv, EGLDisplay dpy,
1145 EGLint *major, EGLint *minor)
1146 {
1147 _EGLDisplay *disp = _eglLookupDisplay(dpy);
1148 driDisplay *display;
1149 const char *driverName = (const char *) disp->NativeDisplay;
1150
1151 assert(disp);
1152
1153 /* Create new driDisplay object to replace the _EGLDisplay that was
1154 * previously created.
1155 */
1156 display = calloc(1, sizeof(*display));
1157 display->Base = *disp;
1158 _eglSaveDisplay(&display->Base);
1159 free(disp);
1160
1161 *major = 1;
1162 *minor = 0;
1163
1164 sscanf(driverName + 1, "%d", &display->minor);
1165
1166 drv->Initialized = EGL_TRUE;
1167 return EGL_TRUE;
1168 }
1169
1170
1171 static EGLBoolean
1172 _eglDRITerminate(_EGLDriver *drv, EGLDisplay dpy)
1173 {
1174 driDisplay *display = Lookup_driDisplay(dpy);
1175 _eglCleanupDisplay(&display->Base);/*rename that function*/
1176 free(display);
1177 free(drv);
1178 return EGL_TRUE;
1179 }
1180
1181
1182 /**
1183 * Plug in the DRI-specific functions into the driver's dispatch table.
1184 * Also, enable some EGL extensions.
1185 */
1186 void
1187 _eglDRIInitDriverFallbacks(_EGLDriver *drv)
1188 {
1189 _eglInitDriverFallbacks(drv);
1190
1191 drv->API.Initialize = _eglDRIInitialize;
1192 drv->API.Terminate = _eglDRITerminate;
1193 drv->API.CreateContext = _eglDRICreateContext;
1194 drv->API.MakeCurrent = _eglDRIMakeCurrent;
1195 drv->API.CreatePbufferSurface = _eglDRICreatePbufferSurface;
1196 drv->API.DestroySurface = _eglDRIDestroySurface;
1197 drv->API.DestroyContext = _eglDRIDestroyContext;
1198 drv->API.CreateScreenSurfaceMESA = _eglDRICreateScreenSurfaceMESA;
1199 drv->API.ShowScreenSurfaceMESA = _eglDRIShowScreenSurfaceMESA;
1200 drv->API.SwapBuffers = _eglDRISwapBuffers;
1201
1202 /* enable supported extensions */
1203 drv->Extensions.MESA_screen_surface = EGL_TRUE;
1204 drv->Extensions.MESA_copy_context = EGL_TRUE;
1205 }