2 #include "e_mod_main.h"
4 /* local function prototypes */
5 static void _cb_tty(E_Compositor *comp, int event);
6 static int _cb_drm_input(int fd, unsigned int mask __UNUSED__, void *data __UNUSED__);
7 static int _cb_drm_udev_event(int fd __UNUSED__, unsigned int mask __UNUSED__, void *data);
8 static void _cb_drm_page_flip(int fd __UNUSED__, unsigned int frame __UNUSED__, unsigned int sec, unsigned int usec, void *data);
9 static void _cb_drm_vblank(int fd __UNUSED__, unsigned int frame __UNUSED__, unsigned int sec __UNUSED__, unsigned int usec __UNUSED__, void *data);
10 static Eina_Bool _egl_init(E_Drm_Compositor *dcomp, struct udev_device *dev);
11 static void _sprites_init(E_Drm_Compositor *dcomp);
12 static void _sprites_shutdown(E_Drm_Compositor *dcomp);
13 static Eina_Bool _outputs_init(E_Drm_Compositor *dcomp, unsigned int conn, struct udev_device *drm_device);
14 static Eina_Bool _output_create(E_Drm_Compositor *dcomp, drmModeRes *res, drmModeConnector *conn, int x, int y, struct udev_device *drm_device);
15 static void _outputs_update(E_Drm_Compositor *dcomp, struct udev_device *drm_device);
16 static Eina_Bool _udev_event_is_hotplug(E_Drm_Compositor *dcomp, struct udev_device *dev);
19 static drmModeModeInfo builtin_mode =
22 1024, 1072, 1176, 1328, 0,
23 768, 771, 775, 798, 0,
25 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC,
30 /* external variables */
31 E_Drm_Compositor *_drm_comp = NULL;
33 EAPI E_Module_Api e_modapi = { E_MODULE_API_VERSION, "Drm" };
36 e_modapi_init(E_Module *m)
38 struct wl_display *disp;
39 struct udev_enumerate *ue;
40 struct udev_list_entry *entry;
41 struct udev_device *drm_dev = NULL;
42 struct wl_event_loop *loop;
43 const char *seat = NULL;
45 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
47 /* try to get the wayland display */
48 if (!(disp = (struct wl_display *)m->data)) return NULL;
50 /* allocate space for the drm compositor */
51 if (!(_drm_comp = malloc(sizeof(E_Drm_Compositor)))) return NULL;
53 memset(_drm_comp, 0, sizeof(E_Drm_Compositor));
55 if (!(_drm_comp->udev = udev_new()))
61 _drm_comp->base.display = disp;
62 if (!(_drm_comp->tty = e_tty_create(&_drm_comp->base, _cb_tty, 0)))
68 ue = udev_enumerate_new(_drm_comp->udev);
69 udev_enumerate_add_match_subsystem(ue, "drm");
70 udev_enumerate_add_match_sysname(ue, "card[0-9]*");
72 udev_enumerate_scan_devices(ue);
73 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(ue))
75 struct udev_device *dev;
76 const char *path = NULL;
78 path = udev_list_entry_get_name(entry);
79 dev = udev_device_new_from_syspath(_drm_comp->udev, path);
80 if (!(seat = udev_device_get_property_value(dev, "ID_SEAT")))
82 if (!strcmp(seat, "seat0"))
87 udev_device_unref(dev);
97 if (!_egl_init(_drm_comp, drm_dev))
103 /* _drm_comp->base.destroy = _cb_destroy; */
104 _drm_comp->base.focus = EINA_TRUE;
106 _drm_comp->prev_state = E_COMPOSITOR_STATE_ACTIVE;
108 glGenFramebuffers(1, &_drm_comp->base.fbo);
109 glBindFramebuffer(GL_FRAMEBUFFER, _drm_comp->base.fbo);
111 if (!e_compositor_init(&_drm_comp->base, disp))
117 wl_list_init(&_drm_comp->sprites);
118 _sprites_init(_drm_comp);
120 if (!_outputs_init(_drm_comp, 0, drm_dev))
126 udev_device_unref(drm_dev);
127 udev_enumerate_unref(ue);
129 e_evdev_input_create(&_drm_comp->base, _drm_comp->udev, seat);
131 loop = wl_display_get_event_loop(_drm_comp->base.display);
132 _drm_comp->drm_source =
133 wl_event_loop_add_fd(loop, _drm_comp->drm.fd, WL_EVENT_READABLE,
134 _cb_drm_input, _drm_comp);
136 _drm_comp->udev_monitor =
137 udev_monitor_new_from_netlink(_drm_comp->udev, "udev");
138 if (!_drm_comp->udev_monitor)
143 udev_monitor_filter_add_match_subsystem_devtype(_drm_comp->udev_monitor,
146 _drm_comp->udev_drm_source =
147 wl_event_loop_add_fd(loop, udev_monitor_get_fd(_drm_comp->udev_monitor),
148 WL_EVENT_READABLE, _cb_drm_udev_event, _drm_comp);
149 if (udev_monitor_enable_receiving(_drm_comp->udev_monitor) < 0)
155 return &_drm_comp->base;
159 e_modapi_shutdown(E_Module *m __UNUSED__)
161 E_Input_Device *input, *next;
163 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
165 e_compositor_shutdown(&_drm_comp->base);
166 gbm_device_destroy(_drm_comp->gbm);
167 _sprites_shutdown(_drm_comp);
168 drmDropMaster(_drm_comp->drm.fd);
169 e_tty_destroy(_drm_comp->tty);
171 wl_list_for_each_safe(input, next, &_drm_comp->base.inputs, link)
172 e_evdev_input_destroy(input);
181 e_modapi_save(E_Module *m __UNUSED__)
186 /* local function prototypes */
188 _cb_tty(E_Compositor *comp, int event)
191 E_Drm_Output *doutput;
193 E_Input_Device *input;
195 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
199 case 0: // TTY_ENTER_VT
200 comp->focus = EINA_TRUE;
201 if (drmSetMaster(_drm_comp->drm.fd))
203 printf("Failed to set master: %m\n");
204 wl_display_terminate(comp->display);
206 comp->state = _drm_comp->prev_state;
207 e_drm_output_set_modes(_drm_comp);
208 e_compositor_damage_all(comp);
209 wl_list_for_each(input, &comp->inputs, link)
210 e_evdev_add_devices(_drm_comp->udev, input);
212 case 1: // TTY_LEAVE_VT
213 comp->focus = EINA_FALSE;
214 _drm_comp->prev_state = comp->state;
215 comp->state = E_COMPOSITOR_STATE_SLEEPING;
216 wl_list_for_each(output, &comp->outputs, link)
218 output->repaint_needed = EINA_FALSE;
219 e_drm_output_set_cursor(output, NULL);
222 container_of(comp->outputs.next, E_Drm_Output, base.link);
224 wl_list_for_each(sprite, &_drm_comp->sprites, link)
225 drmModeSetPlane(_drm_comp->drm.fd, sprite->plane_id,
226 doutput->crtc_id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
228 wl_list_for_each(input, &comp->inputs, link)
229 e_evdev_remove_devices(input);
231 if (drmDropMaster(_drm_comp->drm.fd < 0))
232 printf("Failed to drop master: %m\n");
239 _cb_drm_input(int fd, unsigned int mask __UNUSED__, void *data __UNUSED__)
241 drmEventContext ectxt;
243 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
245 memset(&ectxt, 0, sizeof(ectxt));
247 ectxt.version = DRM_EVENT_CONTEXT_VERSION;
248 ectxt.page_flip_handler = _cb_drm_page_flip;
249 ectxt.vblank_handler = _cb_drm_vblank;
250 drmHandleEvent(fd, &ectxt);
256 _cb_drm_udev_event(int fd __UNUSED__, unsigned int mask __UNUSED__, void *data)
258 E_Drm_Compositor *dcomp;
259 struct udev_device *event;
261 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
263 if (!(dcomp = data)) return 1;
264 event = udev_monitor_receive_device(dcomp->udev_monitor);
265 if (_udev_event_is_hotplug(dcomp, event))
266 _outputs_update(dcomp, event);
267 udev_device_unref(event);
272 _cb_drm_page_flip(int fd __UNUSED__, unsigned int frame __UNUSED__, unsigned int sec, unsigned int usec, void *data)
274 E_Drm_Output *doutput;
275 E_Drm_Compositor *dcomp;
278 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
280 if (!(doutput = data)) return;
281 dcomp = (E_Drm_Compositor *)doutput->base.compositor;
283 if (doutput->scanout_buffer)
285 e_buffer_post_release(doutput->scanout_buffer);
286 wl_list_remove(&doutput->scanout_buffer_destroy_listener.link);
287 doutput->scanout_buffer = NULL;
288 drmModeRmFB(dcomp->drm.fd, doutput->fs_surf_fb_id);
289 doutput->fs_surf_fb_id = 0;
292 if (doutput->pending_scanout_buffer)
294 doutput->scanout_buffer = doutput->pending_scanout_buffer;
295 wl_list_remove(&doutput->pending_scanout_buffer_destroy_listener.link);
296 wl_signal_add(&doutput->scanout_buffer->resource.destroy_signal,
297 &doutput->scanout_buffer_destroy_listener);
298 doutput->pending_scanout_buffer = NULL;
299 doutput->fs_surf_fb_id = doutput->pending_fs_surf_fb_id;
300 doutput->pending_fs_surf_fb_id = 0;
303 msecs = sec * 1000 + usec / 1000;
304 e_output_finish_frame(&doutput->base, msecs);
308 _cb_drm_vblank(int fd __UNUSED__, unsigned int frame __UNUSED__, unsigned int sec __UNUSED__, unsigned int usec __UNUSED__, void *data)
311 E_Drm_Compositor *dcomp;
313 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
315 if (!(es = data)) return;
316 dcomp = es->compositor;
320 e_buffer_post_release(es->surface->buffer);
321 wl_list_remove(&es->destroy_listener.link);
323 drmModeRmFB(dcomp->drm.fd, es->fb_id);
327 if (es->pending_surface)
329 wl_list_remove(&es->pending_destroy_listener.link);
330 wl_signal_add(&es->pending_surface->buffer->resource.destroy_signal,
331 &es->destroy_listener);
332 es->surface = es->pending_surface;
333 es->pending_surface = NULL;
334 es->fb_id = es->pending_fb_id;
335 es->pending_fb_id = 0;
340 _egl_init(E_Drm_Compositor *dcomp, struct udev_device *dev)
343 const char *ext, *fname, *snum;
345 static const EGLint ctxt_att[] =
347 EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE
350 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
352 if ((snum = udev_device_get_sysnum(dev)))
353 dcomp->drm.id = atoi(snum);
354 if ((!snum) || (dcomp->drm.id < 0))
357 fname = udev_device_get_devnode(dev);
358 if (!(fd = open(fname, (O_RDWR | O_CLOEXEC))))
362 dcomp->gbm = gbm_create_device(dcomp->drm.fd);
364 // dcomp->base.egl_display = eglGetDisplay(dcomp->base.display);
365 dcomp->base.egl_display = eglGetDisplay(dcomp->gbm);
366 if (!dcomp->base.egl_display)
369 if (!eglInitialize(dcomp->base.egl_display, &maj, &min))
372 ext = eglQueryString(dcomp->base.egl_display, EGL_EXTENSIONS);
373 if (!strstr(ext, "EGL_KHR_surfaceless_gles2"))
376 if (!eglBindAPI(EGL_OPENGL_ES_API)) return EINA_FALSE;
378 dcomp->base.egl_context =
379 eglCreateContext(dcomp->base.egl_display, NULL, EGL_NO_CONTEXT, ctxt_att);
380 if (!dcomp->base.egl_context) return EINA_FALSE;
382 if (!eglMakeCurrent(dcomp->base.egl_display, EGL_NO_SURFACE,
383 EGL_NO_SURFACE, dcomp->base.egl_context))
390 _sprites_init(E_Drm_Compositor *dcomp)
393 drmModePlaneRes *res;
397 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
399 if (!(res = drmModeGetPlaneResources(dcomp->drm.fd)))
402 for (i = 0; i < res->count_planes; i++)
404 if (!(plane = drmModeGetPlane(dcomp->drm.fd, res->planes[i])))
406 if (!(es = e_sprite_create(dcomp, plane)))
411 drmModeFreePlane(plane);
412 wl_list_insert(&dcomp->sprites, &es->link);
419 _sprites_shutdown(E_Drm_Compositor *dcomp)
421 E_Drm_Output *doutput;
424 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
426 doutput = container_of(dcomp->base.outputs.next, E_Drm_Output, base.link);
428 wl_list_for_each_safe(es, next, &dcomp->sprites, link)
430 drmModeSetPlane(dcomp->drm.fd, es->plane_id, doutput->crtc_id,
431 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
432 drmModeRmFB(dcomp->drm.fd, es->fb_id);
438 _outputs_init(E_Drm_Compositor *dcomp, unsigned int conn, struct udev_device *drm_device)
440 drmModeConnector *connector;
442 int i = 0, x = 0, y = 0;
444 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
446 if (!(res = drmModeGetResources(dcomp->drm.fd)))
449 if (!(dcomp->crtcs = calloc(res->count_crtcs, sizeof(unsigned int))))
451 drmModeFreeResources(res);
455 dcomp->num_crtcs = res->count_crtcs;
456 memcpy(dcomp->crtcs, res->crtcs, sizeof(unsigned int) * dcomp->num_crtcs);
458 for (i = 0; i < res->count_connectors; i++)
461 drmModeGetConnector(dcomp->drm.fd, res->connectors[i])))
463 if ((connector->connection == DRM_MODE_CONNECTED) &&
464 ((conn == 0) || (connector->connector_id == conn)))
466 if (!_output_create(dcomp, res, connector, x, y, drm_device))
468 drmModeFreeConnector(connector);
471 x += container_of(dcomp->base.outputs.prev, E_Output,
474 drmModeFreeConnector(connector);
477 if (wl_list_empty(&dcomp->base.outputs))
479 drmModeFreeResources(res);
483 drmModeFreeResources(res);
489 _output_create(E_Drm_Compositor *dcomp, drmModeRes *res, drmModeConnector *conn, int x, int y, struct udev_device *drm_device)
491 E_Drm_Output *output;
492 E_Drm_Output_Mode *mode, *next;
493 drmModeEncoder *encoder;
495 unsigned int hdl, stride;
497 if (!(encoder = drmModeGetEncoder(dcomp->drm.fd, conn->encoders[0])))
500 for (i = 0; i < res->count_crtcs; i++)
502 if ((encoder->possible_crtcs & (1 << i)) &&
503 !(dcomp->crtc_alloc & (1 << res->crtcs[i])))
506 if (i == res->count_crtcs)
508 drmModeFreeEncoder(encoder);
512 if (!(output = malloc(sizeof(E_Drm_Output))))
514 drmModeFreeEncoder(encoder);
518 memset(output, 0, sizeof(E_Drm_Output));
520 output->fb_id[0] = -1;
521 output->fb_id[1] = -1;
522 output->base.subpixel = e_drm_output_subpixel_convert(conn->subpixel);
523 output->base.make = "unknown";
524 output->base.model = "unknown";
525 wl_list_init(&output->base.modes);
527 output->crtc_id = res->crtcs[i];
528 dcomp->crtc_alloc |= (1 << output->crtc_id);
529 output->conn_id = conn->connector_id;
530 dcomp->conn_alloc |= (1 << output->conn_id);
532 output->orig_crtc = drmModeGetCrtc(dcomp->drm.fd, output->crtc_id);
533 drmModeFreeEncoder(encoder);
535 for (i = 0; i < conn->count_modes; i++)
537 if (!e_drm_output_add_mode(output, &conn->modes[i]))
541 if (conn->count_modes == 0)
543 if (!e_drm_output_add_mode(output, &builtin_mode))
547 mode = container_of(output->base.modes.next, E_Drm_Output_Mode, base.link);
548 output->base.current = &mode->base;
549 mode->base.flags = (WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED);
551 glGenRenderbuffers(2, output->rbo);
553 for (i = 0; i < 2; i++)
555 glBindRenderbuffer(GL_RENDERBUFFER, output->rbo[i]);
557 gbm_bo_create(dcomp->gbm, output->base.current->w,
558 output->base.current->h, GBM_BO_FORMAT_XRGB8888,
559 (GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING));
560 if (!output->bo[i]) goto ebuffs;
562 dcomp->base.create_image(dcomp->base.egl_display, NULL,
563 EGL_NATIVE_PIXMAP_KHR, output->bo[i], NULL);
564 if (!output->image[i]) goto ebuffs;
565 dcomp->base.image_target_renderbuffer_storage(GL_RENDERBUFFER,
567 stride = gbm_bo_get_pitch(output->bo[i]);
568 hdl = gbm_bo_get_handle(output->bo[i]).u32;
569 ret = drmModeAddFB(dcomp->drm.fd, output->base.current->w,
570 output->base.current->h, 24, 32, stride, hdl,
572 if (ret) goto ebuffs;
576 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
577 GL_RENDERBUFFER, output->rbo[output->current]);
578 ret = drmModeSetCrtc(dcomp->drm.fd, output->crtc_id,
579 output->fb_id[output->current ^ 1], 0, 0,
580 &output->conn_id, 1, &mode->info);
583 /* TODO: backlight init */
585 e_output_init(&output->base, &dcomp->base, x, y,
586 conn->mmWidth, conn->mmHeight, 0);
588 wl_list_insert(dcomp->base.outputs.prev, &output->base.link);
590 output->scanout_buffer_destroy_listener.notify =
591 e_drm_output_scanout_buffer_destroy;
592 output->pending_scanout_buffer_destroy_listener.notify =
593 e_drm_output_pending_scanout_buffer_destroy;
595 output->pending_fs_surf_fb_id = 0;
596 output->base.repaint = e_drm_output_repaint;
597 output->base.destroy = e_drm_output_destroy;
598 output->base.assign_planes = e_drm_output_assign_planes;
599 output->base.set_dpms = e_drm_output_set_dpms;
604 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
608 for (i = 0; i < 2; i++)
610 if ((int)output->fb_id[i] != -1)
611 drmModeRmFB(dcomp->drm.fd, output->fb_id[i]);
612 if (output->image[i])
613 dcomp->base.destroy_image(dcomp->base.egl_display, output->image[i]);
614 if (output->bo[i]) gbm_bo_destroy(output->bo[i]);
616 glBindRenderbuffer(GL_RENDERBUFFER, 0);
617 glDeleteRenderbuffers(2, output->rbo);
620 wl_list_for_each_safe(mode, next, &output->base.modes, base.link)
622 wl_list_remove(&mode->base.link);
625 drmModeFreeCrtc(output->orig_crtc);
626 dcomp->crtc_alloc &= ~(1 << output->crtc_id);
627 dcomp->conn_alloc &= ~(1 << output->conn_id);
634 _outputs_update(E_Drm_Compositor *dcomp, struct udev_device *drm_device)
636 drmModeConnector *conn;
638 E_Drm_Output *doutput, *next;
641 unsigned int connected = 0, disconnects = 0;
644 if (!(res = drmModeGetResources(dcomp->drm.fd)))
647 for (i = 0; i < res->count_connectors; i++)
651 conn_id = res->connectors[i];
652 if (!(conn = drmModeGetConnector(dcomp->drm.fd, conn_id)))
654 if (conn->connection != DRM_MODE_CONNECTED)
656 drmModeFreeConnector(conn);
659 connected |= (1 << conn_id);
660 if (!(dcomp->conn_alloc & (1 << conn_id)))
664 last = container_of(dcomp->base.outputs.prev, E_Output, link);
665 if (!wl_list_empty(&dcomp->base.outputs))
666 x = last->x + last->current->w;
670 _output_create(dcomp, res, conn, x, y, drm_device);
672 drmModeFreeConnector(conn);
674 drmModeFreeResources(res);
676 if ((disconnects = dcomp->conn_alloc & ~connected))
678 wl_list_for_each_safe(doutput, next, &dcomp->base.outputs, base.link)
680 if ((xo != 0) || (yo != 0))
681 e_output_move(&doutput->base, doutput->base.x - xo,
682 doutput->base.y - yo);
683 if (disconnects & (1 << doutput->conn_id))
685 disconnects &= ~(1 << doutput->conn_id);
686 xo += doutput->base.current->w;
687 e_drm_output_destroy(&doutput->base);
692 if (dcomp->conn_alloc == 0)
693 wl_display_terminate(dcomp->base.display);
697 _udev_event_is_hotplug(E_Drm_Compositor *dcomp, struct udev_device *dev)
699 const char *snum, *val;
701 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
703 snum = udev_device_get_sysnum(dev);
704 if ((!snum) || (atoi(snum) != dcomp->drm.id))
707 if (!(val = udev_device_get_property_value(dev, "HOTPLUG")))
710 if (!strcmp(val, "1")) return EINA_TRUE;