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