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