diff options
-rw-r--r-- | src/uterm_drm_shared.c | 156 | ||||
-rw-r--r-- | src/uterm_drm_shared_internal.h | 4 | ||||
-rw-r--r-- | src/uterm_fbdev_internal.h | 10 | ||||
-rw-r--r-- | src/uterm_fbdev_render.c | 15 | ||||
-rw-r--r-- | src/uterm_fbdev_video.c | 373 | ||||
-rw-r--r-- | src/uterm_video.c | 140 | ||||
-rw-r--r-- | src/uterm_video_drm.c | 46 | ||||
-rw-r--r-- | src/uterm_video_dumb.c | 45 | ||||
-rw-r--r-- | src/uterm_video_internal.h | 24 |
9 files changed, 392 insertions, 421 deletions
diff --git a/src/uterm_drm_shared.c b/src/uterm_drm_shared.c index 3a55b05..90069de 100644 --- a/src/uterm_drm_shared.c +++ b/src/uterm_drm_shared.c @@ -285,12 +285,8 @@ int uterm_drm_display_set_dpms(struct uterm_display *disp, int state) { int ret; struct uterm_drm_display *ddrm = disp->data; - struct uterm_drm_video *vdrm; - - if (!display_is_conn(disp) || !video_is_awake(disp->video)) - return -EINVAL; + struct uterm_drm_video *vdrm = disp->video->data; - vdrm = disp->video->data; log_info("setting DPMS of display %p to %s", disp, uterm_dpms_to_name(state)); @@ -302,53 +298,6 @@ int uterm_drm_display_set_dpms(struct uterm_display *disp, int state) return 0; } -int uterm_drm_display_bind(struct uterm_video *video, - struct uterm_display *disp, drmModeRes *res, - drmModeConnector *conn, int fd) -{ - struct uterm_mode *mode; - int ret, i; - struct uterm_drm_display *ddrm = disp->data; - - for (i = 0; i < conn->count_modes; ++i) { - ret = mode_new(&mode, &uterm_drm_mode_ops); - if (ret) - continue; - uterm_drm_mode_set(mode, &conn->modes[i]); - mode->next = disp->modes; - disp->modes = mode; - - /* TODO: more sophisticated default-mode selection */ - if (!disp->default_mode) - disp->default_mode = mode; - } - - if (!disp->modes) { - log_warn("no valid mode for display found"); - return -EFAULT; - } - - ddrm->conn_id = conn->connector_id; - disp->flags |= DISPLAY_AVAILABLE; - disp->next = video->displays; - video->displays = disp; - disp->dpms = uterm_drm_get_dpms(fd, conn); - - log_info("display %p DPMS is %s", disp, - uterm_dpms_to_name(disp->dpms)); - - VIDEO_CB(video, disp, UTERM_NEW); - return 0; -} - -void uterm_drm_display_unbind(struct uterm_display *disp) -{ - VIDEO_CB(disp->video, disp, UTERM_GONE); - uterm_display_deactivate(disp); - disp->video = NULL; - disp->flags &= ~DISPLAY_AVAILABLE; -} - static void event(struct ev_fd *fd, int mask, void *data) { struct uterm_video *video = data; @@ -427,16 +376,20 @@ int uterm_drm_video_find_crtc(struct uterm_video *video, drmModeRes *res, int i, crtc; struct uterm_display *iter; struct uterm_drm_display *ddrm; + struct shl_dlist *it; for (i = 0; i < res->count_crtcs; ++i) { if (enc->possible_crtcs & (1 << i)) { crtc = res->crtcs[i]; - for (iter = video->displays; iter; iter = iter->next) { + shl_dlist_for_each(it, &video->displays) { + iter = shl_dlist_entry(it, + struct uterm_display, + list); ddrm = iter->data; if (ddrm->crtc_id == crtc) break; } - if (!iter) + if (it == &video->displays) return crtc; } } @@ -450,26 +403,58 @@ static void bind_display(struct uterm_video *video, drmModeRes *res, { struct uterm_drm_video *vdrm = video->data; struct uterm_display *disp; - int ret; + struct uterm_drm_display *ddrm; + struct uterm_mode *mode; + int ret, i; - ret = display_new(&disp, ops, video); + ret = display_new(&disp, ops); if (ret) return; + ddrm = disp->data; - ret = uterm_drm_display_bind(video, disp, res, conn, vdrm->fd); - if (ret) { - uterm_display_unref(disp); - return; + for (i = 0; i < conn->count_modes; ++i) { + ret = mode_new(&mode, &uterm_drm_mode_ops); + if (ret) + continue; + + uterm_drm_mode_set(mode, &conn->modes[i]); + + ret = uterm_mode_bind(mode, disp); + if (ret) { + uterm_mode_unref(mode); + continue; + } + + /* TODO: more sophisticated default-mode selection */ + if (!disp->default_mode) + disp->default_mode = mode; + + uterm_mode_unref(mode); } -} -static void unbind_display(struct uterm_display *disp) -{ - if (!display_is_conn(disp)) - return; + if (shl_dlist_empty(&disp->modes)) { + log_warn("no valid mode for display found"); + ret = -EFAULT; + goto err_unref; + } + + ddrm->conn_id = conn->connector_id; + disp->flags |= DISPLAY_AVAILABLE; + disp->dpms = uterm_drm_get_dpms(vdrm->fd, conn); + + log_info("display %p DPMS is %s", disp, + uterm_dpms_to_name(disp->dpms)); + + ret = uterm_display_bind(disp, video); + if (ret) + goto err_unref; - uterm_drm_display_unbind(disp); uterm_display_unref(disp); + return; + +err_unref: + uterm_display_unref(disp); + return; } int uterm_drm_video_hotplug(struct uterm_video *video, @@ -478,9 +463,10 @@ int uterm_drm_video_hotplug(struct uterm_video *video, struct uterm_drm_video *vdrm = video->data; drmModeRes *res; drmModeConnector *conn; - struct uterm_display *disp, *tmp; + struct uterm_display *disp; struct uterm_drm_display *ddrm; int i; + struct shl_dlist *iter, *tmp; if (!video_is_awake(video) || !video_need_hotplug(video)) return 0; @@ -491,22 +477,28 @@ int uterm_drm_video_hotplug(struct uterm_video *video, return -EACCES; } - for (disp = video->displays; disp; disp = disp->next) + shl_dlist_for_each(iter, &video->displays) { + disp = shl_dlist_entry(iter, struct uterm_display, list); disp->flags &= ~DISPLAY_AVAILABLE; + } for (i = 0; i < res->count_connectors; ++i) { conn = drmModeGetConnector(vdrm->fd, res->connectors[i]); if (!conn) continue; if (conn->connection == DRM_MODE_CONNECTED) { - for (disp = video->displays; disp; disp = disp->next) { + shl_dlist_for_each(iter, &video->displays) { + disp = shl_dlist_entry(iter, + struct uterm_display, + list); ddrm = disp->data; + if (ddrm->conn_id == res->connectors[i]) { disp->flags |= DISPLAY_AVAILABLE; break; } } - if (!disp) + if (iter == &video->displays) bind_display(video, res, conn, ops); } drmModeFreeConnector(conn); @@ -514,24 +506,10 @@ int uterm_drm_video_hotplug(struct uterm_video *video, drmModeFreeResources(res); - while (video->displays) { - tmp = video->displays; - if (tmp->flags & DISPLAY_AVAILABLE) - break; - - video->displays = tmp->next; - tmp->next = NULL; - unbind_display(tmp); - } - for (disp = video->displays; disp && disp->next; ) { - tmp = disp->next; - if (tmp->flags & DISPLAY_AVAILABLE) { - disp = tmp; - } else { - disp->next = tmp->next; - tmp->next = NULL; - unbind_display(tmp); - } + shl_dlist_for_each_safe(iter, tmp, &video->displays) { + disp = shl_dlist_entry(iter, struct uterm_display, list); + if (!(disp->flags & DISPLAY_AVAILABLE)) + uterm_display_unbind(disp); } video->flags &= ~VIDEO_HOTPLUG; @@ -553,7 +531,6 @@ int uterm_drm_video_wake_up(struct uterm_video *video, video->flags |= VIDEO_AWAKE; ret = uterm_drm_video_hotplug(video, ops); if (ret) { - video->flags &= ~VIDEO_AWAKE; drmDropMaster(vdrm->fd); return ret; } @@ -566,7 +543,6 @@ void uterm_drm_video_sleep(struct uterm_video *video) struct uterm_drm_video *vdrm = video->data; drmDropMaster(vdrm->fd); - video->flags &= ~VIDEO_AWAKE; } int uterm_drm_video_poll(struct uterm_video *video, diff --git a/src/uterm_drm_shared_internal.h b/src/uterm_drm_shared_internal.h index 6b857c2..199d5b3 100644 --- a/src/uterm_drm_shared_internal.h +++ b/src/uterm_drm_shared_internal.h @@ -75,10 +75,6 @@ int uterm_drm_display_init(struct uterm_display *disp, void *data); void uterm_drm_display_destroy(struct uterm_display *disp); int uterm_drm_display_activate(struct uterm_display *disp, int fd); void uterm_drm_display_deactivate(struct uterm_display *disp, int fd); -int uterm_drm_display_bind(struct uterm_video *video, - struct uterm_display *disp, drmModeRes *res, - drmModeConnector *conn, int fd); -void uterm_drm_display_unbind(struct uterm_display *disp); int uterm_drm_display_set_dpms(struct uterm_display *disp, int state); static inline void *uterm_drm_display_get_data(struct uterm_display *disp) diff --git a/src/uterm_fbdev_internal.h b/src/uterm_fbdev_internal.h index c4257c7..b0ac72e 100644 --- a/src/uterm_fbdev_internal.h +++ b/src/uterm_fbdev_internal.h @@ -41,13 +41,11 @@ struct fbdev_mode { }; struct fbdev_display { - char *node; int fd; - bool pending_intro; - struct fb_fix_screeninfo finfo; struct fb_var_screeninfo vinfo; unsigned int rate; + const char *node; unsigned int bufid; size_t xres; @@ -69,6 +67,12 @@ struct fbdev_display { int_fast32_t dither_b; }; +struct fbdev_video { + char *node; + bool pending_intro; + struct uterm_display *disp; +}; + int uterm_fbdev_display_blit(struct uterm_display *disp, const struct uterm_video_buffer *buf, unsigned int x, unsigned int y); diff --git a/src/uterm_fbdev_render.c b/src/uterm_fbdev_render.c index f441153..ad96ad3 100644 --- a/src/uterm_fbdev_render.c +++ b/src/uterm_fbdev_render.c @@ -110,11 +110,7 @@ int uterm_fbdev_display_blit(struct uterm_display *disp, uint32_t val; struct fbdev_display *fbdev = disp->data; - if (!disp->video || !(disp->flags & DISPLAY_ONLINE)) - return -EINVAL; - if (!buf || !video_is_awake(disp->video)) - return -EINVAL; - if (buf->format != UTERM_FORMAT_XRGB32) + if (!buf || buf->format != UTERM_FORMAT_XRGB32) return -EINVAL; tmp = x + buf->width; @@ -182,9 +178,7 @@ int uterm_fbdev_display_fake_blendv(struct uterm_display *disp, uint32_t val; struct fbdev_display *fbdev = disp->data; - if (!disp->video || !(disp->flags & DISPLAY_ONLINE)) - return -EINVAL; - if (!req || !video_is_awake(disp->video)) + if (!req) return -EINVAL; for (j = 0; j < num; ++j, ++req) { @@ -325,11 +319,6 @@ int uterm_fbdev_display_fill(struct uterm_display *disp, uint32_t full_val, rgb32; struct fbdev_display *fbdev = disp->data; - if (!disp->video || !(disp->flags & DISPLAY_ONLINE)) - return -EINVAL; - if (!video_is_awake(disp->video)) - return -EINVAL; - tmp = x + width; if (tmp < x || x >= fbdev->xres) return -EINVAL; diff --git a/src/uterm_fbdev_video.c b/src/uterm_fbdev_video.c index 59e9db6..df5649f 100644 --- a/src/uterm_fbdev_video.c +++ b/src/uterm_fbdev_video.c @@ -88,18 +88,37 @@ static const struct mode_ops fbdev_mode_ops = { .get_height = mode_get_height, }; +static int display_init(struct uterm_display *disp) +{ + struct fbdev_display *fbdev; + + fbdev = malloc(sizeof(*fbdev)); + if (!fbdev) + return -ENOMEM; + memset(fbdev, 0, sizeof(*fbdev)); + disp->data = fbdev; + disp->dpms = UTERM_DPMS_UNKNOWN; + + return 0; +} + +static void display_destroy(struct uterm_display *disp) +{ + free(disp->data); +} + static int refresh_info(struct uterm_display *disp) { int ret; - struct fbdev_display *fbdev = disp->data; + struct fbdev_display *dfb = disp->data; - ret = ioctl(fbdev->fd, FBIOGET_FSCREENINFO, &fbdev->finfo); + ret = ioctl(dfb->fd, FBIOGET_FSCREENINFO, &dfb->finfo); if (ret) { log_err("cannot get finfo (%d): %m", errno); return -EFAULT; } - ret = ioctl(fbdev->fd, FBIOGET_VSCREENINFO, &fbdev->vinfo); + ret = ioctl(dfb->fd, FBIOGET_VSCREENINFO, &dfb->vinfo); if (ret) { log_err("cannot get vinfo (%d): %m", errno); return -EFAULT; @@ -115,18 +134,16 @@ static int display_activate_force(struct uterm_display *disp, /* TODO: Add support for 24-bpp. However, we need to check how 3-bytes * integers are assembled in big/little/mixed endian systems. */ static const char depths[] = { 32, 16, 0 }; + struct fbdev_display *dfb = disp->data; + struct uterm_mode *m; + struct fbdev_mode *mfb; struct fb_var_screeninfo *vinfo; struct fb_fix_screeninfo *finfo; int ret, i; uint64_t quot; size_t len; unsigned int val; - struct fbdev_display *fbdev = disp->data; - struct fbdev_mode *fbdev_mode; - struct uterm_mode *m; - if (!disp->video || !video_is_awake(disp->video)) - return -EINVAL; if (!force && (disp->flags & DISPLAY_ONLINE)) return 0; @@ -137,12 +154,18 @@ static int display_activate_force(struct uterm_display *disp, if (mode) return -EINVAL; + dfb->fd = open(dfb->node, O_RDWR | O_CLOEXEC | O_NONBLOCK); + if (dfb->fd < 0) { + log_err("cannot open %s (%d): %m", dfb->node, errno); + return -EFAULT; + } + ret = refresh_info(disp); if (ret) - return ret; + goto err_close; - finfo = &fbdev->finfo; - vinfo = &fbdev->vinfo; + finfo = &dfb->finfo; + vinfo = &dfb->vinfo; vinfo->xoffset = 0; vinfo->yoffset = 0; @@ -165,25 +188,25 @@ static int display_activate_force(struct uterm_display *disp, vinfo->yres_virtual = vinfo->yres; } - ret = ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, vinfo); + ret = ioctl(dfb->fd, FBIOPUT_VSCREENINFO, vinfo); if (ret) { disp->flags &= ~DISPLAY_DBUF; vinfo->yres_virtual = vinfo->yres; - ret = ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, vinfo); + ret = ioctl(dfb->fd, FBIOPUT_VSCREENINFO, vinfo); if (ret) { log_debug("cannot reset fb offsets (%d): %m", errno); - return -EFAULT; + goto err_close; } } if (disp->flags & DISPLAY_DBUF) - log_debug("enabling double buffering"); + log_debug("enable double buffering"); else - log_debug("disabling double buffering"); + log_debug("disable double buffering"); ret = refresh_info(disp); if (ret) - return ret; + goto err_close; /* We require TRUECOLOR mode here. That is, each pixel has a color value * that is split into rgba values that we can set directly. Other visual @@ -196,51 +219,54 @@ static int display_activate_force(struct uterm_display *disp, vinfo->bits_per_pixel = depths[i]; vinfo->activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; - ret = ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, + ret = ioctl(dfb->fd, FBIOPUT_VSCREENINFO, vinfo); if (ret < 0) continue; ret = refresh_info(disp); if (ret) - return ret; + goto err_close; if (finfo->visual == FB_VISUAL_TRUECOLOR) break; } } + if (vinfo->bits_per_pixel != 32 && + vinfo->bits_per_pixel != 16) { + log_error("device %s does not support 16/32 bpp but: %u", + dfb->node, vinfo->bits_per_pixel); + ret = -EFAULT; + goto err_close; + } + if (vinfo->xres_virtual < vinfo->xres || (disp->flags & DISPLAY_DBUF && vinfo->yres_virtual < vinfo->yres * 2) || vinfo->yres_virtual < vinfo->yres) { log_warning("device %s has weird virtual buffer sizes (%d %d %d %d)", - fbdev->node, vinfo->xres, vinfo->xres_virtual, + dfb->node, vinfo->xres, vinfo->xres_virtual, vinfo->yres, vinfo->yres_virtual); } - if (vinfo->bits_per_pixel != 32 && - vinfo->bits_per_pixel != 16) { - log_error("device %s does not support 16/32 bpp but: %u", - fbdev->node, vinfo->bits_per_pixel); - return -EFAULT; - } - if (finfo->visual != FB_VISUAL_TRUECOLOR) { log_error("device %s does not support true-color", - fbdev->node); - return -EFAULT; + dfb->node); + ret = -EFAULT; + goto err_close; } if (vinfo->red.length > 8 || vinfo->green.length > 8 || vinfo->blue.length > 8) { log_error("device %s uses unusual color-ranges", - fbdev->node); - return -EFAULT; + dfb->node); + ret = -EFAULT; + goto err_close; } - log_info("activating display %s to %ux%u %u bpp", fbdev->node, + log_info("activating display %s to %ux%u %u bpp", dfb->node, vinfo->xres, vinfo->yres, vinfo->bits_per_pixel); /* calculate monitor rate, default is 60 Hz */ @@ -248,84 +274,90 @@ static int display_activate_force(struct uterm_display *disp, quot *= (vinfo->left_margin + vinfo->right_margin + vinfo->xres); quot *= vinfo->pixclock; if (quot) { - fbdev->rate = 1000000000000000LLU / quot; + dfb->rate = 1000000000000000LLU / quot; } else { - fbdev->rate = 60 * 1000; + dfb->rate = 60 * 1000; log_warning("cannot read monitor refresh rate, forcing 60 Hz"); } - if (fbdev->rate == 0) { + if (dfb->rate == 0) { log_warning("monitor refresh rate is 0 Hz, forcing it to 1 Hz"); - fbdev->rate = 1; - } else if (fbdev->rate > 200000) { + dfb->rate = 1; + } else if (dfb->rate > 200000) { log_warning("monitor refresh rate is >200 Hz (%u Hz), forcing it to 200 Hz", - fbdev->rate / 1000); - fbdev->rate = 200000; + dfb->rate / 1000); + dfb->rate = 200000; } - val = 1000000 / fbdev->rate; + val = 1000000 / dfb->rate; display_set_vblank_timer(disp, val); log_debug("vblank timer: %u ms, monitor refresh rate: %u Hz", val, - fbdev->rate / 1000); + dfb->rate / 1000); len = finfo->line_length * vinfo->yres; if (disp->flags & DISPLAY_DBUF) len *= 2; - fbdev->map = mmap(0, len, PROT_WRITE, MAP_SHARED, - fbdev->fd, 0); - if (fbdev->map == MAP_FAILED) { - log_error("cannot mmap device %s (%d): %m", fbdev->node, + dfb->map = mmap(0, len, PROT_WRITE, MAP_SHARED, dfb->fd, 0); + if (dfb->map == MAP_FAILED) { + log_error("cannot mmap device %s (%d): %m", dfb->node, errno); - return -EFAULT; + ret = -EFAULT; + goto err_close; } - memset(fbdev->map, 0, len); - fbdev->xres = vinfo->xres; - fbdev->yres = vinfo->yres; - fbdev->len = len; - fbdev->stride = finfo->line_length; - fbdev->bufid = 0; - fbdev->Bpp = vinfo->bits_per_pixel / 8; - fbdev->off_r = vinfo->red.offset; - fbdev->len_r = vinfo->red.length; - fbdev->off_g = vinfo->green.offset; - fbdev->len_g = vinfo->green.length; - fbdev->off_b = vinfo->blue.offset; - fbdev->len_b = vinfo->blue.length; - fbdev->dither_r = 0; - fbdev->dither_g = 0; - fbdev->dither_b = 0; - fbdev->xrgb32 = false; - if (fbdev->len_r == 8 && - fbdev->len_g == 8 && - fbdev->len_b == 8 && - fbdev->off_r == 16 && - fbdev->off_g == 8 && - fbdev->off_b == 0 && - fbdev->Bpp == 4) - fbdev->xrgb32 = true; + memset(dfb->map, 0, len); + dfb->xres = vinfo->xres; + dfb->yres = vinfo->yres; + dfb->len = len; + dfb->stride = finfo->line_length; + dfb->bufid = 0; + dfb->Bpp = vinfo->bits_per_pixel / 8; + dfb->off_r = vinfo->red.offset; + dfb->len_r = vinfo->red.length; + dfb->off_g = vinfo->green.offset; + dfb->len_g = vinfo->green.length; + dfb->off_b = vinfo->blue.offset; + dfb->len_b = vinfo->blue.length; + dfb->dither_r = 0; + dfb->dither_g = 0; + dfb->dither_b = 0; + dfb->xrgb32 = false; + if (dfb->len_r == 8 && dfb->len_g == 8 && dfb->len_b == 8 && + dfb->off_r == 16 && dfb->off_g == 8 && dfb->off_b == 0 && + dfb->Bpp == 4) + dfb->xrgb32 = true; /* TODO: make dithering configurable */ disp->flags |= DISPLAY_DITHERING; - if (!disp->current_mode) { + if (disp->current_mode) { + m = disp->current_mode; + } else { ret = mode_new(&m, &fbdev_mode_ops); + if (ret) + goto err_map; + ret = uterm_mode_bind(m, disp); if (ret) { - munmap(fbdev->map, fbdev->len); - return ret; + uterm_mode_unref(m); + goto err_map; } - m->next = disp->modes; - disp->modes = m; - - fbdev_mode = m->data; - fbdev_mode->width = fbdev->xres; - fbdev_mode->height = fbdev->yres; - disp->current_mode = disp->modes; + disp->current_mode = m; + uterm_mode_unref(m); } + mfb = m->data; + mfb->width = dfb->xres; + mfb->height = dfb->yres; + disp->flags |= DISPLAY_ONLINE; return 0; + +err_map: + munmap(dfb->map, dfb->len); +err_close: + close(dfb->fd); + return ret; } static int display_activate(struct uterm_display *disp, struct uterm_mode *mode) @@ -335,23 +367,21 @@ static int display_activate(struct uterm_display *disp, struct uterm_mode *mode) static void display_deactivate_force(struct uterm_display *disp, bool force) { - struct fbdev_display *fbdev = disp->data; + struct fbdev_display *dfb = disp->data; - if (!disp->video || !(disp->flags & DISPLAY_ONLINE)) - return; - - log_info("deactivating device %s", fbdev->node); + log_info("deactivating device %s", dfb->node); + if (dfb->map) { + memset(dfb->map, 0, dfb->len); + munmap(dfb->map, dfb->len); + close(dfb->fd); + dfb->map = NULL; + } if (!force) { - uterm_mode_unref(disp->current_mode); - disp->modes = NULL; + uterm_mode_unbind(disp->current_mode); disp->current_mode = NULL; - } - memset(fbdev->map, 0, fbdev->len); - munmap(fbdev->map, fbdev->len); - - if (!force) disp->flags &= ~DISPLAY_ONLINE; + } } static void display_deactivate(struct uterm_display *disp) @@ -362,10 +392,7 @@ static void display_deactivate(struct uterm_display *disp) static int display_set_dpms(struct uterm_display *disp, int state) { int set, ret; - struct fbdev_display *fbdev = disp->data; - - if (!disp->video || !(disp->flags & DISPLAY_ONLINE)) - return -EINVAL; + struct fbdev_display *dfb = disp->data; switch (state) { case UTERM_DPMS_ON: @@ -384,12 +411,12 @@ static int display_set_dpms(struct uterm_display *disp, int state) return -EINVAL; } - log_info("setting DPMS of device %p to %s", fbdev->node, + log_info("setting DPMS of device %p to %s", dfb->node, uterm_dpms_to_name(state)); - ret = ioctl(fbdev->fd, FBIOBLANK, set); + ret = ioctl(dfb->fd, FBIOBLANK, set); if (ret) { - log_error("cannot set DPMS on %s (%d): %m", fbdev->node, + log_error("cannot set DPMS on %s (%d): %m", dfb->node, errno); return -EFAULT; } @@ -400,41 +427,35 @@ static int display_set_dpms(struct uterm_display *disp, int state) static int display_swap(struct uterm_display *disp) { + struct fbdev_display *dfb = disp->data; struct fb_var_screeninfo *vinfo; int ret; - struct fbdev_display *fbdev = disp->data; - - if (!disp->video || !video_is_awake(disp->video)) - return -EINVAL; - if (!(disp->flags & DISPLAY_ONLINE)) - return -EINVAL; - if (!(disp->flags & DISPLAY_DBUF)) { + if (!(disp->flags & DISPLAY_DBUF)) return display_schedule_vblank_timer(disp); - } - vinfo = &fbdev->vinfo; + vinfo = &dfb->vinfo; vinfo->activate = FB_ACTIVATE_VBL; - if (!fbdev->bufid) - vinfo->yoffset = fbdev->yres; + if (!dfb->bufid) + vinfo->yoffset = dfb->yres; else vinfo->yoffset = 0; - ret = ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, vinfo); + ret = ioctl(dfb->fd, FBIOPUT_VSCREENINFO, vinfo); if (ret) { log_warning("cannot swap buffers on %s (%d): %m", - fbdev->node, errno); + dfb->node, errno); return -EFAULT; } - fbdev->bufid ^= 1; + dfb->bufid ^= 1; return display_schedule_vblank_timer(disp); } static const struct display_ops fbdev_display_ops = { - .init = NULL, - .destroy = NULL, + .init = display_init, + .destroy = display_destroy, .activate = display_activate, .deactivate = display_deactivate, .set_dpms = display_set_dpms, @@ -447,120 +468,100 @@ static const struct display_ops fbdev_display_ops = { static void intro_idle_event(struct ev_eloop *eloop, void *unused, void *data) { - struct uterm_display *disp = data; - struct fbdev_display *fbdev = disp->data; + struct uterm_video *video = data; + struct fbdev_video *vfb = video->data; + struct uterm_display *disp; + struct fbdev_display *dfb; + int ret; - if (!fbdev->pending_intro) - return; + vfb->pending_intro = false; + ev_eloop_unregister_idle_cb(eloop, intro_idle_event, data); - fbdev->pending_intro = false; - ev_eloop_unregister_idle_cb(eloop, intro_idle_event, disp); + ret = display_new(&disp, &fbdev_display_ops); + if (ret) { + log_error("cannot create fbdev display: %d", ret); + return; + } - if (!disp->video) + dfb = disp->data; + dfb->node = vfb->node; + ret = uterm_display_bind(disp, video); + if (ret) { + log_error("cannot bind fbdev display: %d", ret); + uterm_display_unref(disp); return; + } - VIDEO_CB(disp->video, disp, UTERM_NEW); + uterm_display_unref(disp); } static int video_init(struct uterm_video *video, const char *node) { int ret; - struct uterm_display *disp; - struct fbdev_display *fbdev; - - fbdev = malloc(sizeof(*fbdev)); - if (!fbdev) - return -ENOMEM; - memset(fbdev, 0, sizeof(*fbdev)); + struct fbdev_video *vfb; - ret = display_new(&disp, &fbdev_display_ops, video); - if (ret) - goto err_fbdev; - disp->data = fbdev; + log_info("new device on %s", node); - ret = ev_eloop_register_idle_cb(video->eloop, intro_idle_event, disp); - if (ret) { - log_error("cannot register idle event: %d", ret); - goto err_free; - } - fbdev->pending_intro = true; + vfb = malloc(sizeof(*vfb)); + if (!vfb) + return -ENOMEM; + memset(vfb, 0, sizeof(*vfb)); + video->data = vfb; - fbdev->node = strdup(node); - if (!fbdev->node) { - log_err("cannot dup node name"); + vfb->node = strdup(node); + if (!vfb->node) { ret = -ENOMEM; - goto err_idle; + goto err_free; } - fbdev->fd = open(node, O_RDWR | O_CLOEXEC); - if (fbdev->fd < 0) { - log_err("cannot open %s (%d): %m", node, errno); - ret = -EFAULT; + ret = ev_eloop_register_idle_cb(video->eloop, intro_idle_event, video); + if (ret) { + log_error("cannot register idle event: %d", ret); goto err_node; } + vfb->pending_intro = true; - disp->dpms = UTERM_DPMS_UNKNOWN; - video->displays = disp; - - log_info("new device on %s", fbdev->node); return 0; err_node: - free(fbdev->node); -err_idle: - ev_eloop_register_idle_cb(video->eloop, intro_idle_event, disp); + free(vfb->node); err_free: - uterm_display_unref(disp); -err_fbdev: - free(fbdev); + free(vfb); return ret; } static void video_destroy(struct uterm_video *video) { - struct uterm_display *disp; - struct fbdev_display *fbdev; + struct fbdev_video *vfb = video->data; - log_info("free device %p", video); - disp = video->displays; - video->displays = disp->next; - fbdev = disp->data; + log_info("free device on %s", vfb->node); - if (fbdev->pending_intro) + if (vfb->pending_intro) ev_eloop_unregister_idle_cb(video->eloop, intro_idle_event, - disp); - else - VIDEO_CB(video, disp, UTERM_GONE); + video); - close(fbdev->fd); - free(fbdev->node); - free(fbdev); - uterm_display_unref(disp); + free(vfb->node); + free(vfb); } static void video_sleep(struct uterm_video *video) { - if (!(video->flags & VIDEO_AWAKE)) - return; + struct fbdev_video *vfb = video->data; - display_deactivate_force(video->displays, true); - video->flags &= ~VIDEO_AWAKE; + if (vfb->disp && display_is_online(vfb->disp)) + display_deactivate_force(vfb->disp, true); } static int video_wake_up(struct uterm_video *video) { + struct fbdev_video *vfb = video->data; int ret; - if (video->flags & VIDEO_AWAKE) - return 0; - - video->flags |= VIDEO_AWAKE; - if (video->displays->flags & DISPLAY_ONLINE) { - ret = display_activate_force(video->displays, NULL, true); - if (ret) { - video->flags &= ~VIDEO_AWAKE; + if (vfb->disp && display_is_online(vfb->disp)) { + video->flags |= VIDEO_AWAKE; + ret = display_activate_force(vfb->disp, NULL, true); + if (ret) return ret; - } } return 0; diff --git a/src/uterm_video.c b/src/uterm_video.c index 78cf661..aed5e44 100644 --- a/src/uterm_video.c +++ b/src/uterm_video.c @@ -1,7 +1,7 @@ /* * uterm - Linux User-Space Terminal * - * Copyright (c) 2011-2012 David Herrmann <dh.herrmann@googlemail.com> + * Copyright (c) 2011-2013 David Herrmann <dh.herrmann@googlemail.com> * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -36,6 +36,7 @@ #include <unistd.h> #include "eloop.h" #include "log.h" +#include "shl_dlist.h" #include "shl_hook.h" #include "uterm_video.h" #include "uterm_video_internal.h" @@ -113,12 +114,34 @@ void uterm_mode_unref(struct uterm_mode *mode) free(mode); } -struct uterm_mode *uterm_mode_next(struct uterm_mode *mode) +int uterm_mode_bind(struct uterm_mode *mode, struct uterm_display *disp) +{ + if (!mode || !disp || mode->disp) + return -EINVAL; + + mode->disp = disp; + shl_dlist_link_tail(&disp->modes, &mode->list); + uterm_mode_ref(mode); + + return 0; +} + +void uterm_mode_unbind(struct uterm_mode *mode) { if (!mode) + return; + + mode->disp = NULL; + shl_dlist_unlink(&mode->list); + uterm_mode_unref(mode); +} + +struct uterm_mode *uterm_mode_next(struct uterm_mode *mode) +{ + if (!mode || mode->list.next == &mode->disp->modes) return NULL; - return mode->next; + return shl_dlist_entry(mode->list.next, struct uterm_mode, list); } const char *uterm_mode_get_name(const struct uterm_mode *mode) @@ -181,13 +204,12 @@ static void display_vblank_timer_event(struct ev_timer *timer, DISPLAY_CB(disp, UTERM_PAGE_FLIP); } -int display_new(struct uterm_display **out, const struct display_ops *ops, - struct uterm_video *video) +int display_new(struct uterm_display **out, const struct display_ops *ops) { struct uterm_display *disp; int ret; - if (!out || !ops || !video) + if (!out || !ops) return -EINVAL; disp = malloc(sizeof(*disp)); @@ -196,7 +218,9 @@ int display_new(struct uterm_display **out, const struct display_ops *ops, memset(disp, 0, sizeof(*disp)); disp->ref = 1; disp->ops = ops; - disp->video = video; + shl_dlist_init(&disp->modes); + + log_info("new display %p", disp); ret = shl_hook_new(&disp->hook); if (ret) @@ -209,20 +233,13 @@ int display_new(struct uterm_display **out, const struct display_ops *ops, if (ret) goto err_hook; - ret = ev_eloop_add_timer(video->eloop, disp->vblank_timer); - if (ret) - goto err_timer; - ret = VIDEO_CALL(disp->ops->init, 0, disp); if (ret) - goto err_eloop_timer; + goto err_timer; - log_info("new display %p", disp); *out = disp; return 0; -err_eloop_timer: - ev_eloop_rm_timer(disp->vblank_timer); err_timer: ev_timer_unref(disp->vblank_timer); err_hook: @@ -249,25 +266,56 @@ void uterm_display_unref(struct uterm_display *disp) log_info("free display %p", disp); - VIDEO_CALL(disp->ops->destroy, 0, disp); - - while ((mode = disp->modes)) { - disp->modes = mode->next; - mode->next = NULL; - uterm_mode_unref(mode); + while (!shl_dlist_empty(&disp->modes)) { + mode = shl_dlist_entry(disp->modes.prev, struct uterm_mode, + list); + uterm_mode_unbind(mode); } - ev_eloop_rm_timer(disp->vblank_timer); + + VIDEO_CALL(disp->ops->destroy, 0, disp); ev_timer_unref(disp->vblank_timer); shl_hook_free(disp->hook); free(disp); } +int uterm_display_bind(struct uterm_display *disp, struct uterm_video *video) +{ + int ret; + + if (!disp || !video || disp->video) + return -EINVAL; + + ret = ev_eloop_add_timer(video->eloop, disp->vblank_timer); + if (ret) + return ret; + + shl_dlist_link_tail(&video->displays, &disp->list); + disp->video = video; + uterm_display_ref(disp); + VIDEO_CB(disp->video, disp, UTERM_NEW); + + return 0; +} + +void uterm_display_unbind(struct uterm_display *disp) +{ + if (!disp || !disp->video) + return; + + VIDEO_CB(disp->video, disp, UTERM_GONE); + uterm_display_deactivate(disp); + disp->video = NULL; + shl_dlist_unlink(&disp->list); + ev_eloop_rm_timer(disp->vblank_timer); + uterm_display_unref(disp); +} + struct uterm_display *uterm_display_next(struct uterm_display *disp) { - if (!disp) + if (!disp || !disp->video || disp->list.next == &disp->video->displays) return NULL; - return disp->next; + return shl_dlist_entry(disp->list.next, struct uterm_display, list); } int uterm_display_register_cb(struct uterm_display *disp, uterm_display_cb cb, @@ -290,10 +338,10 @@ void uterm_display_unregister_cb(struct uterm_display *disp, struct uterm_mode *uterm_display_get_modes(struct uterm_display *disp) { - if (!disp) + if (!disp || shl_dlist_empty(&disp->modes)) return NULL; - return disp->modes; + return shl_dlist_entry(disp->modes.next, struct uterm_mode, list); } struct uterm_mode *uterm_display_get_current(struct uterm_display *disp) @@ -333,7 +381,8 @@ int uterm_display_get_state(struct uterm_display *disp) int uterm_display_activate(struct uterm_display *disp, struct uterm_mode *mode) { - if (!disp || !display_is_conn(disp) || display_is_online(disp)) + if (!disp || !disp->video || display_is_online(disp) || + !video_is_awake(disp->video)) return -EINVAL; if (!mode) @@ -352,7 +401,7 @@ void uterm_display_deactivate(struct uterm_display *disp) int uterm_display_set_dpms(struct uterm_display *disp, int state) { - if (!disp || !display_is_conn(disp)) + if (!disp || !display_is_online(disp) || !video_is_awake(disp->video)) return -EINVAL; return VIDEO_CALL(disp->ops->set_dpms, 0, disp, state); @@ -360,7 +409,7 @@ int uterm_display_set_dpms(struct uterm_display *disp, int state) int uterm_display_get_dpms(const struct uterm_display *disp) { - if (!disp || !display_is_conn(disp)) + if (!disp || !disp->video) return UTERM_DPMS_OFF; return disp->dpms; @@ -376,7 +425,7 @@ int uterm_display_use(struct uterm_display *disp) int uterm_display_swap(struct uterm_display *disp) { - if (!disp || !display_is_online(disp)) + if (!disp || !display_is_online(disp) || !video_is_awake(disp->video)) return -EINVAL; return VIDEO_CALL(disp->ops->swap, 0, disp); @@ -395,7 +444,7 @@ int uterm_display_fill(struct uterm_display *disp, unsigned int x, unsigned int y, unsigned int width, unsigned int height) { - if (!disp) + if (!disp || !display_is_online(disp) || !video_is_awake(disp->video)) return -EINVAL; return VIDEO_CALL(disp->ops->fill, -EOPNOTSUPP, disp, r, g, b, x, y, @@ -406,7 +455,7 @@ int uterm_display_blit(struct uterm_display *disp, const struct uterm_video_buffer *buf, unsigned int x, unsigned int y) { - if (!disp) + if (!disp || !display_is_online(disp) || !video_is_awake(disp->video)) return -EINVAL; return VIDEO_CALL(disp->ops->blit, -EOPNOTSUPP, disp, buf, x, y); @@ -420,7 +469,7 @@ int uterm_display_fake_blend(struct uterm_display *disp, { struct uterm_video_blend_req req; - if (!disp) + if (!disp || !display_is_online(disp) || !video_is_awake(disp->video)) return -EINVAL; memset(&req, 0, sizeof(req)); @@ -441,7 +490,7 @@ int uterm_display_fake_blendv(struct uterm_display *disp, const struct uterm_video_blend_req *req, size_t num) { - if (!disp) + if (!disp || !display_is_online(disp) || !video_is_awake(disp->video)) return -EINVAL; return VIDEO_CALL(disp->ops->fake_blendv, -EOPNOTSUPP, disp, req, num); @@ -466,6 +515,7 @@ int uterm_video_new(struct uterm_video **out, struct ev_eloop *eloop, video->mod = mod; video->ops = mod->ops; video->eloop = eloop; + shl_dlist_init(&video->displays); ret = shl_hook_new(&video->hook); if (ret) @@ -504,14 +554,13 @@ void uterm_video_unref(struct uterm_video *video) log_info("free device %p", video); - VIDEO_CALL(video->ops->destroy, 0, video); - - while ((disp = video->displays)) { - video->displays = disp->next; - disp->next = NULL; - uterm_display_unref(disp); + while (!shl_dlist_empty(&video->displays)) { + disp = shl_dlist_entry(video->displays.prev, + struct uterm_display, list); + uterm_display_unbind(disp); } + VIDEO_CALL(video->ops->destroy, 0, video); shl_hook_free(video->hook); ev_eloop_unref(video->eloop); free(video); @@ -535,10 +584,11 @@ int uterm_video_use(struct uterm_video *video) struct uterm_display *uterm_video_get_displays(struct uterm_video *video) { - if (!video) + if (!video || shl_dlist_empty(&video->displays)) return NULL; - return video->displays; + return shl_dlist_entry(video->displays.next, struct uterm_display, + list); } int uterm_video_register_cb(struct uterm_video *video, uterm_video_cb cb, @@ -565,6 +615,7 @@ void uterm_video_sleep(struct uterm_video *video) return; VIDEO_CB(video, NULL, UTERM_SLEEP); + video->flags &= ~VIDEO_AWAKE; VIDEO_CALL(video->ops->sleep, 0, video); } @@ -578,9 +629,12 @@ int uterm_video_wake_up(struct uterm_video *video) return 0; ret = VIDEO_CALL(video->ops->wake_up, 0, video); - if (ret) + if (ret) { + video->flags &= ~VIDEO_AWAKE; return ret; + } + video->flags |= VIDEO_AWAKE; VIDEO_CB(video, NULL, UTERM_WAKE_UP); return 0; } diff --git a/src/uterm_video_drm.c b/src/uterm_video_drm.c index d781a16..4e44aab 100644 --- a/src/uterm_video_drm.c +++ b/src/uterm_video_drm.c @@ -1,7 +1,7 @@ /* * uterm - Linux User-Space Terminal * - * Copyright (c) 2011-2012 David Herrmann <dh.herrmann@googlemail.com> + * Copyright (c) 2011-2013 David Herrmann <dh.herrmann@googlemail.com> * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -183,9 +183,7 @@ static int display_activate(struct uterm_display *disp, struct gbm_bo *bo; drmModeModeInfo *minfo; - if (!video || !video_is_awake(video) || !mode) - return -EINVAL; - if (display_is_online(disp)) + if (!mode) return -EINVAL; vdrm = video->data; @@ -283,9 +281,6 @@ static void display_deactivate(struct uterm_display *disp) struct uterm_drm_video *vdrm; struct uterm_drm3d_video *v3d; - if (!display_is_online(disp)) - return; - log_info("deactivating display %p", disp); vdrm = video->data; @@ -317,9 +312,6 @@ static int display_use(struct uterm_display *disp) struct uterm_drm3d_display *d3d = uterm_drm_display_get_data(disp); struct uterm_drm3d_video *v3d; - if (!display_is_online(disp)) - return -EINVAL; - v3d = uterm_drm_video_get_data(disp->video); if (!eglMakeCurrent(v3d->disp, d3d->surface, d3d->surface, v3d->ctx)) { @@ -340,8 +332,6 @@ static int swap_display(struct uterm_display *disp, bool immediate) struct uterm_drm3d_video *v3d; struct uterm_drm_video *vdrm; - if (!display_is_online(disp) || !video_is_awake(disp->video)) - return -EINVAL; if (disp->dpms != UTERM_DPMS_ON) return -EINVAL; if (!immediate && @@ -528,11 +518,7 @@ static int display_blit(struct uterm_display *disp, int ret; uint8_t *packed, *src, *dst; - if (!disp->video || !(disp->flags & DISPLAY_ONLINE)) - return -EINVAL; - if (!video_is_awake(disp->video)) - return -EINVAL; - if (buf->format != UTERM_FORMAT_XRGB32) + if (!buf || buf->format != UTERM_FORMAT_XRGB32) return -EINVAL; v3d = uterm_drm_video_get_data(disp->video); @@ -661,11 +647,7 @@ static int display_blend(struct uterm_display *disp, int ret; uint8_t *packed, *src, *dst; - if (!disp->video || !(disp->flags & DISPLAY_ONLINE)) - return -EINVAL; - if (!video_is_awake(disp->video)) - return -EINVAL; - if (buf->format != UTERM_FORMAT_GREY) + if (!buf || buf->format != UTERM_FORMAT_GREY) return -EINVAL; v3d = uterm_drm_video_get_data(disp->video); @@ -826,11 +808,6 @@ static int display_fill(struct uterm_display *disp, float vertices[6 * 2], colors[6 * 4]; int ret; - if (!disp->video || !(disp->flags & DISPLAY_ONLINE)) - return -EINVAL; - if (!video_is_awake(disp->video)) - return -EINVAL; - v3d = uterm_drm_video_get_data(disp->video); ret = display_use(disp); if (ret) @@ -913,11 +890,14 @@ static void show_displays(struct uterm_video *video) { int ret; struct uterm_display *iter; + struct shl_dlist *i; if (!video_is_awake(video)) return; - for (iter = video->displays; iter; iter = iter->next) { + shl_dlist_for_each(i, &video->displays) { + iter = shl_dlist_entry(i, struct uterm_display, list); + if (!display_is_online(iter)) continue; if (iter->dpms != UTERM_DPMS_ON) @@ -989,6 +969,8 @@ static int video_init(struct uterm_video *video, const char *node) goto err_free; vdrm = video->data; + log_debug("initialize 3D layer on %p", video); + v3d->gbm = gbm_create_device(vdrm->fd); if (!v3d->gbm) { log_err("cannot create gbm device for %s (permission denied)", @@ -1076,17 +1058,9 @@ err_free: static void video_destroy(struct uterm_video *video) { struct uterm_drm3d_video *v3d = uterm_drm_video_get_data(video); - struct uterm_display *disp; log_info("free drm video device %p", video); - while ((disp = video->displays)) { - video->displays = disp->next; - disp->next = NULL; - uterm_drm_display_unbind(disp); - uterm_display_unref(disp); - } - if (!eglMakeCurrent(v3d->disp, EGL_NO_SURFACE, EGL_NO_SURFACE, v3d->ctx)) log_error("cannot activate GL context during destruction"); diff --git a/src/uterm_video_dumb.c b/src/uterm_video_dumb.c index 1b7aff3..63dffb0 100644 --- a/src/uterm_video_dumb.c +++ b/src/uterm_video_dumb.c @@ -1,7 +1,7 @@ /* * uterm - Linux User-Space Terminal * - * Copyright (c) 2011-2012 David Herrmann <dh.herrmann@googlemail.com> + * Copyright (c) 2011-2013 David Herrmann <dh.herrmann@googlemail.com> * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -181,9 +181,7 @@ static int display_activate(struct uterm_display *disp, struct uterm_mode *mode) int ret; drmModeModeInfo *minfo; - if (!video || !video_is_awake(video) || !mode) - return -EINVAL; - if (display_is_online(disp)) + if (!mode) return -EINVAL; minfo = uterm_drm_mode_get_info(mode);; @@ -232,9 +230,6 @@ static void display_deactivate(struct uterm_display *disp) struct uterm_drm_video *vdrm; struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp); - if (!display_is_online(disp)) - return; - vdrm = disp->video->data; log_info("deactivating display %p", disp); @@ -253,8 +248,6 @@ static int display_swap(struct uterm_display *disp) struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp); struct uterm_drm_video *vdrm; - if (!display_is_online(disp) || !video_is_awake(disp->video)) - return -EINVAL; if (disp->dpms != UTERM_DPMS_ON) return -EINVAL; @@ -285,11 +278,7 @@ static int display_blit(struct uterm_display *disp, struct uterm_drm2d_rb *rb; struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp); - if (!disp->video || !display_is_online(disp)) - return -EINVAL; - if (!buf || !video_is_awake(disp->video)) - return -EINVAL; - if (buf->format != UTERM_FORMAT_XRGB32) + if (!buf || buf->format != UTERM_FORMAT_XRGB32) return -EINVAL; rb = &d2d->rb[d2d->current_rb ^ 1]; @@ -337,9 +326,7 @@ static int display_fake_blendv(struct uterm_display *disp, struct uterm_drm2d_rb *rb; struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp); - if (!disp->video || !display_is_online(disp)) - return -EINVAL; - if (!req || !video_is_awake(disp->video)) + if (!req) return -EINVAL; rb = &d2d->rb[d2d->current_rb ^ 1]; @@ -419,11 +406,6 @@ static int display_fill(struct uterm_display *disp, struct uterm_drm2d_rb *rb; struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp); - if (!disp->video || !(disp->flags & DISPLAY_ONLINE)) - return -EINVAL; - if (!video_is_awake(disp->video)) - return -EINVAL; - rb = &d2d->rb[d2d->current_rb ^ 1]; sw = uterm_drm_mode_get_width(disp->current_mode); sh = uterm_drm_mode_get_height(disp->current_mode); @@ -472,11 +454,14 @@ static void show_displays(struct uterm_video *video) struct uterm_drm2d_display *d2d; struct uterm_drm2d_rb *rb; struct uterm_drm_video *vdrm = video->data; + struct shl_dlist *i; if (!video_is_awake(video)) return; - for (iter = video->displays; iter; iter = iter->next) { + shl_dlist_for_each(i, &video->displays) { + iter = shl_dlist_entry(i, struct uterm_display, list); + if (!display_is_online(iter)) continue; if (iter->dpms != UTERM_DPMS_ON) @@ -502,11 +487,11 @@ static void page_flip_handler(int fd, unsigned int frame, unsigned int sec, { struct uterm_display *disp = data; - uterm_display_unref(disp); if (disp->flags & DISPLAY_VSYNC) { disp->flags &= ~DISPLAY_VSYNC; DISPLAY_CB(disp, UTERM_PAGE_FLIP); } + uterm_display_unref(disp); } static int video_init(struct uterm_video *video, const char *node) @@ -520,6 +505,8 @@ static int video_init(struct uterm_video *video, const char *node) return ret; vdrm = video->data; + log_debug("initialize 2D layer on %p", video); + if (drmGetCap(vdrm->fd, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0 || !has_dumb) { log_err("driver does not support dumb buffers"); @@ -532,17 +519,7 @@ static int video_init(struct uterm_video *video, const char *node) static void video_destroy(struct uterm_video *video) { - struct uterm_display *disp; - log_info("free drm video device %p", video); - - while ((disp = video->displays)) { - video->displays = disp->next; - disp->next = NULL; - uterm_drm_display_unbind(disp); - uterm_display_unref(disp); - } - uterm_drm_video_destroy(video); } diff --git a/src/uterm_video_internal.h b/src/uterm_video_internal.h index dc92aec..ad627f0 100644 --- a/src/uterm_video_internal.h +++ b/src/uterm_video_internal.h @@ -33,6 +33,7 @@ #include <stdbool.h> #include <stdlib.h> #include "eloop.h" +#include "shl_dlist.h" #include "shl_hook.h" #include "uterm_video.h" @@ -84,14 +85,17 @@ struct uterm_video_module { /* uterm_mode */ struct uterm_mode { + struct shl_dlist list; unsigned long ref; - struct uterm_mode *next; + struct uterm_display *disp; const struct mode_ops *ops; void *data; }; int mode_new(struct uterm_mode **out, const struct mode_ops *ops); +int uterm_mode_bind(struct uterm_mode *mode, struct uterm_display *disp); +void uterm_mode_unbind(struct uterm_mode *mode); /* uterm_display */ @@ -103,13 +107,13 @@ int mode_new(struct uterm_mode **out, const struct mode_ops *ops); #define DISPLAY_DITHERING 0x20 struct uterm_display { + struct shl_dlist list; unsigned long ref; unsigned int flags; - struct uterm_display *next; struct uterm_video *video; struct shl_hook *hook; - struct uterm_mode *modes; + struct shl_dlist modes; struct uterm_mode *default_mode; struct uterm_mode *current_mode; int dpms; @@ -122,25 +126,21 @@ struct uterm_display { void *data; }; -int display_new(struct uterm_display **out, const struct display_ops *ops, - struct uterm_video *video); +int display_new(struct uterm_display **out, const struct display_ops *ops); void display_set_vblank_timer(struct uterm_display *disp, unsigned int msecs); int display_schedule_vblank_timer(struct uterm_display *disp); +int uterm_display_bind(struct uterm_display *disp, struct uterm_video *video); +void uterm_display_unbind(struct uterm_display *disp); #define DISPLAY_CB(disp, act) shl_hook_call((disp)->hook, (disp), \ &(struct uterm_display_event){ \ .action = (act), \ }) -static inline bool display_is_conn(const struct uterm_display *disp) -{ - return disp->video; -} - static inline bool display_is_online(const struct uterm_display *disp) { - return display_is_conn(disp) && (disp->flags & DISPLAY_ONLINE); + return disp->video && (disp->flags & DISPLAY_ONLINE); } /* uterm_video */ @@ -153,7 +153,7 @@ struct uterm_video { unsigned int flags; struct ev_eloop *eloop; - struct uterm_display *displays; + struct shl_dlist displays; struct shl_hook *hook; const struct uterm_video_module *mod; |