void uterm_display_deactivate(struct uterm_display *disp) { if (!disp || !display_is_online(disp)) return; VIDEO_CALL(disp->ops->deactivate, 0, disp); }
int uterm_display_swap(struct uterm_display *disp) { if (!disp || !display_is_online(disp)) return -EINVAL; return VIDEO_CALL(disp->ops->swap, 0, disp); }
SHL_EXPORT int uterm_display_fake_blend(struct uterm_display *disp, const struct uterm_video_buffer *buf, unsigned int x, unsigned int y, uint8_t fr, uint8_t fg, uint8_t fb, uint8_t br, uint8_t bg, uint8_t bb) { struct uterm_video_blend_req req; if (!disp || !display_is_online(disp) || !video_is_awake(disp->video)) return -EINVAL; memset(&req, 0, sizeof(req)); req.buf = buf; req.x = x; req.y = y; req.fr = fr; req.fg = fg; req.fb = fb; req.br = br; req.bg = bg; req.bb = bb; return VIDEO_CALL(disp->ops->fake_blendv, -EOPNOTSUPP, disp, &req, 1); }
int uterm_screen_swap(struct uterm_screen *screen) { if (!screen || !display_is_online(screen->disp)) return -EINVAL; return VIDEO_CALL(screen->disp->ops->swap, 0, screen->disp); }
static void display_deactivate(struct uterm_display *disp) { if (!display_is_online(disp)) return; if (disp->dumb.saved_crtc) { if (disp->video->flags & VIDEO_AWAKE) { drmModeSetCrtc(disp->video->dumb.fd, disp->dumb.saved_crtc->crtc_id, disp->dumb.saved_crtc->buffer_id, disp->dumb.saved_crtc->x, disp->dumb.saved_crtc->y, &disp->dumb.conn_id, 1, &disp->dumb.saved_crtc->mode); } drmModeFreeCrtc(disp->dumb.saved_crtc); disp->dumb.saved_crtc = NULL; } destroy_rb(disp, &disp->dumb.rb[1]); destroy_rb(disp, &disp->dumb.rb[0]); disp->current_mode = NULL; disp->flags &= ~(DISPLAY_ONLINE | DISPLAY_VSYNC); log_info("deactivating display %p", disp); }
int uterm_display_use(struct uterm_display *disp) { if (!disp || !display_is_online(disp)) return -EINVAL; return VIDEO_CALL(disp->ops->use, -EOPNOTSUPP, disp); }
int uterm_screen_use(struct uterm_screen *screen) { if (!screen || !display_is_online(screen->disp)) return -EINVAL; return VIDEO_CALL(screen->disp->ops->use, -EOPNOTSUPP, screen->disp); }
SHL_EXPORT int uterm_display_set_dpms(struct uterm_display *disp, int state) { if (!disp || !display_is_online(disp) || !video_is_awake(disp->video)) return -EINVAL; return VIDEO_CALL(disp->ops->set_dpms, 0, disp, state); }
SHL_EXPORT int uterm_display_swap(struct uterm_display *disp, bool immediate) { if (!disp || !display_is_online(disp) || !video_is_awake(disp->video)) return -EINVAL; return VIDEO_CALL(disp->ops->swap, 0, disp, immediate); }
SHL_EXPORT int uterm_display_use(struct uterm_display *disp, bool *opengl) { if (!disp || !display_is_online(disp)) return -EINVAL; return VIDEO_CALL(disp->ops->use, -EOPNOTSUPP, disp, opengl); }
int uterm_display_activate(struct uterm_display *disp, struct uterm_mode *mode) { if (!disp || !display_is_conn(disp) || display_is_online(disp)) return -EINVAL; if (!mode) mode = disp->default_mode; return VIDEO_CALL(disp->ops->activate, 0, disp, mode); }
SHL_EXPORT int uterm_display_blit(struct uterm_display *disp, const struct uterm_video_buffer *buf, unsigned int x, unsigned int y) { if (!disp || !display_is_online(disp) || !video_is_awake(disp->video)) return -EINVAL; return VIDEO_CALL(disp->ops->blit, -EOPNOTSUPP, disp, buf, x, y); }
SHL_EXPORT int uterm_display_fake_blendv(struct uterm_display *disp, const struct uterm_video_blend_req *req, size_t num) { if (!disp || !display_is_online(disp) || !video_is_awake(disp->video)) return -EINVAL; return VIDEO_CALL(disp->ops->fake_blendv, -EOPNOTSUPP, disp, req, num); }
SHL_EXPORT int uterm_display_get_buffers(struct uterm_display *disp, struct uterm_video_buffer *buffer, unsigned int formats) { if (!disp || !display_is_online(disp) || !buffer) return -EINVAL; return VIDEO_CALL(disp->ops->get_buffers, -EOPNOTSUPP, disp, buffer, formats); }
SHL_EXPORT int uterm_display_fill(struct uterm_display *disp, uint8_t r, uint8_t g, uint8_t b, unsigned int x, unsigned int y, unsigned int width, unsigned int height) { 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, width, height); }
SHL_EXPORT int uterm_display_activate(struct uterm_display *disp, struct uterm_mode *mode) { if (!disp || !disp->video || display_is_online(disp) || !video_is_awake(disp->video)) return -EINVAL; if (!mode) mode = disp->default_mode; return VIDEO_CALL(disp->ops->activate, 0, disp, mode); }
static int display_blit(struct uterm_display *disp, const struct uterm_video_buffer *buf, unsigned int x, unsigned int y) { unsigned int tmp; uint8_t *dst, *src; struct dumb_rb *rb; unsigned int width, height; unsigned int sw, sh; if (!disp->video || !display_is_online(disp)) return -EINVAL; if (!buf || !video_is_awake(disp->video)) return -EINVAL; if (buf->format != UTERM_FORMAT_XRGB32) return -EINVAL; rb = &disp->dumb.rb[disp->dumb.current_rb ^ 1]; sw = disp->current_mode->dumb.info.hdisplay; sh = disp->current_mode->dumb.info.vdisplay; tmp = x + buf->width; if (tmp < x || x >= sw) return -EINVAL; if (tmp > sw) width = sw - x; else width = buf->width; tmp = y + buf->height; if (tmp < y || y >= sh) return -EINVAL; if (tmp > sh) height = sh - y; else height = buf->height; dst = rb->map; dst = &dst[y * rb->stride + x * 4]; src = buf->data; while (height--) { memcpy(dst, src, 4 * width); dst += rb->stride; src += buf->stride; } return 0; }
static int display_swap(struct uterm_display *disp) { int ret; if (!display_is_online(disp) || !video_is_awake(disp->video)) return -EINVAL; if (disp->dpms != UTERM_DPMS_ON) return -EINVAL; errno = 0; disp->dumb.current_rb ^= 1; ret = drmModePageFlip(disp->video->dumb.fd, disp->dumb.crtc_id, disp->dumb.rb[disp->dumb.current_rb].fb, DRM_MODE_PAGE_FLIP_EVENT, disp); if (ret) { log_warn("page-flip failed %d %d", ret, errno); return -EFAULT; } uterm_display_ref(disp); disp->flags |= DISPLAY_VSYNC; return 0; }
static void show_displays(struct uterm_video *video) { int ret; struct uterm_display *iter; if (!video_is_awake(video)) return; for (iter = video->displays; iter; iter = iter->next) { if (!display_is_online(iter)) continue; if (iter->dpms != UTERM_DPMS_ON) continue; ret = drmModeSetCrtc(video->dumb.fd, iter->dumb.crtc_id, iter->dumb.rb[iter->dumb.current_rb].fb, 0, 0, &iter->dumb.conn_id, 1, &iter->current_mode->dumb.info); if (ret) { log_err("cannot set drm-crtc on display %p", iter); continue; } } }
static int display_fake_blendv(struct uterm_display *disp, const struct uterm_video_blend_req *req, size_t num) { unsigned int tmp; uint8_t *dst, *src; struct dumb_rb *rb; unsigned int width, height, i, j; unsigned int sw, sh; unsigned int r, g, b; if (!disp->video || !display_is_online(disp)) return -EINVAL; if (!req || !video_is_awake(disp->video)) return -EINVAL; rb = &disp->dumb.rb[disp->dumb.current_rb ^ 1]; sw = disp->current_mode->dumb.info.hdisplay; sh = disp->current_mode->dumb.info.vdisplay; for (j = 0; j < num; ++j, ++req) { if (!req->buf) continue; if (req->buf->format != UTERM_FORMAT_GREY) return -EOPNOTSUPP; tmp = req->x + req->buf->width; if (tmp < req->x || req->x >= sw) return -EINVAL; if (tmp > sw) width = sw - req->x; else width = req->buf->width; tmp = req->y + req->buf->height; if (tmp < req->y || req->y >= sh) return -EINVAL; if (tmp > sh) height = sh - req->y; else height = req->buf->height; dst = rb->map; dst = &dst[req->y * rb->stride + req->x * 4]; src = req->buf->data; while (height--) { for (i = 0; i < width; ++i) { /* Division by 256 instead of 255 increases * speed by like 20% on slower machines. * Downside is, full white is 254/254/254 * instead of 255/255/255. */ if (src[i] == 0) { r = req->br; g = req->bg; b = req->bb; } else if (src[i] == 255) { r = req->fr; g = req->fg; b = req->fb; } else { r = req->fr * src[i] + req->br * (255 - src[i]); r /= 256; g = req->fg * src[i] + req->bg * (255 - src[i]); g /= 256; b = req->fb * src[i] + req->bb * (255 - src[i]); b /= 256; } ((uint32_t*)dst)[i] = (r << 16) | (g << 8) | b; } dst += rb->stride; src += req->buf->stride; } } return 0; }
static int display_blend(struct uterm_display *disp, const struct uterm_video_buffer *buf, unsigned int x, unsigned int y, uint8_t fr, uint8_t fg, uint8_t fb, uint8_t br, uint8_t bg, uint8_t bb) { unsigned int tmp; uint8_t *dst, *src; struct dumb_rb *rb; unsigned int width, height, i; unsigned int sw, sh; unsigned int r, g, b; if (!disp->video || !display_is_online(disp)) return -EINVAL; if (!buf || !video_is_awake(disp->video)) return -EINVAL; rb = &disp->dumb.rb[disp->dumb.current_rb ^ 1]; sw = disp->current_mode->dumb.info.hdisplay; sh = disp->current_mode->dumb.info.vdisplay; tmp = x + buf->width; if (tmp < x || x >= sw) return -EINVAL; if (tmp > sw) width = sw - x; else width = buf->width; tmp = y + buf->height; if (tmp < y || y >= sh) return -EINVAL; if (tmp > sh) height = sh - y; else height = buf->height; dst = rb->map; dst = &dst[y * rb->stride + x * 4]; src = buf->data; if (buf->format == UTERM_FORMAT_GREY) { while (height--) { for (i = 0; i < width; ++i) { r = (fr & 0xff) * src[i] / 255 + (br & 0xff) * (255 - src[i]) / 255; g = (fg & 0xff) * src[i] / 255 + (bg & 0xff) * (255 - src[i]) / 255; b = (fb & 0xff) * src[i] / 255 + (bb & 0xff) * (255 - src[i]) / 255; ((uint32_t*)dst)[i] = ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff); } dst += rb->stride; src += buf->stride; } } else { log_warning("using unsupported buffer format for blending"); } return 0; }
static int display_activate(struct uterm_display *disp, struct uterm_mode *mode) { struct uterm_video *video = disp->video; int ret, crtc, i; drmModeRes *res; drmModeConnector *conn; drmModeEncoder *enc; if (!video || !video_is_awake(video) || !mode) return -EINVAL; if (display_is_online(disp)) return -EINVAL; log_info("activating display %p to %ux%u", disp, mode->dumb.info.hdisplay, mode->dumb.info.vdisplay); res = drmModeGetResources(video->dumb.fd); if (!res) { log_err("cannot get resources for display %p", disp); return -EFAULT; } conn = drmModeGetConnector(video->dumb.fd, disp->dumb.conn_id); if (!conn) { log_err("cannot get connector for display %p", disp); drmModeFreeResources(res); return -EFAULT; } crtc = -1; for (i = 0; i < conn->count_encoders; ++i) { enc = drmModeGetEncoder(video->dumb.fd, conn->encoders[i]); if (!enc) continue; crtc = find_crtc(video, res, enc); drmModeFreeEncoder(enc); if (crtc >= 0) break; } drmModeFreeConnector(conn); drmModeFreeResources(res); if (crtc < 0) { log_warn("cannot find crtc for new display"); return -ENODEV; } disp->dumb.crtc_id = crtc; disp->dumb.current_rb = 0; disp->current_mode = mode; disp->dumb.saved_crtc = drmModeGetCrtc(video->dumb.fd, disp->dumb.crtc_id); ret = init_rb(disp, &disp->dumb.rb[0]); if (ret) goto err_saved; ret = init_rb(disp, &disp->dumb.rb[1]); if (ret) goto err_rb; ret = drmModeSetCrtc(video->dumb.fd, disp->dumb.crtc_id, disp->dumb.rb[0].fb, 0, 0, &disp->dumb.conn_id, 1, &disp->current_mode->dumb.info); if (ret) { log_err("cannot set drm-crtc"); ret = -EFAULT; goto err_fb; } disp->flags |= DISPLAY_ONLINE; return 0; err_fb: destroy_rb(disp, &disp->dumb.rb[1]); err_rb: destroy_rb(disp, &disp->dumb.rb[0]); err_saved: disp->current_mode = NULL; if (disp->dumb.saved_crtc) { drmModeFreeCrtc(disp->dumb.saved_crtc); disp->dumb.saved_crtc = NULL; } return ret; }
static int display_blend(struct uterm_display *disp, const struct uterm_video_buffer *buf, unsigned int x, unsigned int y, uint8_t fr, uint8_t fg, uint8_t fb, uint8_t br, uint8_t bg, uint8_t bb) { unsigned int tmp; uint8_t *dst, *src; struct dumb_rb *rb; unsigned int width, height, i; unsigned int sw, sh; unsigned int r, g, b; if (!disp->video || !display_is_online(disp)) return -EINVAL; if (!buf || !video_is_awake(disp->video)) return -EINVAL; rb = &disp->dumb.rb[disp->dumb.current_rb ^ 1]; sw = disp->current_mode->dumb.info.hdisplay; sh = disp->current_mode->dumb.info.vdisplay; tmp = x + buf->width; if (tmp < x || x >= sw) return -EINVAL; if (tmp > sw) width = sw - x; else width = buf->width; tmp = y + buf->height; if (tmp < y || y >= sh) return -EINVAL; if (tmp > sh) height = sh - y; else height = buf->height; dst = rb->map; dst = &dst[y * rb->stride + x * 4]; src = buf->data; if (buf->format == UTERM_FORMAT_GREY) { while (height--) { for (i = 0; i < width; ++i) { /* Division by 256 instead of 255 increases * speed by like 20% on slower machines. * Downside is, full white is 254/254/254 * instead of 255/255/255. */ if (src[i] == 0) { r = br; g = bg; b = bb; } else if (src[i] == 255) { r = fr; g = fg; b = fb; } else { r = fr * src[i] + br * (255 - src[i]); r /= 256; g = fg * src[i] + bg * (255 - src[i]); g /= 256; b = fb * src[i] + bb * (255 - src[i]); b /= 256; } ((uint32_t*)dst)[i] = (r << 16) | (g << 8) | b; } dst += rb->stride; src += buf->stride; } } else { log_warning("using unsupported buffer format for blending"); } return 0; }