egl: added args string to _eglMain()
[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 char *displayString = (const char *) dpy->NativeDisplay;
86 const int card = atoi(args);
87 _EGLDriver *driver = NULL;
88 char driverName[1000];
89
90 if (!driver_name_from_card_number(card, driverName, sizeof(driverName))) {
91 _eglLog(_EGL_WARNING,
92 "Unable to determine driver name for card %d\n", card);
93 return NULL;
94 }
95
96 _eglLog(_EGL_DEBUG, "Driver name: %s\n", driverName);
97
98 driver = _eglOpenDriver(dpy, driverName);
99
100 return driver;
101
102 #else
103
104 int length;
105 char path[NAME_MAX];
106 struct dirent *dirent;
107 #if 1
108 FILE *file;
109 #endif
110 DIR *dir;
111 _EGLDriver *driver = NULL;;
112
113 snprintf(path, sizeof(path), "%s/drm", sysfs);
114 if (!(dir = opendir(path))) {
115 _eglLog(_EGL_WARNING, "%s DRM devices not found.", path);
116 return EGL_FALSE;
117 }
118 while ((dirent = readdir(dir))) {
119
120 if (strncmp(&dirent->d_name[0], "card", 4) != 0)
121 continue;
122 if (strcmp(&dirent->d_name[4], &driverName[1]) != 0)
123 continue;
124
125 snprintf(path, sizeof(path), "%s/drm/card%s/dri_library_name",
126 sysfs, &driverName[1]);
127 _eglLog(_EGL_INFO, "Opening %s", path);
128 #if 1
129 file = fopen(path, "r");
130 if (!file) {
131 _eglLog(_EGL_WARNING, "Failed to open %s", path);
132 return NULL;
133 }
134 fgets(path, sizeof(path), file);
135 fclose(file);
136 #else
137 strcpy(path, "r200\n");
138 #endif
139 if ((length = strlen(path)) > 0)
140 path[length - 1] = '\0'; /* remove the trailing newline from sysfs */
141 strncat(path, "_dri", sizeof(path));
142
143 driver = _eglOpenDriver(dpy, path);
144
145 break;
146 }
147 closedir(dir);
148
149 return driver;
150 #endif
151 }
152
153
154 /**
155 * Called by eglCreateContext via drv->API.CreateContext().
156 */
157 static EGLContext
158 _eglDRICreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
159 EGLContext share_list, const EGLint *attrib_list)
160 {
161 driDisplay *disp = Lookup_driDisplay(dpy);
162 driContext *c, *share;
163 void *sharePriv;
164 _EGLConfig *conf;
165 __GLcontextModes visMode;
166
167 c = (driContext *) calloc(1, sizeof(*c));
168 if (!c)
169 return EGL_NO_CONTEXT;
170
171 if (!_eglInitContext(drv, dpy, &c->Base, config, attrib_list)) {
172 free(c);
173 return EGL_NO_CONTEXT;
174 }
175
176 if (share_list != EGL_NO_CONTEXT) {
177 _EGLContext *shareCtx = _eglLookupContext(share_list);
178 if (!shareCtx) {
179 _eglError(EGL_BAD_CONTEXT, "eglCreateContext(share_list)");
180 return EGL_FALSE;
181 }
182 }
183 share = Lookup_driContext(share_list);
184 if (share)
185 sharePriv = share->driContext.private;
186 else
187 sharePriv = NULL;
188
189 conf = _eglLookupConfig(drv, dpy, config);
190 assert(conf);
191 _eglConfigToContextModesRec(conf, &visMode);
192
193 c->driContext.private = disp->driScreen.createNewContext(disp, &visMode,
194 GLX_WINDOW_BIT, sharePriv, &c->driContext);
195 if (!c->driContext.private) {
196 free(c);
197 return EGL_FALSE;
198 }
199
200 /* generate handle and insert into hash table */
201 _eglSaveContext(&c->Base);
202
203 return _eglGetContextHandle(&c->Base);
204 }
205
206
207 static EGLBoolean
208 _eglDRIMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw,
209 EGLSurface read, EGLContext context)
210 {
211 driDisplay *disp = Lookup_driDisplay(dpy);
212 driContext *ctx = Lookup_driContext(context);
213 EGLBoolean b;
214 __DRIid drawBuf = (__DRIid) draw;
215 __DRIid readBuf = (__DRIid) read;
216
217 b = _eglMakeCurrent(drv, dpy, draw, read, context);
218 if (!b)
219 return EGL_FALSE;
220
221 if (ctx) {
222 ctx->driContext.bindContext(disp, 0, drawBuf, readBuf, &ctx->driContext);
223 }
224 else {
225 /* what's this??? */
226 /* _mesa_make_current( NULL, NULL, NULL );*/
227 }
228 return EGL_TRUE;
229 }
230
231
232 static EGLSurface
233 _eglDRICreatePbufferSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
234 const EGLint *attrib_list)
235 {
236 driSurface *surf;
237
238 surf = (driSurface *) calloc(1, sizeof(*surf));
239 if (!surf) {
240 return EGL_NO_SURFACE;
241 }
242
243 if (!_eglInitSurface(drv, dpy, &surf->Base, EGL_PBUFFER_BIT,
244 config, attrib_list)) {
245 free(surf);
246 return EGL_NO_SURFACE;
247 }
248
249 /* create software-based pbuffer */
250 {
251 #if 0
252 GLcontext *ctx = NULL; /* this _should_ be OK */
253 #endif
254 __GLcontextModes visMode;
255 _EGLConfig *conf = _eglLookupConfig(drv, dpy, config);
256 assert(conf); /* bad config should be caught earlier */
257 _eglConfigToContextModesRec(conf, &visMode);
258
259 #if 0
260 surf->mesa_framebuffer = _mesa_create_framebuffer(&visMode);
261 _mesa_add_soft_renderbuffers(surf->mesa_framebuffer,
262 GL_TRUE, /* color bufs */
263 visMode.haveDepthBuffer,
264 visMode.haveStencilBuffer,
265 visMode.haveAccumBuffer,
266 GL_FALSE, /* alpha */
267 GL_FALSE /* aux */ );
268
269 /* set pbuffer/framebuffer size */
270 _mesa_resize_framebuffer(ctx, surf->mesa_framebuffer,
271 surf->Base.Width, surf->Base.Height);
272 #endif
273 }
274
275 _eglSaveSurface(&surf->Base);
276
277 return surf->Base.Handle;
278 }
279
280
281 static EGLBoolean
282 _eglDRIDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
283 {
284 driDisplay *disp = Lookup_driDisplay(dpy);
285 driSurface *fs = Lookup_driSurface(surface);
286
287 _eglRemoveSurface(&fs->Base);
288
289 fs->drawable.destroyDrawable(disp, fs->drawable.private);
290
291 if (fs->Base.IsBound) {
292 fs->Base.DeletePending = EGL_TRUE;
293 }
294 else {
295 free(fs);
296 }
297 return EGL_TRUE;
298 }
299
300
301 static EGLBoolean
302 _eglDRIDestroyContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext context)
303 {
304 driDisplay *disp = Lookup_driDisplay(dpy);
305 driContext *fc = Lookup_driContext(context);
306
307 _eglRemoveContext(&fc->Base);
308
309 fc->driContext.destroyContext(disp, 0, fc->driContext.private);
310
311 if (fc->Base.IsBound) {
312 fc->Base.DeletePending = EGL_TRUE;
313 }
314 else {
315 free(fc);
316 }
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, dpy, &surface->Base, EGL_SCREEN_BIT_MESA,
341 cfg, attrib_list)) {
342 free(surface);
343 return EGL_NO_SURFACE;
344 }
345
346 _eglSaveSurface(&surface->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 _eglRemoveSurface(&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 __DRIscreenPrivate *psp;
679
680 pDRIScreen = __eglFindDRIScreen(ndpy, screen);
681 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
682 return GL_FALSE;
683 }
684 psp = (__DRIscreenPrivate *) 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 __DRIscreenPrivate *psp;
695
696 pDRIScreen = __glXFindDRIScreen(dpy, screen);
697 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
698 return GL_FALSE;
699 }
700
701 psp = (__DRIscreenPrivate *) 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 __DRIscreenPrivate *psp;
720
721 pDRIScreen = __eglFindDRIScreen(ndpy, screen);
722 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
723 return GL_FALSE;
724 }
725 psp = (__DRIscreenPrivate *) 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 __DRIscreenPrivate *psp;
739
740 pDRIScreen = __eglFindDRIScreen(ndpy, screen);
741 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
742 return GL_FALSE;
743 }
744 psp = (__DRIscreenPrivate *) 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 __DRIscreenPrivate *psp;
760
761 pDRIScreen = __eglFindDRIScreen(ndpy, screen);
762 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
763 return GL_FALSE;
764 }
765 psp = (__DRIscreenPrivate *) 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 __DRIscreenPrivate *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 = (__DRIscreenPrivate *) 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 __DRIcontextPrivate *pcp = (__DRIcontextPrivate *)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 return EGL_FALSE;
1088
1089 DRM_UNLOCK( dpy->drmFD, dpy->pSAREA, dpy->serverContext );
1090
1091 return EGL_TRUE;
1092 }
1093
1094
1095 /**
1096 * Create all the EGL screens for the given display.
1097 */
1098 EGLBoolean
1099 _eglDRICreateScreens(driDisplay *dpy)
1100 {
1101 const int numScreens = 1; /* XXX fix this someday */
1102 int i;
1103
1104 for (i = 0; i < numScreens; i++) {
1105 char path[ NAME_MAX ];
1106 FILE *file;
1107 driScreen *s;
1108
1109 /* Create a screen */
1110 if ( !( s = ( driScreen * ) calloc( 1, sizeof( *s ) ) ) )
1111 return EGL_FALSE;
1112
1113 snprintf( s->fb, NAME_MAX, "fb%d", dpy->minor );
1114 _eglInitScreen( &s->Base );
1115
1116 _eglAddScreen( &dpy->Base, &s->Base );
1117
1118 /* Create the screen's mode list */
1119 snprintf( path, sizeof( path ), "%s/graphics/%s/modes", sysfs, s->fb );
1120 file = fopen( path, "r" );
1121 while ( fgets( path, sizeof( path ), file ) ) {
1122 unsigned int x, y, r;
1123 char c;
1124 path[ strlen( path ) - 1 ] = '\0'; /* strip off \n from sysfs */
1125 sscanf( path, "%c:%ux%u-%u", &c, &x, &y, &r );
1126 _eglAddNewMode( &s->Base, x, y, r * 1000, path );
1127 }
1128 fclose( file );
1129
1130 /*
1131 * NOTE: we used to set the colormap here, but that didn't work reliably.
1132 * Some entries near the start of the table would get corrupted by later
1133 * mode changes.
1134 */
1135 }
1136
1137 return EGL_TRUE;
1138 }
1139
1140
1141 EGLBoolean
1142 _eglDRIInitialize(_EGLDriver *drv, EGLDisplay dpy,
1143 EGLint *major, EGLint *minor)
1144 {
1145 _EGLDisplay *disp = _eglLookupDisplay(dpy);
1146 driDisplay *display;
1147 const char *driverName = (const char *) disp->NativeDisplay;
1148
1149 assert(disp);
1150
1151 /* Create new driDisplay object to replace the _EGLDisplay that was
1152 * previously created.
1153 */
1154 display = calloc(1, sizeof(*display));
1155 display->Base = *disp;
1156 _eglSaveDisplay(&display->Base);
1157 free(disp);
1158
1159 *major = 1;
1160 *minor = 0;
1161
1162 sscanf(driverName + 1, "%d", &display->minor);
1163
1164 drv->Initialized = EGL_TRUE;
1165 return EGL_TRUE;
1166 }
1167
1168
1169 static EGLBoolean
1170 _eglDRITerminate(_EGLDriver *drv, EGLDisplay dpy)
1171 {
1172 driDisplay *display = Lookup_driDisplay(dpy);
1173 _eglCleanupDisplay(&display->Base);/*rename that function*/
1174 free(display);
1175 free(drv);
1176 return EGL_TRUE;
1177 }
1178
1179
1180 /**
1181 * Plug in the DRI-specific functions into the driver's dispatch table.
1182 * Also, enable some EGL extensions.
1183 */
1184 void
1185 _eglDRIInitDriverFallbacks(_EGLDriver *drv)
1186 {
1187 _eglInitDriverFallbacks(drv);
1188
1189 drv->API.Initialize = _eglDRIInitialize;
1190 drv->API.Terminate = _eglDRITerminate;
1191 drv->API.CreateContext = _eglDRICreateContext;
1192 drv->API.MakeCurrent = _eglDRIMakeCurrent;
1193 drv->API.CreatePbufferSurface = _eglDRICreatePbufferSurface;
1194 drv->API.DestroySurface = _eglDRIDestroySurface;
1195 drv->API.DestroyContext = _eglDRIDestroyContext;
1196 drv->API.CreateScreenSurfaceMESA = _eglDRICreateScreenSurfaceMESA;
1197 drv->API.ShowScreenSurfaceMESA = _eglDRIShowScreenSurfaceMESA;
1198 drv->API.SwapBuffers = _eglDRISwapBuffers;
1199
1200 /* enable supported extensions */
1201 drv->Extensions.MESA_screen_surface = EGL_TRUE;
1202 drv->Extensions.MESA_copy_context = EGL_TRUE;
1203 }