2 * uterm - Linux User-Space Terminal
4 * Copyright (c) 2011-2013 David Herrmann <dh.herrmann@googlemail.com>
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files
8 * (the "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 * Core Implementation of the uterm_video and uterm_display objects.
39 #include "shl_dlist.h"
41 #include "uterm_video.h"
42 #include "uterm_video_internal.h"
44 #define LOG_SUBSYSTEM "video"
46 const char *uterm_dpms_to_name(int dpms)
51 case UTERM_DPMS_STANDBY:
53 case UTERM_DPMS_SUSPEND:
62 bool uterm_video_available(const struct uterm_video_module *mod)
67 if (mod == UTERM_VIDEO_DRM2D || mod == UTERM_VIDEO_DRM3D)
68 return video_drm_available();
73 int mode_new(struct uterm_mode **out, const struct mode_ops *ops)
75 struct uterm_mode *mode;
81 mode = malloc(sizeof(*mode));
84 memset(mode, 0, sizeof(*mode));
88 ret = VIDEO_CALL(mode->ops->init, 0, mode);
100 void uterm_mode_ref(struct uterm_mode *mode)
102 if (!mode || !mode->ref)
108 void uterm_mode_unref(struct uterm_mode *mode)
110 if (!mode || !mode->ref || --mode->ref)
113 VIDEO_CALL(mode->ops->destroy, 0, mode);
117 int uterm_mode_bind(struct uterm_mode *mode, struct uterm_display *disp)
119 if (!mode || !disp || mode->disp)
123 shl_dlist_link_tail(&disp->modes, &mode->list);
124 uterm_mode_ref(mode);
129 void uterm_mode_unbind(struct uterm_mode *mode)
135 shl_dlist_unlink(&mode->list);
136 uterm_mode_unref(mode);
139 struct uterm_mode *uterm_mode_next(struct uterm_mode *mode)
141 if (!mode || mode->list.next == &mode->disp->modes)
144 return shl_dlist_entry(mode->list.next, struct uterm_mode, list);
147 const char *uterm_mode_get_name(const struct uterm_mode *mode)
152 return VIDEO_CALL(mode->ops->get_name, NULL, mode);
155 unsigned int uterm_mode_get_width(const struct uterm_mode *mode)
160 return VIDEO_CALL(mode->ops->get_width, 0, mode);
163 unsigned int uterm_mode_get_height(const struct uterm_mode *mode)
168 return VIDEO_CALL(mode->ops->get_height, 0, mode);
171 int display_schedule_vblank_timer(struct uterm_display *disp)
175 if (disp->vblank_scheduled)
178 ret = ev_timer_update(disp->vblank_timer, &disp->vblank_spec);
182 disp->vblank_scheduled = true;
186 void display_set_vblank_timer(struct uterm_display *disp,
194 disp->vblank_spec.it_value.tv_nsec = msecs * 1000 * 1000;
197 static void display_vblank_timer_event(struct ev_timer *timer,
198 uint64_t expirations,
201 struct uterm_display *disp = data;
203 disp->vblank_scheduled = false;
204 DISPLAY_CB(disp, UTERM_PAGE_FLIP);
207 int display_new(struct uterm_display **out, const struct display_ops *ops)
209 struct uterm_display *disp;
215 disp = malloc(sizeof(*disp));
218 memset(disp, 0, sizeof(*disp));
221 shl_dlist_init(&disp->modes);
223 log_info("new display %p", disp);
225 ret = shl_hook_new(&disp->hook);
229 disp->vblank_spec.it_value.tv_nsec = 15 * 1000 * 1000;
231 ret = ev_timer_new(&disp->vblank_timer, NULL,
232 display_vblank_timer_event, disp, NULL);
236 ret = VIDEO_CALL(disp->ops->init, 0, disp);
244 ev_timer_unref(disp->vblank_timer);
246 shl_hook_free(disp->hook);
252 void uterm_display_ref(struct uterm_display *disp)
254 if (!disp || !disp->ref)
260 void uterm_display_unref(struct uterm_display *disp)
262 struct uterm_mode *mode;
264 if (!disp || !disp->ref || --disp->ref)
267 log_info("free display %p", disp);
269 while (!shl_dlist_empty(&disp->modes)) {
270 mode = shl_dlist_entry(disp->modes.prev, struct uterm_mode,
272 uterm_mode_unbind(mode);
275 VIDEO_CALL(disp->ops->destroy, 0, disp);
276 ev_timer_unref(disp->vblank_timer);
277 shl_hook_free(disp->hook);
281 int uterm_display_bind(struct uterm_display *disp, struct uterm_video *video)
285 if (!disp || !video || disp->video)
288 ret = ev_eloop_add_timer(video->eloop, disp->vblank_timer);
292 shl_dlist_link_tail(&video->displays, &disp->list);
294 uterm_display_ref(disp);
295 VIDEO_CB(disp->video, disp, UTERM_NEW);
300 void uterm_display_unbind(struct uterm_display *disp)
302 if (!disp || !disp->video)
305 VIDEO_CB(disp->video, disp, UTERM_GONE);
306 uterm_display_deactivate(disp);
308 shl_dlist_unlink(&disp->list);
309 ev_eloop_rm_timer(disp->vblank_timer);
310 uterm_display_unref(disp);
313 struct uterm_display *uterm_display_next(struct uterm_display *disp)
315 if (!disp || !disp->video || disp->list.next == &disp->video->displays)
318 return shl_dlist_entry(disp->list.next, struct uterm_display, list);
321 int uterm_display_register_cb(struct uterm_display *disp, uterm_display_cb cb,
327 return shl_hook_add_cast(disp->hook, cb, data, false);
330 void uterm_display_unregister_cb(struct uterm_display *disp,
331 uterm_display_cb cb, void *data)
336 shl_hook_rm_cast(disp->hook, cb, data);
339 struct uterm_mode *uterm_display_get_modes(struct uterm_display *disp)
341 if (!disp || shl_dlist_empty(&disp->modes))
344 return shl_dlist_entry(disp->modes.next, struct uterm_mode, list);
347 struct uterm_mode *uterm_display_get_current(struct uterm_display *disp)
352 return disp->current_mode;
355 struct uterm_mode *uterm_display_get_default(struct uterm_display *disp)
360 return disp->default_mode;
363 int uterm_display_get_state(struct uterm_display *disp)
366 return UTERM_DISPLAY_GONE;
369 if (disp->flags & DISPLAY_ONLINE) {
370 if (disp->video->flags & VIDEO_AWAKE)
371 return UTERM_DISPLAY_ACTIVE;
373 return UTERM_DISPLAY_ASLEEP;
375 return UTERM_DISPLAY_INACTIVE;
378 return UTERM_DISPLAY_GONE;
382 int uterm_display_activate(struct uterm_display *disp, struct uterm_mode *mode)
384 if (!disp || !disp->video || display_is_online(disp) ||
385 !video_is_awake(disp->video))
389 mode = disp->default_mode;
391 return VIDEO_CALL(disp->ops->activate, 0, disp, mode);
394 void uterm_display_deactivate(struct uterm_display *disp)
396 if (!disp || !display_is_online(disp))
399 VIDEO_CALL(disp->ops->deactivate, 0, disp);
402 int uterm_display_set_dpms(struct uterm_display *disp, int state)
404 if (!disp || !display_is_online(disp) || !video_is_awake(disp->video))
407 return VIDEO_CALL(disp->ops->set_dpms, 0, disp, state);
410 int uterm_display_get_dpms(const struct uterm_display *disp)
412 if (!disp || !disp->video)
413 return UTERM_DPMS_OFF;
418 int uterm_display_use(struct uterm_display *disp, bool *opengl)
420 if (!disp || !display_is_online(disp))
423 return VIDEO_CALL(disp->ops->use, -EOPNOTSUPP, disp, opengl);
426 int uterm_display_get_buffers(struct uterm_display *disp,
427 struct uterm_video_buffer *buffer,
428 unsigned int formats)
430 if (!disp || !display_is_online(disp) || !buffer)
433 return VIDEO_CALL(disp->ops->get_buffers, -EOPNOTSUPP, disp, buffer,
437 int uterm_display_swap(struct uterm_display *disp, bool immediate)
439 if (!disp || !display_is_online(disp) || !video_is_awake(disp->video))
442 return VIDEO_CALL(disp->ops->swap, 0, disp, immediate);
445 bool uterm_display_is_swapping(struct uterm_display *disp)
450 return disp->vblank_scheduled || (disp->flags & DISPLAY_VSYNC);
453 int uterm_display_fill(struct uterm_display *disp,
454 uint8_t r, uint8_t g, uint8_t b,
455 unsigned int x, unsigned int y,
456 unsigned int width, unsigned int height)
458 if (!disp || !display_is_online(disp) || !video_is_awake(disp->video))
461 return VIDEO_CALL(disp->ops->fill, -EOPNOTSUPP, disp, r, g, b, x, y,
465 int uterm_display_blit(struct uterm_display *disp,
466 const struct uterm_video_buffer *buf,
467 unsigned int x, unsigned int y)
469 if (!disp || !display_is_online(disp) || !video_is_awake(disp->video))
472 return VIDEO_CALL(disp->ops->blit, -EOPNOTSUPP, disp, buf, x, y);
475 int uterm_display_fake_blend(struct uterm_display *disp,
476 const struct uterm_video_buffer *buf,
477 unsigned int x, unsigned int y,
478 uint8_t fr, uint8_t fg, uint8_t fb,
479 uint8_t br, uint8_t bg, uint8_t bb)
481 struct uterm_video_blend_req req;
483 if (!disp || !display_is_online(disp) || !video_is_awake(disp->video))
486 memset(&req, 0, sizeof(req));
497 return VIDEO_CALL(disp->ops->fake_blendv, -EOPNOTSUPP, disp, &req, 1);
500 int uterm_display_fake_blendv(struct uterm_display *disp,
501 const struct uterm_video_blend_req *req,
504 if (!disp || !display_is_online(disp) || !video_is_awake(disp->video))
507 return VIDEO_CALL(disp->ops->fake_blendv, -EOPNOTSUPP, disp, req, num);
510 int uterm_video_new(struct uterm_video **out, struct ev_eloop *eloop,
511 const char *node, const struct uterm_video_module *mod)
513 struct uterm_video *video;
518 if (!mod || !mod->ops)
521 video = malloc(sizeof(*video));
524 memset(video, 0, sizeof(*video));
527 video->ops = mod->ops;
528 video->eloop = eloop;
529 shl_dlist_init(&video->displays);
531 ret = shl_hook_new(&video->hook);
535 ret = VIDEO_CALL(video->ops->init, 0, video, node);
539 ev_eloop_ref(video->eloop);
540 log_info("new device %p", video);
545 shl_hook_free(video->hook);
551 void uterm_video_ref(struct uterm_video *video)
553 if (!video || !video->ref)
559 void uterm_video_unref(struct uterm_video *video)
561 struct uterm_display *disp;
563 if (!video || !video->ref || --video->ref)
566 log_info("free device %p", video);
568 while (!shl_dlist_empty(&video->displays)) {
569 disp = shl_dlist_entry(video->displays.prev,
570 struct uterm_display, list);
571 uterm_display_unbind(disp);
574 VIDEO_CALL(video->ops->destroy, 0, video);
575 shl_hook_free(video->hook);
576 ev_eloop_unref(video->eloop);
580 void uterm_video_segfault(struct uterm_video *video)
585 VIDEO_CALL(video->ops->segfault, 0, video);
588 struct uterm_display *uterm_video_get_displays(struct uterm_video *video)
590 if (!video || shl_dlist_empty(&video->displays))
593 return shl_dlist_entry(video->displays.next, struct uterm_display,
597 int uterm_video_register_cb(struct uterm_video *video, uterm_video_cb cb,
603 return shl_hook_add_cast(video->hook, cb, data, false);
606 void uterm_video_unregister_cb(struct uterm_video *video, uterm_video_cb cb,
612 shl_hook_rm_cast(video->hook, cb, data);
615 void uterm_video_sleep(struct uterm_video *video)
617 if (!video || !video_is_awake(video))
620 log_debug("go asleep");
622 VIDEO_CB(video, NULL, UTERM_SLEEP);
623 video->flags &= ~VIDEO_AWAKE;
624 VIDEO_CALL(video->ops->sleep, 0, video);
627 int uterm_video_wake_up(struct uterm_video *video)
633 if (video_is_awake(video))
636 log_debug("wake up");
638 ret = VIDEO_CALL(video->ops->wake_up, 0, video);
640 video->flags &= ~VIDEO_AWAKE;
644 video->flags |= VIDEO_AWAKE;
645 VIDEO_CB(video, NULL, UTERM_WAKE_UP);
649 bool uterm_video_is_awake(struct uterm_video *video)
651 return video && video_is_awake(video);
654 void uterm_video_poll(struct uterm_video *video)
659 VIDEO_CALL(video->ops->poll, 0, video);