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
)) {
70 _egl_context_modes_destroy(__GLcontextModes
*modes
)
72 _eglLog(_EGL_DEBUG
, "%s", __FUNCTION__
);
75 __GLcontextModes
* const next
= modes
->next
;
81 * Create a linked list of 'count' GLcontextModes.
82 * These are used during the client/server visual negotiation phase,
85 static __GLcontextModes
*
86 _egl_context_modes_create(unsigned count
, size_t minimum_size
)
88 /* This code copied from libGLX, and modified */
89 const size_t size
= (minimum_size
> sizeof(__GLcontextModes
))
90 ? minimum_size
: sizeof(__GLcontextModes
);
91 __GLcontextModes
* head
= NULL
;
92 __GLcontextModes
** next
;
95 _eglLog(_EGL_DEBUG
, "%s %d %d", __FUNCTION__
, count
, minimum_size
);
98 for (i
= 0 ; i
< count
; i
++) {
99 *next
= (__GLcontextModes
*) calloc(1, size
);
101 _egl_context_modes_destroy(head
);
106 (*next
)->doubleBufferMode
= 1;
107 (*next
)->visualID
= GLX_DONT_CARE
;
108 (*next
)->visualType
= GLX_DONT_CARE
;
109 (*next
)->visualRating
= GLX_NONE
;
110 (*next
)->transparentPixel
= GLX_NONE
;
111 (*next
)->transparentRed
= GLX_DONT_CARE
;
112 (*next
)->transparentGreen
= GLX_DONT_CARE
;
113 (*next
)->transparentBlue
= GLX_DONT_CARE
;
114 (*next
)->transparentAlpha
= GLX_DONT_CARE
;
115 (*next
)->transparentIndex
= GLX_DONT_CARE
;
116 (*next
)->xRenderable
= GLX_DONT_CARE
;
117 (*next
)->fbconfigID
= GLX_DONT_CARE
;
118 (*next
)->swapMethod
= GLX_SWAP_UNDEFINED_OML
;
119 (*next
)->bindToTextureRgb
= GLX_DONT_CARE
;
120 (*next
)->bindToTextureRgba
= GLX_DONT_CARE
;
121 (*next
)->bindToMipmapTexture
= GLX_DONT_CARE
;
122 (*next
)->bindToTextureTargets
= 0;
123 (*next
)->yInverted
= GLX_DONT_CARE
;
125 next
= & ((*next
)->next
);
135 _EGLDriver base
; /* base class/object */
139 struct drm_screen
*screens
[MAX_SCREENS
];
140 size_t count_screens
;
142 struct egl_drm_device
*device
;
147 _EGLSurface base
; /* base class/object */
149 struct egl_drm_drawable
*drawable
;
154 _EGLContext base
; /* base class/object */
156 struct egl_drm_context
*context
;
163 /* currently only support one connector */
164 drmModeConnectorPtr connector
;
166 /* Has this screen been shown */
169 /* Surface that is currently attached to this screen */
170 struct drm_surface
*surf
;
179 /* crtc and mode used */
183 struct drm_mode_modeinfo
*mode
;
185 /* geometry of the screen */
186 struct egl_drm_frontbuffer front
;
190 drm_update_res(struct drm_driver
*drm_drv
)
192 drmModeFreeResources(drm_drv
->res
);
193 drm_drv
->res
= drmModeGetResources(drm_drv
->device
->drmFD
);
197 drm_add_modes_from_connector(_EGLScreen
*screen
, drmModeConnectorPtr connector
)
199 struct drm_mode_modeinfo
*m
;
202 for (i
= 0; i
< connector
->count_modes
; i
++) {
203 m
= &connector
->modes
[i
];
204 _eglAddNewMode(screen
, m
->hdisplay
, m
->vdisplay
, m
->vrefresh
, m
->name
);
210 drm_initialize(_EGLDriver
*drv
, EGLDisplay dpy
, EGLint
*major
, EGLint
*minor
)
212 _EGLDisplay
*disp
= _eglLookupDisplay(dpy
);
213 struct drm_driver
*drm_drv
= (struct drm_driver
*)drv
;
214 struct drm_screen
*screen
= NULL
;
215 drmModeConnectorPtr connector
= NULL
;
216 drmModeResPtr res
= NULL
;
217 unsigned count_connectors
= 0;
223 fd
= drmOpen("i915", NULL
);
228 drm_drv
->device
= egl_drm_create_device(fd
);
229 if (!drm_drv
->device
) {
234 drm_update_res(drm_drv
);
237 count_connectors
= res
->count_connectors
;
239 for(i
= 0; i
< count_connectors
&& i
< MAX_SCREENS
; i
++) {
240 connector
= drmModeGetConnector(fd
, res
->connectors
[i
]);
245 if (connector
->connection
!= DRM_MODE_CONNECTED
) {
246 drmModeFreeConnector(connector
);
250 screen
= malloc(sizeof(struct drm_screen
));
251 memset(screen
, 0, sizeof(*screen
));
252 screen
->connector
= connector
;
253 _eglInitScreen(&screen
->base
);
254 _eglAddScreen(disp
, &screen
->base
);
255 drm_add_modes_from_connector(&screen
->base
, connector
);
256 drm_drv
->screens
[num_screens
++] = screen
;
258 drm_drv
->count_screens
= num_screens
;
260 /* for now we only have one config */
261 _EGLConfig
*config
= calloc(1, sizeof(*config
));
262 memset(config
, 1, sizeof(*config
));
263 _eglInitConfig(config
, 1);
264 _eglSetConfigAttrib(config
, EGL_RED_SIZE
, 8);
265 _eglSetConfigAttrib(config
, EGL_GREEN_SIZE
, 8);
266 _eglSetConfigAttrib(config
, EGL_BLUE_SIZE
, 8);
267 _eglSetConfigAttrib(config
, EGL_ALPHA_SIZE
, 8);
268 _eglSetConfigAttrib(config
, EGL_BUFFER_SIZE
, 32);
269 _eglSetConfigAttrib(config
, EGL_DEPTH_SIZE
, 24);
270 _eglSetConfigAttrib(config
, EGL_STENCIL_SIZE
, 8);
271 _eglSetConfigAttrib(config
, EGL_SURFACE_TYPE
, EGL_PBUFFER_BIT
);
272 _eglAddConfig(disp
, config
);
274 drv
->Initialized
= EGL_TRUE
;
283 drm_takedown_shown_screen(_EGLDriver
*drv
, struct drm_screen
*screen
)
285 struct drm_driver
*drm_drv
= (struct drm_driver
*)drv
;
288 intel_bind_frontbuffer(screen
->surf
->drawable
, NULL
);
291 for (i
= 0; i
< drm_drv
->res
->count_crtcs
; i
++) {
293 drm_drv
->device
->drmFD
,
294 drm_drv
->res
->crtcs
[i
],
297 NULL
, 0, // List of output ids
301 drmModeRmFB(drm_drv
->device
->drmFD
, screen
->fbID
);
302 drmModeFreeFB(screen
->fb
);
305 drmBOUnreference(drm_drv
->device
->drmFD
, &screen
->buffer
);
311 drm_terminate(_EGLDriver
*drv
, EGLDisplay dpy
)
313 struct drm_driver
*drm_drv
= (struct drm_driver
*)drv
;
314 struct drm_screen
*screen
;
317 intel_destroy_device(drm_drv
->device
);
318 drmFreeVersion(drm_drv
->device
->version
);
320 for (i
= 0; i
< drm_drv
->count_screens
; i
++) {
321 screen
= drm_drv
->screens
[i
];
324 drm_takedown_shown_screen(drv
, screen
);
326 drmModeFreeConnector(screen
->connector
);
327 _eglDestroyScreen(&screen
->base
);
328 drm_drv
->screens
[i
] = NULL
;
331 drmClose(drm_drv
->device
->drmFD
);
333 free(drm_drv
->device
);
335 _eglCleanupDisplay(_eglLookupDisplay(dpy
));
342 static struct drm_context
*
343 lookup_drm_context(EGLContext context
)
345 _EGLContext
*c
= _eglLookupContext(context
);
346 return (struct drm_context
*) c
;
350 static struct drm_surface
*
351 lookup_drm_surface(EGLSurface surface
)
353 _EGLSurface
*s
= _eglLookupSurface(surface
);
354 return (struct drm_surface
*) s
;
357 static struct drm_screen
*
358 lookup_drm_screen(EGLDisplay dpy
, EGLScreenMESA screen
)
360 _EGLScreen
*s
= _eglLookupScreen(dpy
, screen
);
361 return (struct drm_screen
*) s
;
364 static __GLcontextModes
*
365 visual_from_config(_EGLConfig
*conf
)
367 __GLcontextModes
*visual
;
370 visual
= _egl_context_modes_create(1, sizeof(*visual
));
372 visual
->greenBits
= 8;
373 visual
->blueBits
= 8;
374 visual
->alphaBits
= 8;
376 visual
->rgbBits
= 32;
377 visual
->doubleBufferMode
= 1;
379 visual
->depthBits
= 24;
380 visual
->haveDepthBuffer
= visual
->depthBits
> 0;
381 visual
->stencilBits
= 8;
382 visual
->haveStencilBuffer
= visual
->stencilBits
> 0;
390 drm_create_context(_EGLDriver
*drv
, EGLDisplay dpy
, EGLConfig config
, EGLContext share_list
, const EGLint
*attrib_list
)
392 struct drm_driver
*drm_drv
= (struct drm_driver
*)drv
;
393 struct drm_context
*c
;
394 struct drm_egl_context
*share
= NULL
;
398 __GLcontextModes
*visual
;
399 struct egl_drm_context
*context
;
401 conf
= _eglLookupConfig(drv
, dpy
, config
);
403 _eglError(EGL_BAD_CONFIG
, "eglCreateContext");
404 return EGL_NO_CONTEXT
;
407 for (i
= 0; attrib_list
&& attrib_list
[i
] != EGL_NONE
; i
++) {
408 switch (attrib_list
[i
]) {
409 /* no attribs defined for now */
411 _eglError(EGL_BAD_ATTRIBUTE
, "eglCreateContext");
412 return EGL_NO_CONTEXT
;
416 c
= (struct drm_context
*) calloc(1, sizeof(struct drm_context
));
418 return EGL_NO_CONTEXT
;
420 _eglInitContext(drv
, dpy
, &c
->base
, config
, attrib_list
);
422 context
= malloc(sizeof(*context
));
423 memset(context
, 0, sizeof(*context
));
428 context
->device
= drm_drv
->device
;
429 visual
= visual_from_config(conf
);
431 ret
= intel_create_context(context
, visual
, share
);
437 c
->context
= context
;
439 /* generate handle and insert into hash table */
440 _eglSaveContext(&c
->base
);
441 assert(_eglGetContextHandle(&c
->base
));
443 return _eglGetContextHandle(&c
->base
);
448 return EGL_NO_CONTEXT
;
452 drm_destroy_context(_EGLDriver
*drv
, EGLDisplay dpy
, EGLContext context
)
454 struct drm_context
*fc
= lookup_drm_context(context
);
455 _eglRemoveContext(&fc
->base
);
456 if (fc
->base
.IsBound
) {
457 fc
->base
.DeletePending
= EGL_TRUE
;
459 intel_destroy_context(fc
->context
);
468 drm_create_window_surface(_EGLDriver
*drv
, EGLDisplay dpy
, EGLConfig config
, NativeWindowType window
, const EGLint
*attrib_list
)
470 return EGL_NO_SURFACE
;
475 drm_create_pixmap_surface(_EGLDriver
*drv
, EGLDisplay dpy
, EGLConfig config
, NativePixmapType pixmap
, const EGLint
*attrib_list
)
477 return EGL_NO_SURFACE
;
482 drm_create_pbuffer_surface(_EGLDriver
*drv
, EGLDisplay dpy
, EGLConfig config
,
483 const EGLint
*attrib_list
)
485 struct drm_driver
*drm_drv
= (struct drm_driver
*)drv
;
490 struct drm_surface
*surf
= NULL
;
491 struct egl_drm_drawable
*drawable
= NULL
;
492 __GLcontextModes
*visual
;
495 conf
= _eglLookupConfig(drv
, dpy
, config
);
497 _eglError(EGL_BAD_CONFIG
, "eglCreatePbufferSurface");
498 return EGL_NO_CONTEXT
;
501 for (i
= 0; attrib_list
&& attrib_list
[i
] != EGL_NONE
; i
++) {
502 switch (attrib_list
[i
]) {
504 width
= attrib_list
[++i
];
507 height
= attrib_list
[++i
];
510 _eglError(EGL_BAD_ATTRIBUTE
, "eglCreatePbufferSurface");
511 return EGL_NO_SURFACE
;
515 if (width
< 1 || height
< 1) {
516 _eglError(EGL_BAD_ATTRIBUTE
, "eglCreatePbufferSurface");
517 return EGL_NO_SURFACE
;
520 surf
= (struct drm_surface
*) calloc(1, sizeof(struct drm_surface
));
524 if (!_eglInitSurface(drv
, dpy
, &surf
->base
, EGL_PBUFFER_BIT
, config
, attrib_list
))
527 drawable
= malloc(sizeof(*drawable
));
528 memset(drawable
, 0, sizeof(*drawable
));
531 drawable
->h
= height
;
533 visual
= visual_from_config(conf
);
535 drawable
->device
= drm_drv
->device
;
536 ret
= intel_create_drawable(drawable
, visual
);
542 surf
->drawable
= drawable
;
544 _eglSaveSurface(&surf
->base
);
545 return surf
->base
.Handle
;
552 return EGL_NO_SURFACE
;
556 drm_create_screen_surface_mesa(_EGLDriver
*drv
, EGLDisplay dpy
, EGLConfig cfg
,
557 const EGLint
*attrib_list
)
559 EGLSurface surf
= drm_create_pbuffer_surface(drv
, dpy
, cfg
, attrib_list
);
564 static struct drm_mode_modeinfo
*
565 drm_find_mode(drmModeConnectorPtr connector
, _EGLMode
*mode
)
568 struct drm_mode_modeinfo
*m
;
570 for (i
= 0; i
< connector
->count_modes
; i
++) {
571 m
= &connector
->modes
[i
];
572 if (m
->hdisplay
== mode
->Width
&& m
->vdisplay
== mode
->Height
&& m
->vrefresh
== mode
->RefreshRate
)
574 m
= &connector
->modes
[0]; /* if we can't find one, return first */
580 draw(size_t x
, size_t y
, size_t w
, size_t h
, size_t pitch
, size_t v
, unsigned int *ptr
)
584 for (i
= x
; i
< x
+ w
; i
++)
585 for(j
= y
; j
< y
+ h
; j
++)
586 ptr
[(i
* pitch
/ 4) + j
] = v
;
591 prettyColors(int fd
, unsigned int handle
, size_t pitch
)
598 drmBOReference(fd
, handle
, &bo
);
599 drmBOMap(fd
, &bo
, DRM_BO_FLAG_READ
| DRM_BO_FLAG_WRITE
, 0, &p
);
600 ptr
= (unsigned int*)p
;
602 for (i
= 0; i
< (bo
.size
/ 4); i
++)
605 for (i
= 0; i
< 4; i
++)
606 draw(i
* 40, i
* 40, 40, 40, pitch
, 0, ptr
);
609 draw(200, 100, 40, 40, pitch
, 0xff00ff, ptr
);
610 draw(100, 200, 40, 40, pitch
, 0xff00ff, ptr
);
616 drm_show_screen_surface_mesa(_EGLDriver
*drv
, EGLDisplay dpy
,
617 EGLScreenMESA screen
,
618 EGLSurface surface
, EGLModeMESA m
)
620 struct drm_driver
*drm_drv
= (struct drm_driver
*)drv
;
621 struct drm_surface
*surf
= lookup_drm_surface(surface
);
622 struct drm_screen
*scrn
= lookup_drm_screen(dpy
, screen
);
623 _EGLMode
*mode
= _eglLookupMode(dpy
, m
);
624 size_t pitch
= mode
->Width
* 4;
625 size_t size
= mode
->Height
* pitch
;
630 drm_takedown_shown_screen(drv
, scrn
);
632 ret
= drmBOCreate(drm_drv
->device
->drmFD
, size
, 0, 0,
636 DRM_BO_FLAG_MEM_VRAM
|
637 DRM_BO_FLAG_NO_EVICT
,
638 DRM_BO_HINT_DONT_FENCE
, &scrn
->buffer
);
643 prettyColors(drm_drv
->device
->drmFD
, scrn
->buffer
.handle
, pitch
);
645 ret
= drmModeAddFB(drm_drv
->device
->drmFD
, mode
->Width
, mode
->Height
,
653 scrn
->fb
= drmModeGetFB(drm_drv
->device
->drmFD
, scrn
->fbID
);
657 for (j
= 0; j
< drm_drv
->res
->count_connectors
; j
++) {
658 drmModeConnector
*con
= drmModeGetConnector(drm_drv
->device
->drmFD
, drm_drv
->res
->connectors
[j
]);
659 scrn
->mode
= drm_find_mode(con
, mode
);
663 for (k
= 0; k
< con
->count_encoders
; k
++) {
664 drmModeEncoder
*enc
= drmModeGetEncoder(drm_drv
->device
->drmFD
, con
->encoders
[k
]);
665 for (i
= 0; i
< drm_drv
->res
->count_crtcs
; i
++) {
666 if (enc
->possible_crtcs
& (1<<i
)) {
667 ret
= drmModeSetCrtc(
668 drm_drv
->device
->drmFD
,
669 drm_drv
->res
->crtcs
[i
],
672 &drm_drv
->res
->connectors
[j
], 1,
674 /* skip the other crtcs now */
675 i
= drm_drv
->res
->count_crtcs
;
681 scrn
->front
.handle
= scrn
->buffer
.handle
;
682 scrn
->front
.pitch
= pitch
;
683 scrn
->front
.width
= mode
->Width
;
684 scrn
->front
.height
= mode
->Height
;
687 intel_bind_frontbuffer(surf
->drawable
, &scrn
->front
);
697 drmBOUnreference(drm_drv
->device
->drmFD
, &scrn
->buffer
);
702 drm_destroy_surface(_EGLDriver
*drv
, EGLDisplay dpy
, EGLSurface surface
)
704 struct drm_surface
*fs
= lookup_drm_surface(surface
);
705 _eglRemoveSurface(&fs
->base
);
706 if (fs
->base
.IsBound
) {
707 fs
->base
.DeletePending
= EGL_TRUE
;
709 intel_bind_frontbuffer(fs
->drawable
, NULL
);
710 intel_destroy_drawable(fs
->drawable
);
719 drm_make_current(_EGLDriver
*drv
, EGLDisplay dpy
, EGLSurface draw
, EGLSurface read
, EGLContext context
)
721 struct drm_surface
*readSurf
= lookup_drm_surface(read
);
722 struct drm_surface
*drawSurf
= lookup_drm_surface(draw
);
723 struct drm_context
*ctx
= lookup_drm_context(context
);
726 b
= _eglMakeCurrent(drv
, dpy
, draw
, read
, context
);
731 if (!drawSurf
|| !readSurf
)
734 intel_make_current(ctx
->context
, drawSurf
->drawable
, readSurf
->drawable
);
736 intel_make_current(NULL
, NULL
, NULL
);
743 drm_swap_buffers(_EGLDriver
*drv
, EGLDisplay dpy
, EGLSurface draw
)
745 struct drm_surface
*surf
= lookup_drm_surface(draw
);
750 if (!_eglSwapBuffers(drv
, dpy
, draw
))
753 intel_swap_buffers(surf
->drawable
);
759 * The bootstrap function. Return a new drm_driver object and
760 * plug in API functions.
763 _eglMain(_EGLDisplay
*dpy
, const char *args
)
765 struct drm_driver
*drm
;
767 drm
= (struct drm_driver
*) calloc(1, sizeof(struct drm_driver
));
772 /* First fill in the dispatch table with defaults */
773 _eglInitDriverFallbacks(&drm
->base
);
774 /* then plug in our Drm-specific functions */
775 drm
->base
.API
.Initialize
= drm_initialize
;
776 drm
->base
.API
.Terminate
= drm_terminate
;
777 drm
->base
.API
.CreateContext
= drm_create_context
;
778 drm
->base
.API
.MakeCurrent
= drm_make_current
;
779 drm
->base
.API
.CreateWindowSurface
= drm_create_window_surface
;
780 drm
->base
.API
.CreatePixmapSurface
= drm_create_pixmap_surface
;
781 drm
->base
.API
.CreatePbufferSurface
= drm_create_pbuffer_surface
;
782 drm
->base
.API
.DestroySurface
= drm_destroy_surface
;
783 drm
->base
.API
.DestroyContext
= drm_destroy_context
;
784 drm
->base
.API
.CreateScreenSurfaceMESA
= drm_create_screen_surface_mesa
;
785 drm
->base
.API
.ShowScreenSurfaceMESA
= drm_show_screen_surface_mesa
;
786 drm
->base
.API
.SwapBuffers
= drm_swap_buffers
;
788 drm
->base
.ClientAPIsMask
= EGL_OPENGL_BIT
/*| EGL_OPENGL_ES_BIT*/;
789 drm
->base
.Name
= "DRM/Gallium";
791 /* enable supported extensions */
792 drm
->base
.Extensions
.MESA_screen_surface
= EGL_TRUE
;
793 drm
->base
.Extensions
.MESA_copy_context
= EGL_TRUE
;