55f4d92afb30c3d2ef72232a5f54bd234a627ef0
[mesa.git] / src / gallium / winsys / egl_drm / intel / intel_egl.c
1
2 #include <assert.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <stdio.h>
6 #include <stdint.h>
7
8 #include "eglconfig.h"
9 #include "eglcontext.h"
10 #include "egldisplay.h"
11 #include "egldriver.h"
12 #include "eglglobals.h"
13 #include "eglmode.h"
14 #include "eglscreen.h"
15 #include "eglsurface.h"
16 #include "egllog.h"
17
18 #include "intel_egl.h"
19
20 #include "xf86drm.h"
21 #include "xf86drmMode.h"
22
23 #include "intel_context.h"
24
25 #include "state_tracker/st_public.h"
26
27 #define MAX_SCREENS 16
28
29 static void
30 drm_get_device_id(struct egl_drm_device *device)
31 {
32 char path[512];
33 FILE *file;
34
35 /* TODO get the real minor */
36 int minor = 0;
37
38 snprintf(path, sizeof(path), "/sys/class/drm/card%d/device/device", minor);
39 file = fopen(path, "r");
40 if (!file) {
41 _eglLog(_EGL_WARNING, "Could not retrive device ID\n");
42 return;
43 }
44
45 fgets(path, sizeof( path ), file);
46 sscanf(path, "%x", &device->deviceID);
47 fclose(file);
48 }
49
50 static struct egl_drm_device*
51 egl_drm_create_device(int drmFD)
52 {
53 struct egl_drm_device *device = malloc(sizeof(*device));
54 memset(device, 0, sizeof(*device));
55 device->drmFD = drmFD;
56
57 device->version = drmGetVersion(device->drmFD);
58
59 drm_get_device_id(device);
60
61 if (!intel_create_device(device)) {
62 free(device);
63 return NULL;
64 }
65
66 return device;
67 }
68
69 __GLcontextModes* _gl_context_modes_create( unsigned count, size_t minimum_size );
70
71 struct drm_screen;
72
73 struct drm_driver
74 {
75 _EGLDriver base; /* base class/object */
76
77 drmModeResPtr res;
78
79 struct drm_screen *screens[MAX_SCREENS];
80 size_t count_screens;
81
82 struct egl_drm_device *device;
83 };
84
85 struct drm_surface
86 {
87 _EGLSurface base; /* base class/object */
88
89 struct egl_drm_drawable *drawable;
90 };
91
92 struct drm_context
93 {
94 _EGLContext base; /* base class/object */
95
96 struct egl_drm_context *context;
97 };
98
99 struct drm_screen
100 {
101 _EGLScreen base;
102
103 /* currently only support one connector */
104 drmModeConnectorPtr connector;
105 uint32_t connectorID;
106
107 /* Has this screen been shown */
108 int shown;
109
110 /* Surface that is currently attached to this screen */
111 struct drm_surface *surf;
112
113 /* backing buffer */
114 drmBO buffer;
115
116 /* framebuffer */
117 drmModeFBPtr fb;
118 uint32_t fbID;
119
120 /* crtc and mode used */
121 drmModeCrtcPtr crtc;
122 uint32_t crtcID;
123
124 struct drm_mode_modeinfo *mode;
125
126 /* geometry of the screen */
127 struct egl_drm_frontbuffer front;
128 };
129
130 static void
131 drm_update_res(struct drm_driver *drm_drv)
132 {
133 drmModeFreeResources(drm_drv->res);
134 drm_drv->res = drmModeGetResources(drm_drv->device->drmFD);
135 }
136
137 static void
138 drm_add_modes_from_connector(_EGLScreen *screen, drmModeConnectorPtr connector)
139 {
140 struct drm_mode_modeinfo *m;
141 int i;
142
143 for (i = 0; i < connector->count_modes; i++) {
144 m = &connector->modes[i];
145 _eglAddNewMode(screen, m->hdisplay, m->vdisplay, m->vrefresh, m->name);
146 }
147 }
148
149
150 static EGLBoolean
151 drm_initialize(_EGLDriver *drv, EGLDisplay dpy, EGLint *major, EGLint *minor)
152 {
153 _EGLDisplay *disp = _eglLookupDisplay(dpy);
154 struct drm_driver *drm_drv = (struct drm_driver *)drv;
155 struct drm_screen *screen = NULL;
156 drmModeConnectorPtr connector = NULL;
157 drmModeResPtr res = NULL;
158 unsigned count_connectors = 0;
159 int num_screens = 0;
160
161 EGLint i;
162 int fd;
163
164 fd = drmOpen("i915", NULL);
165 if (fd < 0) {
166 return EGL_FALSE;
167 }
168
169 drm_drv->device = egl_drm_create_device(fd);
170 if (!drm_drv->device) {
171 drmClose(fd);
172 return EGL_FALSE;
173 }
174
175 drm_update_res(drm_drv);
176 res = drm_drv->res;
177 if (res)
178 count_connectors = res->count_connectors;
179
180 for(i = 0; i < count_connectors && i < MAX_SCREENS; i++) {
181 connector = drmModeGetConnector(fd, res->connectors[i]);
182
183 if (!connector)
184 continue;
185
186 if (connector->connection != DRM_MODE_CONNECTED) {
187 drmModeFreeConnector(connector);
188 continue;
189 }
190
191 screen = malloc(sizeof(struct drm_screen));
192 memset(screen, 0, sizeof(*screen));
193 screen->connectorID = res->connectors[i];
194 screen->connector = connector;
195 _eglInitScreen(&screen->base);
196 _eglAddScreen(disp, &screen->base);
197 drm_add_modes_from_connector(&screen->base, connector);
198 drm_drv->screens[num_screens++] = screen;
199 }
200 drm_drv->count_screens = num_screens;
201
202 /* for now we only have one config */
203 _EGLConfig *config = calloc(1, sizeof(*config));
204 memset(config, 1, sizeof(*config));
205 _eglInitConfig(config, 1);
206 _eglSetConfigAttrib(config, EGL_RED_SIZE, 8);
207 _eglSetConfigAttrib(config, EGL_GREEN_SIZE, 8);
208 _eglSetConfigAttrib(config, EGL_BLUE_SIZE, 8);
209 _eglSetConfigAttrib(config, EGL_ALPHA_SIZE, 8);
210 _eglSetConfigAttrib(config, EGL_BUFFER_SIZE, 32);
211 _eglSetConfigAttrib(config, EGL_DEPTH_SIZE, 24);
212 _eglSetConfigAttrib(config, EGL_STENCIL_SIZE, 8);
213 _eglSetConfigAttrib(config, EGL_SURFACE_TYPE, EGL_PBUFFER_BIT);
214 _eglAddConfig(disp, config);
215
216 drv->Initialized = EGL_TRUE;
217
218 *major = 1;
219 *minor = 4;
220
221 return EGL_TRUE;
222 }
223
224 static void
225 drm_takedown_shown_screen(_EGLDriver *drv, struct drm_screen *screen)
226 {
227 struct drm_driver *drm_drv = (struct drm_driver *)drv;
228
229 intel_bind_frontbuffer(screen->surf->drawable, NULL);
230 screen->surf = NULL;
231
232 drmModeSetCrtc(
233 drm_drv->device->drmFD,
234 drm_drv->res->crtcs[1],
235 0, // FD
236 0, 0,
237 NULL, 0, // List of output ids
238 NULL);
239
240 drmModeRmFB(drm_drv->device->drmFD, screen->fbID);
241 drmModeFreeFB(screen->fb);
242 screen->fb = NULL;
243
244 drmBOUnreference(drm_drv->device->drmFD, &screen->buffer);
245
246 screen->shown = 0;
247 }
248
249 static EGLBoolean
250 drm_terminate(_EGLDriver *drv, EGLDisplay dpy)
251 {
252 struct drm_driver *drm_drv = (struct drm_driver *)drv;
253 struct drm_screen *screen;
254 int i = 0;
255
256 intel_destroy_device(drm_drv->device);
257 drmFreeVersion(drm_drv->device->version);
258
259 for (i = 0; i < drm_drv->count_screens; i++) {
260 screen = drm_drv->screens[i];
261
262 if (screen->shown)
263 drm_takedown_shown_screen(drv, screen);
264
265 drmModeFreeConnector(screen->connector);
266 _eglDestroyScreen(&screen->base);
267 drm_drv->screens[i] = NULL;
268 }
269
270 drmClose(drm_drv->device->drmFD);
271
272 free(drm_drv->device);
273
274 _eglCleanupDisplay(_eglLookupDisplay(dpy));
275 free(drm_drv);
276
277 return EGL_TRUE;
278 }
279
280
281 static struct drm_context *
282 lookup_drm_context(EGLContext context)
283 {
284 _EGLContext *c = _eglLookupContext(context);
285 return (struct drm_context *) c;
286 }
287
288
289 static struct drm_surface *
290 lookup_drm_surface(EGLSurface surface)
291 {
292 _EGLSurface *s = _eglLookupSurface(surface);
293 return (struct drm_surface *) s;
294 }
295
296 static struct drm_screen *
297 lookup_drm_screen(EGLDisplay dpy, EGLScreenMESA screen)
298 {
299 _EGLScreen *s = _eglLookupScreen(dpy, screen);
300 return (struct drm_screen *) s;
301 }
302
303 static __GLcontextModes*
304 visual_from_config(_EGLConfig *conf)
305 {
306 __GLcontextModes *visual;
307 (void)conf;
308
309 visual = _gl_context_modes_create(1, sizeof(*visual));
310 visual->redBits = 8;
311 visual->greenBits = 8;
312 visual->blueBits = 8;
313 visual->alphaBits = 8;
314
315 visual->rgbBits = 32;
316 visual->doubleBufferMode = 1;
317
318 visual->depthBits = 24;
319 visual->haveDepthBuffer = visual->depthBits > 0;
320 visual->stencilBits = 8;
321 visual->haveStencilBuffer = visual->stencilBits > 0;
322
323 return visual;
324 }
325
326
327
328 static EGLContext
329 drm_create_context(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list)
330 {
331 struct drm_driver *drm_drv = (struct drm_driver *)drv;
332 struct drm_context *c;
333 struct drm_egl_context *share = NULL;
334 _EGLConfig *conf;
335 int i;
336 int ret;
337 __GLcontextModes *visual;
338 struct egl_drm_context *context;
339
340 conf = _eglLookupConfig(drv, dpy, config);
341 if (!conf) {
342 _eglError(EGL_BAD_CONFIG, "eglCreateContext");
343 return EGL_NO_CONTEXT;
344 }
345
346 for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
347 switch (attrib_list[i]) {
348 /* no attribs defined for now */
349 default:
350 _eglError(EGL_BAD_ATTRIBUTE, "eglCreateContext");
351 return EGL_NO_CONTEXT;
352 }
353 }
354
355 c = (struct drm_context *) calloc(1, sizeof(struct drm_context));
356 if (!c)
357 return EGL_NO_CONTEXT;
358
359 _eglInitContext(drv, dpy, &c->base, config, attrib_list);
360
361 context = malloc(sizeof(*context));
362 memset(context, 0, sizeof(*context));
363
364 if (!context)
365 goto err_c;
366
367 context->device = drm_drv->device;
368 visual = visual_from_config(conf);
369
370 ret = intel_create_context(context, visual, share);
371 free(visual);
372
373 if (!ret)
374 goto err_gl;
375
376 c->context = context;
377
378 /* generate handle and insert into hash table */
379 _eglSaveContext(&c->base);
380 assert(_eglGetContextHandle(&c->base));
381
382 return _eglGetContextHandle(&c->base);
383 err_gl:
384 free(context);
385 err_c:
386 free(c);
387 return EGL_NO_CONTEXT;
388 }
389
390 static EGLBoolean
391 drm_destroy_context(_EGLDriver *drv, EGLDisplay dpy, EGLContext context)
392 {
393 struct drm_context *fc = lookup_drm_context(context);
394 _eglRemoveContext(&fc->base);
395 if (fc->base.IsBound) {
396 fc->base.DeletePending = EGL_TRUE;
397 } else {
398 intel_destroy_context(fc->context);
399 free(fc->context);
400 free(fc);
401 }
402 return EGL_TRUE;
403 }
404
405
406 static EGLSurface
407 drm_create_window_surface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list)
408 {
409 return EGL_NO_SURFACE;
410 }
411
412
413 static EGLSurface
414 drm_create_pixmap_surface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, NativePixmapType pixmap, const EGLint *attrib_list)
415 {
416 return EGL_NO_SURFACE;
417 }
418
419
420 static EGLSurface
421 drm_create_pbuffer_surface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
422 const EGLint *attrib_list)
423 {
424 struct drm_driver *drm_drv = (struct drm_driver *)drv;
425 int i;
426 int ret;
427 int width = -1;
428 int height = -1;
429 struct drm_surface *surf = NULL;
430 struct egl_drm_drawable *drawable = NULL;
431 __GLcontextModes *visual;
432 _EGLConfig *conf;
433
434 conf = _eglLookupConfig(drv, dpy, config);
435 if (!conf) {
436 _eglError(EGL_BAD_CONFIG, "eglCreatePbufferSurface");
437 return EGL_NO_CONTEXT;
438 }
439
440 for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
441 switch (attrib_list[i]) {
442 case EGL_WIDTH:
443 width = attrib_list[++i];
444 break;
445 case EGL_HEIGHT:
446 height = attrib_list[++i];
447 break;
448 default:
449 _eglError(EGL_BAD_ATTRIBUTE, "eglCreatePbufferSurface");
450 return EGL_NO_SURFACE;
451 }
452 }
453
454 if (width < 1 || height < 1) {
455 _eglError(EGL_BAD_ATTRIBUTE, "eglCreatePbufferSurface");
456 return EGL_NO_SURFACE;
457 }
458
459 surf = (struct drm_surface *) calloc(1, sizeof(struct drm_surface));
460 if (!surf)
461 goto err;
462
463 if (!_eglInitSurface(drv, dpy, &surf->base, EGL_PBUFFER_BIT, config, attrib_list))
464 goto err_surf;
465
466 drawable = malloc(sizeof(*drawable));
467 memset(drawable, 0, sizeof(*drawable));
468
469 drawable->w = width;
470 drawable->h = height;
471
472 visual = visual_from_config(conf);
473
474 drawable->device = drm_drv->device;
475 ret = intel_create_drawable(drawable, visual);
476 free(visual);
477
478 if (!ret)
479 goto err_draw;
480
481 surf->drawable = drawable;
482
483 _eglSaveSurface(&surf->base);
484 return surf->base.Handle;
485
486 err_draw:
487 free(drawable);
488 err_surf:
489 free(surf);
490 err:
491 return EGL_NO_SURFACE;
492 }
493
494 static EGLSurface
495 drm_create_screen_surface_mesa(_EGLDriver *drv, EGLDisplay dpy, EGLConfig cfg,
496 const EGLint *attrib_list)
497 {
498 EGLSurface surf = drm_create_pbuffer_surface(drv, dpy, cfg, attrib_list);
499
500 return surf;
501 }
502
503 static struct drm_mode_modeinfo *
504 drm_find_mode(drmModeConnectorPtr connector, _EGLMode *mode)
505 {
506 int i;
507 struct drm_mode_modeinfo *m;
508
509 for (i = 0; i < connector->count_modes; i++) {
510 m = &connector->modes[i];
511 if (m->hdisplay == mode->Width && m->vdisplay == mode->Height && m->vrefresh == mode->RefreshRate)
512 break;
513 m = NULL;
514 }
515
516 return m;
517 }
518 static void
519 draw(size_t x, size_t y, size_t w, size_t h, size_t pitch, size_t v, unsigned int *ptr)
520 {
521 int i, j;
522
523 for (i = x; i < x + w; i++)
524 for(j = y; j < y + h; j++)
525 ptr[(i * pitch / 4) + j] = v;
526
527 }
528
529 static void
530 prettyColors(int fd, unsigned int handle, size_t pitch)
531 {
532 drmBO bo;
533 unsigned int *ptr;
534 void *p;
535 int i;
536
537 drmBOReference(fd, handle, &bo);
538 drmBOMap(fd, &bo, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, &p);
539 ptr = (unsigned int*)p;
540
541 for (i = 0; i < (bo.size / 4); i++)
542 ptr[i] = 0xFFFFFFFF;
543
544 for (i = 0; i < 4; i++)
545 draw(i * 40, i * 40, 40, 40, pitch, 0, ptr);
546
547
548 draw(200, 100, 40, 40, pitch, 0xff00ff, ptr);
549 draw(100, 200, 40, 40, pitch, 0xff00ff, ptr);
550
551 drmBOUnmap(fd, &bo);
552 }
553
554 static EGLBoolean
555 drm_show_screen_surface_mesa(_EGLDriver *drv, EGLDisplay dpy,
556 EGLScreenMESA screen,
557 EGLSurface surface, EGLModeMESA m)
558 {
559 struct drm_driver *drm_drv = (struct drm_driver *)drv;
560 struct drm_surface *surf = lookup_drm_surface(surface);
561 struct drm_screen *scrn = lookup_drm_screen(dpy, screen);
562 _EGLMode *mode = _eglLookupMode(dpy, m);
563 size_t pitch = 2048 * 4;
564 size_t size = mode->Height * pitch;
565 int ret;
566
567 if (scrn->shown)
568 drm_takedown_shown_screen(drv, scrn);
569
570 ret = drmBOCreate(drm_drv->device->drmFD, size, 0, 0,
571 DRM_BO_FLAG_READ |
572 DRM_BO_FLAG_WRITE |
573 DRM_BO_FLAG_MEM_TT |
574 DRM_BO_FLAG_MEM_VRAM |
575 DRM_BO_FLAG_NO_EVICT,
576 DRM_BO_HINT_DONT_FENCE, &scrn->buffer);
577
578 if (ret)
579 return EGL_FALSE;
580
581 prettyColors(drm_drv->device->drmFD, scrn->buffer.handle, pitch);
582
583 ret = drmModeAddFB(drm_drv->device->drmFD, mode->Width, mode->Height,
584 32, 32, pitch,
585 scrn->buffer.handle,
586 &scrn->fbID);
587
588 if (ret)
589 goto err_bo;
590
591 scrn->fb = drmModeGetFB(drm_drv->device->drmFD, scrn->fbID);
592 if (!scrn->fb)
593 goto err_bo;
594
595 scrn->mode = drm_find_mode(scrn->connector, mode);
596 if (!scrn->mode)
597 goto err_fb;
598
599 ret = drmModeSetCrtc(
600 drm_drv->device->drmFD,
601 drm_drv->res->crtcs[1],
602 scrn->fbID,
603 0, 0,
604 &scrn->connectorID, 1,
605 scrn->mode);
606
607
608 scrn->front.handle = scrn->buffer.handle;
609 scrn->front.pitch = pitch;
610 scrn->front.width = mode->Width;
611 scrn->front.height = mode->Height;
612
613 scrn->surf = surf;
614 intel_bind_frontbuffer(surf->drawable, &scrn->front);
615
616 scrn->shown = 1;
617
618 return EGL_TRUE;
619
620 err_fb:
621 /* TODO remove fb */
622
623 err_bo:
624 drmBOUnreference(drm_drv->device->drmFD, &scrn->buffer);
625 return EGL_FALSE;
626 }
627
628 static EGLBoolean
629 drm_destroy_surface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
630 {
631 struct drm_surface *fs = lookup_drm_surface(surface);
632 _eglRemoveSurface(&fs->base);
633 if (fs->base.IsBound) {
634 fs->base.DeletePending = EGL_TRUE;
635 } else {
636 intel_bind_frontbuffer(fs->drawable, NULL);
637 intel_destroy_drawable(fs->drawable);
638 free(fs->drawable);
639 free(fs);
640 }
641 return EGL_TRUE;
642 }
643
644
645 static EGLBoolean
646 drm_make_current(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext context)
647 {
648 struct drm_surface *readSurf = lookup_drm_surface(read);
649 struct drm_surface *drawSurf = lookup_drm_surface(draw);
650 struct drm_context *ctx = lookup_drm_context(context);
651 EGLBoolean b;
652
653 b = _eglMakeCurrent(drv, dpy, draw, read, context);
654 if (!b)
655 return EGL_FALSE;
656
657 if (ctx) {
658 if (!drawSurf || !readSurf)
659 return EGL_FALSE;
660
661 intel_make_current(ctx->context, drawSurf->drawable, readSurf->drawable);
662 } else {
663 intel_make_current(NULL, NULL, NULL);
664 }
665
666 return EGL_TRUE;
667 }
668
669 static EGLBoolean
670 drm_swap_buffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
671 {
672 struct drm_surface *surf = lookup_drm_surface(draw);
673 if (!surf)
674 return EGL_FALSE;
675
676 /* error checking */
677 if (!_eglSwapBuffers(drv, dpy, draw))
678 return EGL_FALSE;
679
680 intel_swap_buffers(surf->drawable);
681 return EGL_TRUE;
682 }
683
684
685 /**
686 * The bootstrap function. Return a new drm_driver object and
687 * plug in API functions.
688 */
689 _EGLDriver *
690 _eglMain(_EGLDisplay *dpy, const char *args)
691 {
692 struct drm_driver *drm;
693
694 drm = (struct drm_driver *) calloc(1, sizeof(struct drm_driver));
695 if (!drm) {
696 return NULL;
697 }
698
699 /* First fill in the dispatch table with defaults */
700 _eglInitDriverFallbacks(&drm->base);
701 /* then plug in our Drm-specific functions */
702 drm->base.API.Initialize = drm_initialize;
703 drm->base.API.Terminate = drm_terminate;
704 drm->base.API.CreateContext = drm_create_context;
705 drm->base.API.MakeCurrent = drm_make_current;
706 drm->base.API.CreateWindowSurface = drm_create_window_surface;
707 drm->base.API.CreatePixmapSurface = drm_create_pixmap_surface;
708 drm->base.API.CreatePbufferSurface = drm_create_pbuffer_surface;
709 drm->base.API.DestroySurface = drm_destroy_surface;
710 drm->base.API.DestroyContext = drm_destroy_context;
711 drm->base.API.CreateScreenSurfaceMESA = drm_create_screen_surface_mesa;
712 drm->base.API.ShowScreenSurfaceMESA = drm_show_screen_surface_mesa;
713 drm->base.API.SwapBuffers = drm_swap_buffers;
714
715 drm->base.ClientAPIsMask = EGL_OPENGL_BIT /*| EGL_OPENGL_ES_BIT*/;
716 drm->base.Name = "DRM/Gallium";
717
718 /* enable supported extensions */
719 drm->base.Extensions.MESA_screen_surface = EGL_TRUE;
720 drm->base.Extensions.MESA_copy_context = EGL_TRUE;
721
722 return &drm->base;
723 }