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