9 #include "eglcontext.h"
10 #include "egldisplay.h"
11 #include "egldriver.h"
12 #include "eglglobals.h"
14 #include "eglscreen.h"
15 #include "eglsurface.h"
18 #include "intel_egl.h"
21 #include "xf86drmMode.h"
23 #include "intel_context.h"
25 #include "state_tracker/st_public.h"
27 #define MAX_SCREENS 16
30 drm_get_device_id(struct egl_drm_device
*device
)
35 /* TODO get the real minor */
38 snprintf(path
, sizeof(path
), "/sys/class/drm/card%d/device/device", minor
);
39 file
= fopen(path
, "r");
41 _eglLog(_EGL_WARNING
, "Could not retrive device ID\n");
45 fgets(path
, sizeof( path
), file
);
46 sscanf(path
, "%x", &device
->deviceID
);
50 static struct egl_drm_device
*
51 egl_drm_create_device(int drmFD
)
53 struct egl_drm_device
*device
= malloc(sizeof(*device
));
54 memset(device
, 0, sizeof(*device
));
55 device
->drmFD
= drmFD
;
57 device
->version
= drmGetVersion(device
->drmFD
);
59 drm_get_device_id(device
);
61 if (!intel_create_device(device
)) {
69 __GLcontextModes
* _gl_context_modes_create( unsigned count
, size_t minimum_size
);
75 _EGLDriver base
; /* base class/object */
79 struct drm_screen
*screens
[MAX_SCREENS
];
82 struct egl_drm_device
*device
;
87 _EGLSurface base
; /* base class/object */
89 struct egl_drm_drawable
*drawable
;
94 _EGLContext base
; /* base class/object */
96 struct egl_drm_context
*context
;
103 /* currently only support one connector */
104 drmModeConnectorPtr connector
;
105 uint32_t connectorID
;
107 /* Has this screen been shown */
110 /* Surface that is currently attached to this screen */
111 struct drm_surface
*surf
;
120 /* crtc and mode used */
124 struct drm_mode_modeinfo
*mode
;
126 /* geometry of the screen */
127 struct egl_drm_frontbuffer front
;
131 drm_update_res(struct drm_driver
*drm_drv
)
133 drmModeFreeResources(drm_drv
->res
);
134 drm_drv
->res
= drmModeGetResources(drm_drv
->device
->drmFD
);
138 drm_add_modes_from_connector(_EGLScreen
*screen
, drmModeConnectorPtr connector
)
140 struct drm_mode_modeinfo
*m
;
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
);
151 drm_initialize(_EGLDriver
*drv
, EGLDisplay dpy
, EGLint
*major
, EGLint
*minor
)
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;
164 fd
= drmOpen("i915", NULL
);
169 drm_drv
->device
= egl_drm_create_device(fd
);
170 if (!drm_drv
->device
) {
175 drm_update_res(drm_drv
);
178 count_connectors
= res
->count_connectors
;
180 for(i
= 0; i
< count_connectors
&& i
< MAX_SCREENS
; i
++) {
181 connector
= drmModeGetConnector(fd
, res
->connectors
[i
]);
186 if (connector
->connection
!= DRM_MODE_CONNECTED
) {
187 drmModeFreeConnector(connector
);
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
;
200 drm_drv
->count_screens
= num_screens
;
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
);
216 drv
->Initialized
= EGL_TRUE
;
225 drm_takedown_shown_screen(_EGLDriver
*drv
, struct drm_screen
*screen
)
227 struct drm_driver
*drm_drv
= (struct drm_driver
*)drv
;
229 intel_bind_frontbuffer(screen
->surf
->drawable
, NULL
);
233 drm_drv
->device
->drmFD
,
234 drm_drv
->res
->crtcs
[1],
237 NULL
, 0, // List of output ids
240 drmModeRmFB(drm_drv
->device
->drmFD
, screen
->fbID
);
241 drmModeFreeFB(screen
->fb
);
244 drmBOUnreference(drm_drv
->device
->drmFD
, &screen
->buffer
);
250 drm_terminate(_EGLDriver
*drv
, EGLDisplay dpy
)
252 struct drm_driver
*drm_drv
= (struct drm_driver
*)drv
;
253 struct drm_screen
*screen
;
256 intel_destroy_device(drm_drv
->device
);
257 drmFreeVersion(drm_drv
->device
->version
);
259 for (i
= 0; i
< drm_drv
->count_screens
; i
++) {
260 screen
= drm_drv
->screens
[i
];
263 drm_takedown_shown_screen(drv
, screen
);
265 drmModeFreeConnector(screen
->connector
);
266 _eglDestroyScreen(&screen
->base
);
267 drm_drv
->screens
[i
] = NULL
;
270 drmClose(drm_drv
->device
->drmFD
);
272 free(drm_drv
->device
);
274 _eglCleanupDisplay(_eglLookupDisplay(dpy
));
281 static struct drm_context
*
282 lookup_drm_context(EGLContext context
)
284 _EGLContext
*c
= _eglLookupContext(context
);
285 return (struct drm_context
*) c
;
289 static struct drm_surface
*
290 lookup_drm_surface(EGLSurface surface
)
292 _EGLSurface
*s
= _eglLookupSurface(surface
);
293 return (struct drm_surface
*) s
;
296 static struct drm_screen
*
297 lookup_drm_screen(EGLDisplay dpy
, EGLScreenMESA screen
)
299 _EGLScreen
*s
= _eglLookupScreen(dpy
, screen
);
300 return (struct drm_screen
*) s
;
303 static __GLcontextModes
*
304 visual_from_config(_EGLConfig
*conf
)
306 __GLcontextModes
*visual
;
309 visual
= _gl_context_modes_create(1, sizeof(*visual
));
311 visual
->greenBits
= 8;
312 visual
->blueBits
= 8;
313 visual
->alphaBits
= 8;
315 visual
->rgbBits
= 32;
316 visual
->doubleBufferMode
= 1;
318 visual
->depthBits
= 24;
319 visual
->haveDepthBuffer
= visual
->depthBits
> 0;
320 visual
->stencilBits
= 8;
321 visual
->haveStencilBuffer
= visual
->stencilBits
> 0;
329 drm_create_context(_EGLDriver
*drv
, EGLDisplay dpy
, EGLConfig config
, EGLContext share_list
, const EGLint
*attrib_list
)
331 struct drm_driver
*drm_drv
= (struct drm_driver
*)drv
;
332 struct drm_context
*c
;
333 struct drm_egl_context
*share
= NULL
;
337 __GLcontextModes
*visual
;
338 struct egl_drm_context
*context
;
340 conf
= _eglLookupConfig(drv
, dpy
, config
);
342 _eglError(EGL_BAD_CONFIG
, "eglCreateContext");
343 return EGL_NO_CONTEXT
;
346 for (i
= 0; attrib_list
&& attrib_list
[i
] != EGL_NONE
; i
++) {
347 switch (attrib_list
[i
]) {
348 /* no attribs defined for now */
350 _eglError(EGL_BAD_ATTRIBUTE
, "eglCreateContext");
351 return EGL_NO_CONTEXT
;
355 c
= (struct drm_context
*) calloc(1, sizeof(struct drm_context
));
357 return EGL_NO_CONTEXT
;
359 _eglInitContext(drv
, dpy
, &c
->base
, config
, attrib_list
);
361 context
= malloc(sizeof(*context
));
362 memset(context
, 0, sizeof(*context
));
367 context
->device
= drm_drv
->device
;
368 visual
= visual_from_config(conf
);
370 ret
= intel_create_context(context
, visual
, share
);
376 c
->context
= context
;
378 /* generate handle and insert into hash table */
379 _eglSaveContext(&c
->base
);
380 assert(_eglGetContextHandle(&c
->base
));
382 return _eglGetContextHandle(&c
->base
);
387 return EGL_NO_CONTEXT
;
391 drm_destroy_context(_EGLDriver
*drv
, EGLDisplay dpy
, EGLContext context
)
393 struct drm_context
*fc
= lookup_drm_context(context
);
394 _eglRemoveContext(&fc
->base
);
395 if (fc
->base
.IsBound
) {
396 fc
->base
.DeletePending
= EGL_TRUE
;
398 intel_destroy_context(fc
->context
);
407 drm_create_window_surface(_EGLDriver
*drv
, EGLDisplay dpy
, EGLConfig config
, NativeWindowType window
, const EGLint
*attrib_list
)
409 return EGL_NO_SURFACE
;
414 drm_create_pixmap_surface(_EGLDriver
*drv
, EGLDisplay dpy
, EGLConfig config
, NativePixmapType pixmap
, const EGLint
*attrib_list
)
416 return EGL_NO_SURFACE
;
421 drm_create_pbuffer_surface(_EGLDriver
*drv
, EGLDisplay dpy
, EGLConfig config
,
422 const EGLint
*attrib_list
)
424 struct drm_driver
*drm_drv
= (struct drm_driver
*)drv
;
429 struct drm_surface
*surf
= NULL
;
430 struct egl_drm_drawable
*drawable
= NULL
;
431 __GLcontextModes
*visual
;
434 conf
= _eglLookupConfig(drv
, dpy
, config
);
436 _eglError(EGL_BAD_CONFIG
, "eglCreatePbufferSurface");
437 return EGL_NO_CONTEXT
;
440 for (i
= 0; attrib_list
&& attrib_list
[i
] != EGL_NONE
; i
++) {
441 switch (attrib_list
[i
]) {
443 width
= attrib_list
[++i
];
446 height
= attrib_list
[++i
];
449 _eglError(EGL_BAD_ATTRIBUTE
, "eglCreatePbufferSurface");
450 return EGL_NO_SURFACE
;
454 if (width
< 1 || height
< 1) {
455 _eglError(EGL_BAD_ATTRIBUTE
, "eglCreatePbufferSurface");
456 return EGL_NO_SURFACE
;
459 surf
= (struct drm_surface
*) calloc(1, sizeof(struct drm_surface
));
463 if (!_eglInitSurface(drv
, dpy
, &surf
->base
, EGL_PBUFFER_BIT
, config
, attrib_list
))
466 drawable
= malloc(sizeof(*drawable
));
467 memset(drawable
, 0, sizeof(*drawable
));
470 drawable
->h
= height
;
472 visual
= visual_from_config(conf
);
474 drawable
->device
= drm_drv
->device
;
475 ret
= intel_create_drawable(drawable
, visual
);
481 surf
->drawable
= drawable
;
483 _eglSaveSurface(&surf
->base
);
484 return surf
->base
.Handle
;
491 return EGL_NO_SURFACE
;
495 drm_create_screen_surface_mesa(_EGLDriver
*drv
, EGLDisplay dpy
, EGLConfig cfg
,
496 const EGLint
*attrib_list
)
498 EGLSurface surf
= drm_create_pbuffer_surface(drv
, dpy
, cfg
, attrib_list
);
503 static struct drm_mode_modeinfo
*
504 drm_find_mode(drmModeConnectorPtr connector
, _EGLMode
*mode
)
507 struct drm_mode_modeinfo
*m
;
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
)
519 draw(size_t x
, size_t y
, size_t w
, size_t h
, size_t pitch
, size_t v
, unsigned int *ptr
)
523 for (i
= x
; i
< x
+ w
; i
++)
524 for(j
= y
; j
< y
+ h
; j
++)
525 ptr
[(i
* pitch
/ 4) + j
] = v
;
530 prettyColors(int fd
, unsigned int handle
, size_t pitch
)
537 drmBOReference(fd
, handle
, &bo
);
538 drmBOMap(fd
, &bo
, DRM_BO_FLAG_READ
| DRM_BO_FLAG_WRITE
, 0, &p
);
539 ptr
= (unsigned int*)p
;
541 for (i
= 0; i
< (bo
.size
/ 4); i
++)
544 for (i
= 0; i
< 4; i
++)
545 draw(i
* 40, i
* 40, 40, 40, pitch
, 0, ptr
);
548 draw(200, 100, 40, 40, pitch
, 0xff00ff, ptr
);
549 draw(100, 200, 40, 40, pitch
, 0xff00ff, ptr
);
555 drm_show_screen_surface_mesa(_EGLDriver
*drv
, EGLDisplay dpy
,
556 EGLScreenMESA screen
,
557 EGLSurface surface
, EGLModeMESA m
)
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
;
568 drm_takedown_shown_screen(drv
, scrn
);
570 ret
= drmBOCreate(drm_drv
->device
->drmFD
, size
, 0, 0,
574 DRM_BO_FLAG_MEM_VRAM
|
575 DRM_BO_FLAG_NO_EVICT
,
576 DRM_BO_HINT_DONT_FENCE
, &scrn
->buffer
);
581 prettyColors(drm_drv
->device
->drmFD
, scrn
->buffer
.handle
, pitch
);
583 ret
= drmModeAddFB(drm_drv
->device
->drmFD
, mode
->Width
, mode
->Height
,
591 scrn
->fb
= drmModeGetFB(drm_drv
->device
->drmFD
, scrn
->fbID
);
595 scrn
->mode
= drm_find_mode(scrn
->connector
, mode
);
599 ret
= drmModeSetCrtc(
600 drm_drv
->device
->drmFD
,
601 drm_drv
->res
->crtcs
[1],
604 &scrn
->connectorID
, 1,
608 scrn
->front
.handle
= scrn
->buffer
.handle
;
609 scrn
->front
.pitch
= pitch
;
610 scrn
->front
.width
= mode
->Width
;
611 scrn
->front
.height
= mode
->Height
;
614 intel_bind_frontbuffer(surf
->drawable
, &scrn
->front
);
624 drmBOUnreference(drm_drv
->device
->drmFD
, &scrn
->buffer
);
629 drm_destroy_surface(_EGLDriver
*drv
, EGLDisplay dpy
, EGLSurface surface
)
631 struct drm_surface
*fs
= lookup_drm_surface(surface
);
632 _eglRemoveSurface(&fs
->base
);
633 if (fs
->base
.IsBound
) {
634 fs
->base
.DeletePending
= EGL_TRUE
;
636 intel_bind_frontbuffer(fs
->drawable
, NULL
);
637 intel_destroy_drawable(fs
->drawable
);
646 drm_make_current(_EGLDriver
*drv
, EGLDisplay dpy
, EGLSurface draw
, EGLSurface read
, EGLContext context
)
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
);
653 b
= _eglMakeCurrent(drv
, dpy
, draw
, read
, context
);
658 if (!drawSurf
|| !readSurf
)
661 intel_make_current(ctx
->context
, drawSurf
->drawable
, readSurf
->drawable
);
663 intel_make_current(NULL
, NULL
, NULL
);
670 drm_swap_buffers(_EGLDriver
*drv
, EGLDisplay dpy
, EGLSurface draw
)
672 struct drm_surface
*surf
= lookup_drm_surface(draw
);
677 if (!_eglSwapBuffers(drv
, dpy
, draw
))
680 intel_swap_buffers(surf
->drawable
);
686 * The bootstrap function. Return a new drm_driver object and
687 * plug in API functions.
690 _eglMain(_EGLDisplay
*dpy
, const char *args
)
692 struct drm_driver
*drm
;
694 drm
= (struct drm_driver
*) calloc(1, sizeof(struct drm_driver
));
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
;
715 drm
->base
.ClientAPIsMask
= EGL_OPENGL_BIT
/*| EGL_OPENGL_ES_BIT*/;
716 drm
->base
.Name
= "DRM/Gallium";
718 /* enable supported extensions */
719 drm
->base
.Extensions
.MESA_screen_surface
= EGL_TRUE
;
720 drm
->base
.Extensions
.MESA_copy_context
= EGL_TRUE
;