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.
38 #include "shl_dlist.h"
42 #include "uterm_video.h"
43 #include "uterm_video_internal.h"
45 #define LOG_SUBSYSTEM "video"
48 const char *uterm_dpms_to_name(int dpms)
53 case UTERM_DPMS_STANDBY:
55 case UTERM_DPMS_SUSPEND:
65 bool uterm_video_available(const struct uterm_video_module *mod)
70 if (mod == UTERM_VIDEO_DRM2D || mod == UTERM_VIDEO_DRM3D)
71 return video_drm_available();
77 int mode_new(struct uterm_mode **out, const struct mode_ops *ops)
79 struct uterm_mode *mode;
85 mode = malloc(sizeof(*mode));
88 memset(mode, 0, sizeof(*mode));
92 ret = VIDEO_CALL(mode->ops->init, 0, mode);
105 void uterm_mode_ref(struct uterm_mode *mode)
107 if (!mode || !mode->ref)
114 void uterm_mode_unref(struct uterm_mode *mode)
116 if (!mode || !mode->ref || --mode->ref)
119 VIDEO_CALL(mode->ops->destroy, 0, mode);
124 int uterm_mode_bind(struct uterm_mode *mode, struct uterm_display *disp)
126 if (!mode || !disp || mode->disp)
130 shl_dlist_link_tail(&disp->modes, &mode->list);
131 uterm_mode_ref(mode);
137 void uterm_mode_unbind(struct uterm_mode *mode)
143 shl_dlist_unlink(&mode->list);
144 uterm_mode_unref(mode);
148 struct uterm_mode *uterm_mode_next(struct uterm_mode *mode)
150 if (!mode || mode->list.next == &mode->disp->modes)
153 return shl_dlist_entry(mode->list.next, struct uterm_mode, list);
157 const char *uterm_mode_get_name(const struct uterm_mode *mode)
162 return VIDEO_CALL(mode->ops->get_name, NULL, mode);
166 unsigned int uterm_mode_get_width(const struct uterm_mode *mode)
171 return VIDEO_CALL(mode->ops->get_width, 0, mode);
175 unsigned int uterm_mode_get_height(const struct uterm_mode *mode)
180 return VIDEO_CALL(mode->ops->get_height, 0, mode);
183 int display_schedule_vblank_timer(struct uterm_display *disp)
187 if (disp->vblank_scheduled)
190 ret = ev_timer_update(disp->vblank_timer, &disp->vblank_spec);
194 disp->vblank_scheduled = true;
198 void display_set_vblank_timer(struct uterm_display *disp,
206 disp->vblank_spec.it_value.tv_nsec = msecs * 1000 * 1000;
209 static void display_vblank_timer_event(struct ev_timer *timer,
210 uint64_t expirations,
213 struct uterm_display *disp = data;
215 disp->vblank_scheduled = false;
216 DISPLAY_CB(disp, UTERM_PAGE_FLIP);
219 int display_new(struct uterm_display **out, const struct display_ops *ops)
221 struct uterm_display *disp;
227 disp = malloc(sizeof(*disp));
230 memset(disp, 0, sizeof(*disp));
233 shl_dlist_init(&disp->modes);
235 log_info("new display %p", disp);
237 ret = shl_hook_new(&disp->hook);
241 disp->vblank_spec.it_value.tv_nsec = 15 * 1000 * 1000;
243 ret = ev_timer_new(&disp->vblank_timer, NULL,
244 display_vblank_timer_event, disp, NULL, NULL);
248 ret = VIDEO_CALL(disp->ops->init, 0, disp);
256 ev_timer_unref(disp->vblank_timer);
258 shl_hook_free(disp->hook);
265 void uterm_display_ref(struct uterm_display *disp)
267 if (!disp || !disp->ref)
274 void uterm_display_unref(struct uterm_display *disp)
276 struct uterm_mode *mode;
278 if (!disp || !disp->ref || --disp->ref)
281 log_info("free display %p", disp);
283 while (!shl_dlist_empty(&disp->modes)) {
284 mode = shl_dlist_entry(disp->modes.prev, struct uterm_mode,
286 uterm_mode_unbind(mode);
289 VIDEO_CALL(disp->ops->destroy, 0, disp);
290 ev_timer_unref(disp->vblank_timer);
291 shl_hook_free(disp->hook);
296 int uterm_display_bind(struct uterm_display *disp, struct uterm_video *video)
300 if (!disp || !video || disp->video)
303 ret = ev_eloop_add_timer(video->eloop, disp->vblank_timer);
307 shl_dlist_link_tail(&video->displays, &disp->list);
309 uterm_display_ref(disp);
310 VIDEO_CB(disp->video, disp, UTERM_NEW);
316 void uterm_display_unbind(struct uterm_display *disp)
318 if (!disp || !disp->video)
321 VIDEO_CB(disp->video, disp, UTERM_GONE);
322 uterm_display_deactivate(disp);
324 shl_dlist_unlink(&disp->list);
325 ev_eloop_rm_timer(disp->vblank_timer);
326 uterm_display_unref(disp);
330 struct uterm_display *uterm_display_next(struct uterm_display *disp)
332 if (!disp || !disp->video || disp->list.next == &disp->video->displays)
335 return shl_dlist_entry(disp->list.next, struct uterm_display, list);
339 int uterm_display_register_cb(struct uterm_display *disp, uterm_display_cb cb,
345 return shl_hook_add_cast(disp->hook, cb, data, false);
349 void uterm_display_unregister_cb(struct uterm_display *disp,
350 uterm_display_cb cb, void *data)
355 shl_hook_rm_cast(disp->hook, cb, data);
359 struct uterm_mode *uterm_display_get_modes(struct uterm_display *disp)
361 if (!disp || shl_dlist_empty(&disp->modes))
364 return shl_dlist_entry(disp->modes.next, struct uterm_mode, list);
368 struct uterm_mode *uterm_display_get_current(struct uterm_display *disp)
373 return disp->current_mode;
377 struct uterm_mode *uterm_display_get_default(struct uterm_display *disp)
382 return disp->default_mode;
386 int uterm_display_get_state(struct uterm_display *disp)
389 return UTERM_DISPLAY_GONE;
392 if (disp->flags & DISPLAY_ONLINE) {
393 if (disp->video->flags & VIDEO_AWAKE)
394 return UTERM_DISPLAY_ACTIVE;
396 return UTERM_DISPLAY_ASLEEP;
398 return UTERM_DISPLAY_INACTIVE;
401 return UTERM_DISPLAY_GONE;
406 int uterm_display_activate(struct uterm_display *disp, struct uterm_mode *mode)
408 if (!disp || !disp->video || display_is_online(disp) ||
409 !video_is_awake(disp->video))
413 mode = disp->default_mode;
415 return VIDEO_CALL(disp->ops->activate, 0, disp, mode);
419 void uterm_display_deactivate(struct uterm_display *disp)
421 if (!disp || !display_is_online(disp))
424 VIDEO_CALL(disp->ops->deactivate, 0, disp);
428 int uterm_display_set_dpms(struct uterm_display *disp, int state)
430 if (!disp || !display_is_online(disp) || !video_is_awake(disp->video))
433 return VIDEO_CALL(disp->ops->set_dpms, 0, disp, state);
437 int uterm_display_get_dpms(const struct uterm_display *disp)
439 if (!disp || !disp->video)
440 return UTERM_DPMS_OFF;
446 int uterm_display_use(struct uterm_display *disp, bool *opengl)
448 if (!disp || !display_is_online(disp))
451 return VIDEO_CALL(disp->ops->use, -EOPNOTSUPP, disp, opengl);
455 int uterm_display_get_buffers(struct uterm_display *disp,
456 struct uterm_video_buffer *buffer,
457 unsigned int formats)
459 if (!disp || !display_is_online(disp) || !buffer)
462 return VIDEO_CALL(disp->ops->get_buffers, -EOPNOTSUPP, disp, buffer,
467 int uterm_display_swap(struct uterm_display *disp, bool immediate)
469 if (!disp || !display_is_online(disp) || !video_is_awake(disp->video))
472 return VIDEO_CALL(disp->ops->swap, 0, disp, immediate);
476 bool uterm_display_is_swapping(struct uterm_display *disp)
481 return disp->vblank_scheduled || (disp->flags & DISPLAY_VSYNC);
485 int uterm_display_fill(struct uterm_display *disp,
486 uint8_t r, uint8_t g, uint8_t b,
487 unsigned int x, unsigned int y,
488 unsigned int width, unsigned int height)
490 if (!disp || !display_is_online(disp) || !video_is_awake(disp->video))
493 return VIDEO_CALL(disp->ops->fill, -EOPNOTSUPP, disp, r, g, b, x, y,
498 int uterm_display_blit(struct uterm_display *disp,
499 const struct uterm_video_buffer *buf,
500 unsigned int x, unsigned int y)
502 if (!disp || !display_is_online(disp) || !video_is_awake(disp->video))
505 return VIDEO_CALL(disp->ops->blit, -EOPNOTSUPP, disp, buf, x, y);
509 int uterm_display_fake_blend(struct uterm_display *disp,
510 const struct uterm_video_buffer *buf,
511 unsigned int x, unsigned int y,
512 uint8_t fr, uint8_t fg, uint8_t fb,
513 uint8_t br, uint8_t bg, uint8_t bb)
515 struct uterm_video_blend_req req;
517 if (!disp || !display_is_online(disp) || !video_is_awake(disp->video))
520 memset(&req, 0, sizeof(req));
531 return VIDEO_CALL(disp->ops->fake_blendv, -EOPNOTSUPP, disp, &req, 1);
535 int uterm_display_fake_blendv(struct uterm_display *disp,
536 const struct uterm_video_blend_req *req,
539 if (!disp || !display_is_online(disp) || !video_is_awake(disp->video))
542 return VIDEO_CALL(disp->ops->fake_blendv, -EOPNOTSUPP, disp, req, num);
546 int uterm_video_new(struct uterm_video **out, struct ev_eloop *eloop,
547 const char *node, const struct uterm_video_module *mod)
549 struct uterm_video *video;
554 if (!mod || !mod->ops)
557 video = malloc(sizeof(*video));
560 memset(video, 0, sizeof(*video));
563 video->ops = mod->ops;
564 video->eloop = eloop;
565 shl_dlist_init(&video->displays);
567 ret = shl_hook_new(&video->hook);
571 ret = VIDEO_CALL(video->ops->init, 0, video, node);
575 ev_eloop_ref(video->eloop);
576 log_info("new device %p", video);
581 shl_hook_free(video->hook);
588 void uterm_video_ref(struct uterm_video *video)
590 if (!video || !video->ref)
597 void uterm_video_unref(struct uterm_video *video)
599 struct uterm_display *disp;
601 if (!video || !video->ref || --video->ref)
604 log_info("free device %p", video);
606 while (!shl_dlist_empty(&video->displays)) {
607 disp = shl_dlist_entry(video->displays.prev,
608 struct uterm_display, list);
609 uterm_display_unbind(disp);
612 VIDEO_CALL(video->ops->destroy, 0, video);
613 shl_hook_free(video->hook);
614 ev_eloop_unref(video->eloop);
619 void uterm_video_segfault(struct uterm_video *video)
624 VIDEO_CALL(video->ops->segfault, 0, video);
628 struct uterm_display *uterm_video_get_displays(struct uterm_video *video)
630 if (!video || shl_dlist_empty(&video->displays))
633 return shl_dlist_entry(video->displays.next, struct uterm_display,
638 int uterm_video_register_cb(struct uterm_video *video, uterm_video_cb cb,
644 return shl_hook_add_cast(video->hook, cb, data, false);
648 void uterm_video_unregister_cb(struct uterm_video *video, uterm_video_cb cb,
654 shl_hook_rm_cast(video->hook, cb, data);
658 void uterm_video_sleep(struct uterm_video *video)
660 if (!video || !video_is_awake(video))
663 log_debug("go asleep");
665 VIDEO_CB(video, NULL, UTERM_SLEEP);
666 video->flags &= ~VIDEO_AWAKE;
667 VIDEO_CALL(video->ops->sleep, 0, video);
671 int uterm_video_wake_up(struct uterm_video *video)
677 if (video_is_awake(video))
680 log_debug("wake up");
682 ret = VIDEO_CALL(video->ops->wake_up, 0, video);
684 video->flags &= ~VIDEO_AWAKE;
688 video->flags |= VIDEO_AWAKE;
689 VIDEO_CB(video, NULL, UTERM_WAKE_UP);
694 bool uterm_video_is_awake(struct uterm_video *video)
696 return video && video_is_awake(video);
700 void uterm_video_poll(struct uterm_video *video)
705 VIDEO_CALL(video->ops->poll, 0, video);