egl: Use the link functions to manage resources.
[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 (fs->Base.IsBound) {
300 fs->Base.DeletePending = EGL_TRUE;
301 }
302 else {
303 free(fs);
304 }
305 return EGL_TRUE;
306 }
307
308
309 static EGLBoolean
310 _eglDRIDestroyContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext context)
311 {
312 driDisplay *disp = Lookup_driDisplay(dpy);
313 driContext *fc = Lookup_driContext(context);
314
315 _eglUnlinkContext(&fc->Base);
316
317 fc->driContext.destroyContext(disp, 0, fc->driContext.private);
318
319 if (fc->Base.IsBound) {
320 fc->Base.DeletePending = EGL_TRUE;
321 }
322 else {
323 free(fc);
324 }
325 return EGL_TRUE;
326 }
327
328
329 /**
330 * Create a drawing surface which can be directly displayed on a screen.
331 */
332 static EGLSurface
333 _eglDRICreateScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLConfig cfg,
334 const EGLint *attrib_list)
335 {
336 _EGLConfig *config = _eglLookupConfig(drv, dpy, cfg);
337 driDisplay *disp = Lookup_driDisplay(dpy);
338 driSurface *surface;
339 __GLcontextModes visMode;
340 __DRIid drawBuf;
341
342 surface = (driSurface *) calloc(1, sizeof(*surface));
343 if (!surface) {
344 return EGL_NO_SURFACE;
345 }
346
347 /* init base class, do error checking, etc. */
348 if (!_eglInitSurface(drv, &surface->Base, EGL_SCREEN_BIT_MESA,
349 config, attrib_list)) {
350 free(surface);
351 return EGL_NO_SURFACE;
352 }
353
354 _eglLinkSurface(&surface->Base &disp->Base);
355
356
357 /*
358 * XXX this is where we should allocate video memory for the surface!
359 */
360
361
362 /* convert EGLConfig to GLvisual */
363 _eglConfigToContextModesRec(config, &visMode);
364
365 drawBuf = (__DRIid) _eglGetSurfaceHandle(&surface->Base);
366
367 /* Create a new DRI drawable */
368 if (!disp->driScreen.createNewDrawable(disp, &visMode, drawBuf,
369 &surface->drawable, GLX_WINDOW_BIT,
370 empty_attribute_list)) {
371 _eglUnlinkSurface(&surface->Base);
372 free(surface);
373 return EGL_NO_SURFACE;
374 }
375
376 return surface->Base.Handle;
377 }
378
379
380 /**
381 * Set the fbdev colormap to a simple linear ramp.
382 */
383 static void
384 _eglDRILoadColormap(driScreen *scrn)
385 {
386 char path[ NAME_MAX ];
387 char *buffer;
388 int i, fd;
389
390 /* cmap attribute uses 256 lines of 16 bytes.
391 * Allocate one extra char for the \0 added by sprintf()
392 */
393 if ( !( buffer = malloc( 256 * 16 + 1 ) ) ) {
394 _eglLog(_EGL_WARNING, "Out of memory in _eglDRILoadColormap");
395 return;
396 }
397
398 /* cmap attribute uses 256 lines of 16 bytes */
399 for ( i = 0; i < 256; i++ ) {
400 int c = (i << 8) | i; /* expand to 16-bit value */
401 sprintf(&buffer[i * 16], "%02x%c%04x%04x%04x\n", i, ' ', c, c, c);
402 }
403
404 snprintf(path, sizeof(path), "%s/graphics/%s/color_map", sysfs, scrn->fb);
405 if ( !( fd = open( path, O_RDWR ) ) ) {
406 _eglLog(_EGL_WARNING, "Unable to open %s to set colormap", path);
407 return;
408 }
409 write( fd, buffer, 256 * 16 );
410 close( fd );
411
412 free( buffer );
413 }
414
415
416 /**
417 * Show the given surface on the named screen.
418 * If surface is EGL_NO_SURFACE, disable the screen's output.
419 * Called via eglShowSurfaceMESA().
420 */
421 EGLBoolean
422 _eglDRIShowScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy,
423 EGLScreenMESA screen,
424 EGLSurface surface, EGLModeMESA m)
425 {
426 driDisplay *display = Lookup_driDisplay(dpy);
427 driScreen *scrn = Lookup_driScreen(dpy, screen);
428 driSurface *surf = Lookup_driSurface(surface);
429 _EGLMode *mode = _eglLookupMode(dpy, m);
430 FILE *file;
431 char fname[NAME_MAX], buffer[1000];
432 int temp;
433
434 _eglLog(_EGL_DEBUG, "Enter _eglDRIShowScreenSurface");
435
436 /* This will check that surface, screen, and mode are valid.
437 * Also, it checks that the surface is large enough for the mode, etc.
438 */
439 if (!_eglShowScreenSurfaceMESA(drv, dpy, screen, surface, m))
440 return EGL_FALSE;
441
442 assert(surface == EGL_NO_SURFACE || surf);
443 assert(m == EGL_NO_MODE_MESA || mode);
444 assert(scrn);
445
446 /*
447 * Blank/unblank screen depending on if m == EGL_NO_MODE_MESA
448 */
449 snprintf(fname, sizeof(fname), "%s/graphics/%s/blank", sysfs, scrn->fb);
450 file = fopen(fname, "r+");
451 if (!file) {
452 _eglLog(_EGL_WARNING, "kernel patch?? chown all fb sysfs attrib to allow"
453 " write - %s\n", fname);
454 return EGL_FALSE;
455 }
456 snprintf(buffer, sizeof(buffer), "%d",
457 (m == EGL_NO_MODE_MESA ? VESA_POWERDOWN : VESA_VSYNC_SUSPEND));
458 fputs(buffer, file);
459 fclose(file);
460
461 if (m == EGL_NO_MODE_MESA) {
462 /* all done! */
463 return EGL_TRUE;
464 }
465
466 _eglLog(_EGL_INFO, "Setting display mode to %d x %d, %d bpp",
467 mode->Width, mode->Height, display->bpp);
468
469 /*
470 * Set the display mode
471 */
472 snprintf(fname, sizeof(fname), "%s/graphics/%s/mode", sysfs, scrn->fb);
473 file = fopen(fname, "r+");
474 if (!file) {
475 _eglLog(_EGL_WARNING, "Failed to open %s to set mode", fname);
476 return EGL_FALSE;
477 }
478 /* note: nothing happens without the \n! */
479 snprintf(buffer, sizeof(buffer), "%s\n", mode->Name);
480 fputs(buffer, file);
481 fclose(file);
482 _eglLog(_EGL_INFO, "Set mode to %s in %s", mode->Name, fname);
483
484 /*
485 * Set display bpp
486 */
487 snprintf(fname, sizeof(fname), "%s/graphics/%s/bits_per_pixel",
488 sysfs, scrn->fb);
489 file = fopen(fname, "r+");
490 if (!file) {
491 _eglLog(_EGL_WARNING, "Failed to open %s to set bpp", fname);
492 return EGL_FALSE;
493 }
494 display->bpp = GET_CONFIG_ATTRIB(surf->Base.Config, EGL_BUFFER_SIZE);
495 display->cpp = display->bpp / 8;
496 snprintf(buffer, sizeof(buffer), "%d", display->bpp);
497 fputs(buffer, file);
498 fclose(file);
499
500 /*
501 * Unblank display
502 */
503 snprintf(fname, sizeof(fname), "%s/graphics/%s/blank", sysfs, scrn->fb);
504 file = fopen(fname, "r+");
505 if (!file) {
506 _eglLog(_EGL_WARNING, "Failed to open %s", fname);
507 return EGL_FALSE;
508 }
509 snprintf(buffer, sizeof(buffer), "%d", VESA_NO_BLANKING);
510 fputs(buffer, file);
511 fclose(file);
512
513 /*
514 * Set fbdev buffer virtual size to surface's size.
515 */
516 snprintf(fname, sizeof(fname), "%s/graphics/%s/virtual_size", sysfs, scrn->fb);
517 file = fopen(fname, "r+");
518 snprintf(buffer, sizeof(buffer), "%d,%d", surf->Base.Width, surf->Base.Height);
519 fputs(buffer, file);
520 rewind(file);
521 fgets(buffer, sizeof(buffer), file);
522 sscanf(buffer, "%d,%d", &display->virtualWidth, &display->virtualHeight);
523 fclose(file);
524
525 /*
526 * round up pitch as needed
527 */
528 temp = display->virtualWidth;
529 switch (display->bpp / 8) {
530 case 1: temp = (display->virtualWidth + 127) & ~127; break;
531 case 2: temp = (display->virtualWidth + 31) & ~31; break;
532 case 3:
533 case 4: temp = (display->virtualWidth + 15) & ~15; break;
534 default:
535 _eglLog(_EGL_WARNING, "Bad display->bpp = %d in _eglDRIShowScreenSurface");
536 }
537 display->virtualWidth = temp;
538
539 /*
540 * sanity check
541 */
542 if (surf->Base.Width < display->virtualWidth ||
543 surf->Base.Height < display->virtualHeight) {
544 /* this case _should_ have been caught at the top of this function */
545 _eglLog(_EGL_WARNING, "too small of surface in _eglDRIShowScreenSurfaceMESA "
546 "%d x %d < %d x %d",
547 surf->Base.Width,
548 surf->Base.Height,
549 display->virtualWidth,
550 display->virtualHeight);
551 /*
552 return EGL_FALSE;
553 */
554 }
555
556 /* This used to be done in the _eglDRICreateScreens routine. */
557 _eglDRILoadColormap(scrn);
558
559 return EGL_TRUE;
560 }
561
562
563 /**
564 * Called by eglSwapBuffers via the drv->API.SwapBuffers() pointer.
565 *
566 * If the backbuffer is on a videocard, this is extraordinarily slow!
567 */
568 static EGLBoolean
569 _eglDRISwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
570 {
571 driSurface *drawable = Lookup_driSurface(draw);
572
573 /* this does error checking */
574 if (!_eglSwapBuffers(drv, dpy, draw))
575 return EGL_FALSE;
576
577 drawable->drawable.swapBuffers(NULL, drawable->drawable.private);
578
579 return EGL_TRUE;
580 }
581
582
583 EGLBoolean
584 _eglDRIGetDisplayInfo(driDisplay *dpy)
585 {
586 char path[ NAME_MAX ];
587 FILE *file;
588 int i, rc;
589 drmSetVersion sv;
590 drm_magic_t magic;
591
592 snprintf( path, sizeof( path ), "%s/graphics/fb%d/device/device", sysfs, dpy->minor );
593 file = fopen( path, "r" );
594 if (!file) {
595 _eglLog(_EGL_WARNING, "Unable to open %s", path);
596 return EGL_FALSE;
597 }
598 fgets( path, sizeof( path ), file );
599 sscanf( path, "%x", &dpy->chipset );
600 fclose( file );
601
602 sprintf(path, DRM_DEV_NAME, DRM_DIR_NAME, dpy->minor);
603 if ( ( dpy->drmFD = open(path, O_RDWR, 0) ) < 0 ) {
604 _eglLog(_EGL_WARNING, "drmOpen failed.");
605 return EGL_FALSE;
606 }
607
608 /* Set the interface version, asking for 1.2 */
609 sv.drm_di_major = 1;
610 sv.drm_di_minor = 2;
611 sv.drm_dd_major = -1;
612 if ((rc = drmSetInterfaceVersion(dpy->drmFD, &sv)))
613 return EGL_FALSE;
614
615 /* self authorize */
616 if (drmGetMagic(dpy->drmFD, &magic))
617 return EGL_FALSE;
618 if (drmAuthMagic(dpy->drmFD, magic))
619 return EGL_FALSE;
620
621 /* Map framebuffer and SAREA */
622 for (i = 0; ; i++) {
623 drm_handle_t handle, offset;
624 drmSize size;
625 drmMapType type;
626 drmMapFlags flags;
627 int mtrr;
628
629 if (drmGetMap(dpy->drmFD, i, &offset, &size, &type, &flags,
630 &handle, &mtrr))
631 break;
632
633 if (type == DRM_FRAME_BUFFER) {
634 rc = drmMap( dpy->drmFD, offset, size, (drmAddressPtr) &dpy->pFB);
635 if (rc < 0) {
636 _eglLog(_EGL_WARNING, "drmMap DRM_FAME_BUFFER failed");
637 return EGL_FALSE;
638 }
639 dpy->fbSize = size;
640 _eglLog(_EGL_INFO, "Found framebuffer size: %d", dpy->fbSize);
641 }
642 else if (type == DRM_SHM) {
643 rc = drmMap(dpy->drmFD, offset, size, (drmAddressPtr) &dpy->pSAREA);
644 if (rc < 0 ) {
645 _eglLog(_EGL_WARNING, "drmMap DRM_SHM failed.");
646 return EGL_FALSE;
647 }
648 dpy->SAREASize = SAREA_MAX;
649 _eglLog(_EGL_DEBUG, "mapped SAREA 0x%08lx to %p, size %d",
650 (unsigned long) offset, dpy->pSAREA, dpy->SAREASize );
651 }
652 }
653
654 if (!dpy->pFB) {
655 _eglLog(_EGL_WARNING, "failed to map framebuffer");
656 return EGL_FALSE;
657 }
658
659 if (!dpy->pSAREA) {
660 /* if this happens, make sure you're using the most recent DRM modules */
661 _eglLog(_EGL_WARNING, "failed to map SAREA");
662 return EGL_FALSE;
663 }
664
665 memset( dpy->pSAREA, 0, dpy->SAREASize );
666
667 return EGL_TRUE;
668 }
669
670
671 /* Return the DRI per screen structure */
672 static __DRIscreen *
673 __eglFindDRIScreen(__DRInativeDisplay *ndpy, int scrn)
674 {
675 driDisplay *disp = (driDisplay *)ndpy;
676 return &disp->driScreen;
677 }
678
679
680 static GLboolean
681 __eglCreateContextWithConfig(__DRInativeDisplay* ndpy, int screen,
682 int configID, void* context,
683 drm_context_t * hHWContext)
684 {
685 __DRIscreen *pDRIScreen;
686 __DRIscreenPrivate *psp;
687
688 pDRIScreen = __eglFindDRIScreen(ndpy, screen);
689 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
690 return GL_FALSE;
691 }
692 psp = (__DRIscreenPrivate *) pDRIScreen->private;
693 if (psp->fd) {
694 if (drmCreateContext(psp->fd, hHWContext)) {
695 _eglLog(_EGL_WARNING, "drmCreateContext failed.");
696 return GL_FALSE;
697 }
698 *(void**)context = (void*) *hHWContext;
699 }
700 #if 0
701 __DRIscreen *pDRIScreen;
702 __DRIscreenPrivate *psp;
703
704 pDRIScreen = __glXFindDRIScreen(dpy, screen);
705 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
706 return GL_FALSE;
707 }
708
709 psp = (__DRIscreenPrivate *) pDRIScreen->private;
710
711 if (psp->fd) {
712 if (drmCreateContext(psp->fd, hHWContext)) {
713 _eglLog(_EGL_WARNING, "drmCreateContext failed.");
714 return GL_FALSE;
715 }
716 *(void**)contextID = (void*) *hHWContext;
717 }
718 #endif
719 return GL_TRUE;
720 }
721
722
723 static GLboolean
724 __eglDestroyContext( __DRInativeDisplay * ndpy, int screen, __DRIid context )
725 {
726 __DRIscreen *pDRIScreen;
727 __DRIscreenPrivate *psp;
728
729 pDRIScreen = __eglFindDRIScreen(ndpy, screen);
730 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
731 return GL_FALSE;
732 }
733 psp = (__DRIscreenPrivate *) pDRIScreen->private;
734 if (psp->fd)
735 drmDestroyContext(psp->fd, context);
736
737 return GL_TRUE;
738 }
739
740
741 static GLboolean
742 __eglCreateDrawable(__DRInativeDisplay * ndpy, int screen,
743 __DRIid drawable, drm_drawable_t * hHWDrawable)
744 {
745 __DRIscreen *pDRIScreen;
746 __DRIscreenPrivate *psp;
747
748 pDRIScreen = __eglFindDRIScreen(ndpy, screen);
749 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
750 return GL_FALSE;
751 }
752 psp = (__DRIscreenPrivate *) pDRIScreen->private;
753 if (psp->fd) {
754 if (drmCreateDrawable(psp->fd, hHWDrawable)) {
755 _eglLog(_EGL_WARNING, "drmCreateDrawable failed.");
756 return GL_FALSE;
757 }
758 }
759 return GL_TRUE;
760 }
761
762
763 static GLboolean
764 __eglDestroyDrawable( __DRInativeDisplay * ndpy, int screen, __DRIid drawable )
765 {
766 __DRIscreen *pDRIScreen;
767 __DRIscreenPrivate *psp;
768
769 pDRIScreen = __eglFindDRIScreen(ndpy, screen);
770 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
771 return GL_FALSE;
772 }
773 psp = (__DRIscreenPrivate *) pDRIScreen->private;
774 if (psp->fd)
775 drmDestroyDrawable(psp->fd, drawable);
776
777 return GL_TRUE;
778 }
779
780 static GLboolean
781 __eglGetDrawableInfo(__DRInativeDisplay * ndpy, int screen, __DRIid drawable,
782 unsigned int* index, unsigned int* stamp,
783 int* X, int* Y, int* W, int* H,
784 int* numClipRects, drm_clip_rect_t ** pClipRects,
785 int* backX, int* backY,
786 int* numBackClipRects, drm_clip_rect_t ** pBackClipRects )
787 {
788 __DRIscreen *pDRIScreen;
789 __DRIscreenPrivate *psp;
790 driSurface *surf = Lookup_driSurface((EGLSurface) drawable);
791
792 pDRIScreen = __eglFindDRIScreen(ndpy, screen);
793
794 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
795 return GL_FALSE;
796 }
797 psp = (__DRIscreenPrivate *) pDRIScreen->private;
798 *X = 0;
799 *Y = 0;
800 *W = surf->Base.Width;
801 *H = surf->Base.Height;
802
803 *backX = 0;
804 *backY = 0;
805 *numBackClipRects = 0;
806 *pBackClipRects = NULL;
807
808 *numClipRects = 1;
809 *pClipRects = malloc(sizeof(**pClipRects));
810 **pClipRects = (drm_clip_rect_t){0, 0, surf->Base.Width, surf->Base.Height};
811
812 psp->pSAREA->drawableTable[0].stamp = 1;
813 *stamp = 1;
814 #if 0
815 GLXDrawable drawable = (GLXDrawable) draw;
816 drm_clip_rect_t * cliprect;
817 Display* display = (Display*)dpy;
818 __DRIcontextPrivate *pcp = (__DRIcontextPrivate *)CurrentContext->driContext.private;
819 if (drawable == 0) {
820 return GL_FALSE;
821 }
822
823 cliprect = (drm_clip_rect_t*) _mesa_malloc(sizeof(drm_clip_rect_t));
824 cliprect->x1 = drawable->x;
825 cliprect->y1 = drawable->y;
826 cliprect->x2 = drawable->x + drawable->w;
827 cliprect->y2 = drawable->y + drawable->h;
828
829 /* the drawable index is by client id */
830 *index = display->clientID;
831
832 *stamp = pcp->driScreenPriv->pSAREA->drawableTable[display->clientID].stamp;
833 *x = drawable->x;
834 *y = drawable->y;
835 *width = drawable->w;
836 *height = drawable->h;
837 *numClipRects = 1;
838 *pClipRects = cliprect;
839
840 *backX = drawable->x;
841 *backY = drawable->y;
842 *numBackClipRects = 0;
843 *pBackClipRects = 0;
844 #endif
845 return GL_TRUE;
846 }
847
848
849 /**
850 * Implement \c __DRIinterfaceMethods::getProcAddress.
851 */
852 static __DRIfuncPtr
853 get_proc_address(const char * proc_name)
854 {
855 return NULL;
856 }
857
858
859 /**
860 * Destroy a linked list of \c __GLcontextModes structures created by
861 * \c _gl_context_modes_create.
862 *
863 * \param modes Linked list of structures to be destroyed. All structres
864 * in the list will be freed.
865 */
866 static void
867 __egl_context_modes_destroy(__GLcontextModes *modes)
868 {
869 while ( modes != NULL ) {
870 __GLcontextModes * const next = modes->next;
871
872 free( modes );
873 modes = next;
874 }
875 }
876
877
878 /**
879 * Allocate a linked list of \c __GLcontextModes structures. The fields of
880 * each structure will be initialized to "reasonable" default values. In
881 * most cases this is the default value defined by table 3.4 of the GLX
882 * 1.3 specification. This means that most values are either initialized to
883 * zero or \c GLX_DONT_CARE (which is -1). As support for additional
884 * extensions is added, the new values will be initialized to appropriate
885 * values from the extension specification.
886 *
887 * \param count Number of structures to allocate.
888 * \param minimum_size Minimum size of a structure to allocate. This allows
889 * for differences in the version of the
890 * \c __GLcontextModes stucture used in libGL and in a
891 * DRI-based driver.
892 * \returns A pointer to the first element in a linked list of \c count
893 * stuctures on success, or \c NULL on failure.
894 *
895 * \warning Use of \c minimum_size does \b not guarantee binary compatibility.
896 * The fundamental assumption is that if the \c minimum_size
897 * specified by the driver and the size of the \c __GLcontextModes
898 * structure in libGL is the same, then the meaning of each byte in
899 * the structure is the same in both places. \b Be \b careful!
900 * Basically this means that fields have to be added in libGL and
901 * then propagated to drivers. Drivers should \b never arbitrarilly
902 * extend the \c __GLcontextModes data-structure.
903 */
904 static __GLcontextModes *
905 __egl_context_modes_create(unsigned count, size_t minimum_size)
906 {
907 const size_t size = (minimum_size > sizeof( __GLcontextModes ))
908 ? minimum_size : sizeof( __GLcontextModes );
909 __GLcontextModes * base = NULL;
910 __GLcontextModes ** next;
911 unsigned i;
912
913 next = & base;
914 for ( i = 0 ; i < count ; i++ ) {
915 *next = (__GLcontextModes *) malloc( size );
916 if ( *next == NULL ) {
917 __egl_context_modes_destroy( base );
918 base = NULL;
919 break;
920 }
921
922 (void) memset( *next, 0, size );
923 (*next)->visualID = GLX_DONT_CARE;
924 (*next)->visualType = GLX_DONT_CARE;
925 (*next)->visualRating = GLX_NONE;
926 (*next)->transparentPixel = GLX_NONE;
927 (*next)->transparentRed = GLX_DONT_CARE;
928 (*next)->transparentGreen = GLX_DONT_CARE;
929 (*next)->transparentBlue = GLX_DONT_CARE;
930 (*next)->transparentAlpha = GLX_DONT_CARE;
931 (*next)->transparentIndex = GLX_DONT_CARE;
932 (*next)->xRenderable = GLX_DONT_CARE;
933 (*next)->fbconfigID = GLX_DONT_CARE;
934 (*next)->swapMethod = GLX_SWAP_UNDEFINED_OML;
935
936 next = & ((*next)->next);
937 }
938
939 return base;
940 }
941
942
943 static GLboolean
944 __eglWindowExists(__DRInativeDisplay *dpy, __DRIid draw)
945 {
946 return EGL_TRUE;
947 }
948
949
950 /**
951 * Get the unadjusted system time (UST). Currently, the UST is measured in
952 * microseconds since Epoc. The actual resolution of the UST may vary from
953 * system to system, and the units may vary from release to release.
954 * Drivers should not call this function directly. They should instead use
955 * \c glXGetProcAddress to obtain a pointer to the function.
956 *
957 * \param ust Location to store the 64-bit UST
958 * \returns Zero on success or a negative errno value on failure.
959 *
960 * \sa glXGetProcAddress, PFNGLXGETUSTPROC
961 *
962 * \since Internal API version 20030317.
963 */
964 static int
965 __eglGetUST(int64_t *ust)
966 {
967 struct timeval tv;
968
969 if ( ust == NULL ) {
970 return -EFAULT;
971 }
972
973 if ( gettimeofday( & tv, NULL ) == 0 ) {
974 ust[0] = (tv.tv_sec * 1000000) + tv.tv_usec;
975 return 0;
976 }
977 else {
978 return -errno;
979 }
980 }
981
982 /**
983 * Determine the refresh rate of the specified drawable and display.
984 *
985 * \param dpy Display whose refresh rate is to be determined.
986 * \param drawable Drawable whose refresh rate is to be determined.
987 * \param numerator Numerator of the refresh rate.
988 * \param demoninator Denominator of the refresh rate.
989 * \return If the refresh rate for the specified display and drawable could
990 * be calculated, True is returned. Otherwise False is returned.
991 *
992 * \note This function is implemented entirely client-side. A lot of other
993 * functionality is required to export GLX_OML_sync_control, so on
994 * XFree86 this function can be called for direct-rendering contexts
995 * when GLX_OML_sync_control appears in the client extension string.
996 */
997 static GLboolean
998 __eglGetMSCRate(__DRInativeDisplay * dpy, __DRIid drawable,
999 int32_t * numerator, int32_t * denominator)
1000 {
1001 return EGL_TRUE;
1002 }
1003
1004
1005 /**
1006 * Table of functions exported by the loader to the driver.
1007 */
1008 static const __DRIinterfaceMethods interface_methods = {
1009 get_proc_address,
1010
1011 __egl_context_modes_create,
1012 __egl_context_modes_destroy,
1013
1014 __eglFindDRIScreen,
1015 __eglWindowExists,
1016
1017 __eglCreateContextWithConfig,
1018 __eglDestroyContext,
1019
1020 __eglCreateDrawable,
1021 __eglDestroyDrawable,
1022 __eglGetDrawableInfo,
1023
1024 __eglGetUST,
1025 __eglGetMSCRate,
1026 };
1027
1028
1029 static int
1030 __glXGetInternalVersion(void)
1031 {
1032 return 20050725;
1033 }
1034
1035 static const char createNewScreenName[] = "__driCreateNewScreen_20050727";
1036
1037
1038 /**
1039 * Do per-display initialization.
1040 */
1041 EGLBoolean
1042 _eglDRICreateDisplay(driDisplay *dpy, __DRIframebuffer *framebuffer)
1043 {
1044 PFNCREATENEWSCREENFUNC createNewScreen;
1045 int api_ver = __glXGetInternalVersion();
1046 __DRIversion ddx_version;
1047 __DRIversion dri_version;
1048 __DRIversion drm_version;
1049 drmVersionPtr version;
1050
1051 version = drmGetVersion( dpy->drmFD );
1052 if ( version ) {
1053 drm_version.major = version->version_major;
1054 drm_version.minor = version->version_minor;
1055 drm_version.patch = version->version_patchlevel;
1056 drmFreeVersion( version );
1057 }
1058 else {
1059 drm_version.major = -1;
1060 drm_version.minor = -1;
1061 drm_version.patch = -1;
1062 }
1063
1064 /*
1065 * Get device name (like "tdfx") and the ddx version numbers.
1066 * We'll check the version in each DRI driver's "createScreen"
1067 * function.
1068 */
1069 ddx_version.major = 4;
1070 ddx_version.minor = 0;
1071 ddx_version.patch = 0;
1072
1073 /*
1074 * Get the DRI X extension version.
1075 */
1076 dri_version.major = 4;
1077 dri_version.minor = 0;
1078 dri_version.patch = 0;
1079
1080 createNewScreen = ( PFNCREATENEWSCREENFUNC ) dlsym( dpy->Base.Driver->LibHandle, createNewScreenName );
1081 if ( !createNewScreen ) {
1082 _eglLog(_EGL_WARNING, "Couldn't find %s function in the driver.",
1083 createNewScreenName );
1084 return EGL_FALSE;
1085 }
1086
1087 dpy->driScreen.private = createNewScreen( dpy, 0, &dpy->driScreen, NULL,
1088 &ddx_version, &dri_version,
1089 &drm_version, framebuffer,
1090 dpy->pSAREA, dpy->drmFD,
1091 api_ver,
1092 & interface_methods,
1093 NULL);
1094 if (!dpy->driScreen.private) {
1095 _eglLog(_EGL_WARNING, "egldri.c: DRI create new screen failed");
1096 return EGL_FALSE;
1097 }
1098
1099 DRM_UNLOCK( dpy->drmFD, dpy->pSAREA, dpy->serverContext );
1100
1101 return EGL_TRUE;
1102 }
1103
1104
1105 /**
1106 * Create all the EGL screens for the given display.
1107 */
1108 EGLBoolean
1109 _eglDRICreateScreens(driDisplay *dpy)
1110 {
1111 const int numScreens = 1; /* XXX fix this someday */
1112 int i;
1113
1114 for (i = 0; i < numScreens; i++) {
1115 char path[ NAME_MAX ];
1116 FILE *file;
1117 driScreen *s;
1118
1119 /* Create a screen */
1120 if ( !( s = ( driScreen * ) calloc( 1, sizeof( *s ) ) ) )
1121 return EGL_FALSE;
1122
1123 snprintf( s->fb, NAME_MAX, "fb%d", dpy->minor );
1124 _eglInitScreen( &s->Base );
1125
1126 _eglAddScreen( &dpy->Base, &s->Base );
1127
1128 /* Create the screen's mode list */
1129 snprintf( path, sizeof( path ), "%s/graphics/%s/modes", sysfs, s->fb );
1130 file = fopen( path, "r" );
1131 while ( fgets( path, sizeof( path ), file ) ) {
1132 unsigned int x, y, r;
1133 char c;
1134 path[ strlen( path ) - 1 ] = '\0'; /* strip off \n from sysfs */
1135 sscanf( path, "%c:%ux%u-%u", &c, &x, &y, &r );
1136 _eglAddNewMode( &s->Base, x, y, r * 1000, path );
1137 }
1138 fclose( file );
1139
1140 /*
1141 * NOTE: we used to set the colormap here, but that didn't work reliably.
1142 * Some entries near the start of the table would get corrupted by later
1143 * mode changes.
1144 */
1145 }
1146
1147 return EGL_TRUE;
1148 }
1149
1150
1151 EGLBoolean
1152 _eglDRIInitialize(_EGLDriver *drv, EGLDisplay dpy,
1153 EGLint *major, EGLint *minor)
1154 {
1155 _EGLDisplay *disp = _eglLookupDisplay(dpy);
1156 driDisplay *display;
1157 const char *driverName = (const char *) disp->NativeDisplay;
1158
1159 assert(disp);
1160
1161 /* Create new driDisplay object to replace the _EGLDisplay that was
1162 * previously created.
1163 */
1164 display = calloc(1, sizeof(*display));
1165 display->Base = *disp;
1166 _eglSaveDisplay(&display->Base);
1167 free(disp);
1168
1169 *major = 1;
1170 *minor = 0;
1171
1172 sscanf(driverName + 1, "%d", &display->minor);
1173
1174 drv->Initialized = EGL_TRUE;
1175 return EGL_TRUE;
1176 }
1177
1178
1179 static EGLBoolean
1180 _eglDRITerminate(_EGLDriver *drv, EGLDisplay dpy)
1181 {
1182 driDisplay *display = Lookup_driDisplay(dpy);
1183 _eglCleanupDisplay(&display->Base);/*rename that function*/
1184 free(display);
1185 free(drv);
1186 return EGL_TRUE;
1187 }
1188
1189
1190 /**
1191 * Plug in the DRI-specific functions into the driver's dispatch table.
1192 * Also, enable some EGL extensions.
1193 */
1194 void
1195 _eglDRIInitDriverFallbacks(_EGLDriver *drv)
1196 {
1197 _eglInitDriverFallbacks(drv);
1198
1199 drv->API.Initialize = _eglDRIInitialize;
1200 drv->API.Terminate = _eglDRITerminate;
1201 drv->API.CreateContext = _eglDRICreateContext;
1202 drv->API.MakeCurrent = _eglDRIMakeCurrent;
1203 drv->API.CreatePbufferSurface = _eglDRICreatePbufferSurface;
1204 drv->API.DestroySurface = _eglDRIDestroySurface;
1205 drv->API.DestroyContext = _eglDRIDestroyContext;
1206 drv->API.CreateScreenSurfaceMESA = _eglDRICreateScreenSurfaceMESA;
1207 drv->API.ShowScreenSurfaceMESA = _eglDRIShowScreenSurfaceMESA;
1208 drv->API.SwapBuffers = _eglDRISwapBuffers;
1209
1210 /* enable supported extensions */
1211 drv->Extensions.MESA_screen_surface = EGL_TRUE;
1212 drv->Extensions.MESA_copy_context = EGL_TRUE;
1213 }