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); }
static int display_swap(struct uterm_display *disp) { struct fb_var_screeninfo *vinfo; int ret; if (!disp->video || !video_is_awake(disp->video)) return -EINVAL; if (!(disp->flags & DISPLAY_ONLINE)) return -EINVAL; if (!(disp->flags & DISPLAY_DBUF)) return 0; vinfo = &disp->fbdev.vinfo; vinfo->activate = FB_ACTIVATE_VBL; if (!disp->fbdev.bufid) vinfo->yoffset = disp->fbdev.yres; else vinfo->yoffset = 0; ret = ioctl(disp->fbdev.fd, FBIOPUT_VSCREENINFO, vinfo); if (ret) { log_warning("cannot swap buffers on %s (%d): %m", disp->fbdev.node, errno); return -EFAULT; } disp->fbdev.bufid ^= 1; return 0; }
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_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); }
static void video_sleep(struct uterm_video *video) { if (!video_is_awake(video)) return; drmDropMaster(video->dumb.fd); video->flags &= ~VIDEO_AWAKE; }
void uterm_video_sleep(struct uterm_video *video) { if (!video || !video_is_awake(video)) return; VIDEO_CB(video, NULL, UTERM_SLEEP); VIDEO_CALL(video->ops->sleep, 0, video); }
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_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 void uterm_video_sleep(struct uterm_video *video) { if (!video || !video_is_awake(video)) return; log_debug("go asleep"); VIDEO_CB(video, NULL, UTERM_SLEEP); video->flags &= ~VIDEO_AWAKE; VIDEO_CALL(video->ops->sleep, 0, video); }
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; }
int uterm_video_wake_up(struct uterm_video *video) { int ret; if (!video) return -EINVAL; if (video_is_awake(video)) return 0; ret = VIDEO_CALL(video->ops->wake_up, 0, video); if (ret) return ret; VIDEO_CB(video, NULL, UTERM_WAKE_UP); return 0; }
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; unsigned int width, height; if (!disp->video || !(disp->flags & DISPLAY_ONLINE)) return -EINVAL; if (!buf || !video_is_awake(disp->video)) return -EINVAL; if (buf->format != UTERM_FORMAT_XRGB32) return -EINVAL; tmp = x + buf->width; if (tmp < x || x >= disp->fbdev.xres) return -EINVAL; if (tmp > disp->fbdev.xres) width = disp->fbdev.xres - x; else width = buf->width; tmp = y + buf->height; if (tmp < y || y >= disp->fbdev.yres) return -EINVAL; if (tmp > disp->fbdev.yres) height = disp->fbdev.yres - y; else height = buf->height; if (!(disp->flags & DISPLAY_DBUF) || disp->fbdev.bufid) dst = disp->fbdev.map; else dst = &disp->fbdev.map[disp->fbdev.yres * disp->fbdev.stride]; dst = &dst[y * disp->fbdev.stride + x * disp->fbdev.bpp]; src = buf->data; while (height--) { memcpy(dst, src, 4 * width); dst += disp->fbdev.stride; src += buf->stride; } return 0; }
static int 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) { unsigned int tmp, i; uint8_t *dst; struct dumb_rb *rb; unsigned int sw, sh; if (!disp->video || !(disp->flags & DISPLAY_ONLINE)) return -EINVAL; if (!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 + width; if (tmp < x || x >= sw) return -EINVAL; if (tmp > sw) width = sw - x; tmp = y + height; if (tmp < y || y >= sh) return -EINVAL; if (tmp > sh) height = sh - y; dst = rb->map; dst = &dst[y * rb->stride + x * 4]; while (height--) { for (i = 0; i < width; ++i) { ((uint32_t*)dst)[i] = ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff); } dst += rb->stride; } return 0; }
static int 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) { unsigned int tmp, i; uint8_t *dst; if (!disp->video || !(disp->flags & DISPLAY_ONLINE)) return -EINVAL; if (!video_is_awake(disp->video)) return -EINVAL; tmp = x + width; if (tmp < x || x >= disp->fbdev.xres) return -EINVAL; if (tmp > disp->fbdev.xres) width = disp->fbdev.xres - x; tmp = y + height; if (tmp < y || y >= disp->fbdev.yres) return -EINVAL; if (tmp > disp->fbdev.yres) height = disp->fbdev.yres - y; if (!(disp->flags & DISPLAY_DBUF) || disp->fbdev.bufid) dst = disp->fbdev.map; else dst = &disp->fbdev.map[disp->fbdev.yres * disp->fbdev.stride]; dst = &dst[y * disp->fbdev.stride + x * disp->fbdev.bpp]; while (height--) { for (i = 0; i < width; ++i) { ((uint32_t*)dst)[i] = ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff); } dst += disp->fbdev.stride; } return 0; }
SHL_EXPORT int uterm_video_wake_up(struct uterm_video *video) { int ret; if (!video) return -EINVAL; if (video_is_awake(video)) return 0; log_debug("wake up"); ret = VIDEO_CALL(video->ops->wake_up, 0, video); if (ret) { video->flags &= ~VIDEO_AWAKE; return ret; } video->flags |= VIDEO_AWAKE; VIDEO_CB(video, NULL, UTERM_WAKE_UP); 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 video_wake_up(struct uterm_video *video) { int ret; if (video_is_awake(video)) return 0; ret = drmSetMaster(video->dumb.fd); if (ret) { log_err("cannot set DRM-master"); return -EACCES; } video->flags |= VIDEO_AWAKE; ret = hotplug(video); if (ret) { video->flags &= ~VIDEO_AWAKE; drmDropMaster(video->dumb.fd); return ret; } show_displays(video); return 0; }
static int display_activate_force(struct uterm_display *disp, struct uterm_mode *mode, bool force) { static const char depths[] = { 32, 24, 16, 0 }; struct fb_var_screeninfo *vinfo; struct fb_fix_screeninfo *finfo; int ret, i; uint64_t quot; size_t len; if (!disp->video || !video_is_awake(disp->video)) return -EINVAL; if (!force && (disp->flags & DISPLAY_ONLINE)) return 0; /* TODO: We do not support explicit modesetting in fbdev, so we require * @mode to be NULL. You can still switch modes via "fbset" on the * console and then restart the app. It will automatically adapt to the * new mode. The only values changed here are bpp and color mode. */ if (mode) return -EINVAL; ret = refresh_info(disp); if (ret) return ret; finfo = &disp->fbdev.finfo; vinfo = &disp->fbdev.vinfo; vinfo->xoffset = 0; vinfo->yoffset = 0; vinfo->activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; vinfo->xres_virtual = vinfo->xres; vinfo->yres_virtual = vinfo->yres * 2; vinfo->bits_per_pixel = 32; log_info("activating display %s to %ux%u %u bpp", disp->fbdev.node, vinfo->xres, vinfo->yres, vinfo->bits_per_pixel); ret = ioctl(disp->fbdev.fd, FBIOPUT_VSCREENINFO, vinfo); if (ret) { disp->flags &= ~DISPLAY_DBUF; vinfo->yres_virtual = vinfo->yres; ret = ioctl(disp->fbdev.fd, FBIOPUT_VSCREENINFO, vinfo); if (ret) { log_err("cannot set vinfo (%d): %m", errno); return -EFAULT; } log_debug("disabling double buffering"); } else { disp->flags |= DISPLAY_DBUF; log_debug("enabling double buffering"); } ret = refresh_info(disp); if (ret) return ret; /* 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 * modes like pseudocolor or direct-color do not provide this. As I have * never seen a device that does not support TRUECOLOR, I think we can * ignore them here. */ if (finfo->visual != FB_VISUAL_TRUECOLOR) { for (i = 0; depths[i]; ++i) { vinfo->bits_per_pixel = depths[i]; vinfo->activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; ret = ioctl(disp->fbdev.fd, FBIOPUT_VSCREENINFO, vinfo); if (ret < 0) continue; ret = refresh_info(disp); if (ret) return ret; if (finfo->visual == FB_VISUAL_TRUECOLOR) break; } } if (vinfo->xres_virtual < vinfo->xres || (disp->flags & DISPLAY_DBUF && vinfo->yres_virtual < vinfo->yres * 2) || vinfo->yres_virtual < vinfo->yres) { log_error("device %s does not support out buffer sizes", disp->fbdev.node); return -EFAULT; } if (vinfo->bits_per_pixel % 8) { log_error("device %s uses no power of 8 bpp: %u", disp->fbdev.node, vinfo->bits_per_pixel); return -EFAULT; } if (finfo->visual != FB_VISUAL_TRUECOLOR || vinfo->bits_per_pixel < 16) { log_error("device %s does not support true-color bpp >= 16", disp->fbdev.node); return -EFAULT; } /* TODO: remove this check and correctly provide conversions for the * blitting functions. In fact, the for-loop above is totally useless * while using this restriction here but lets be optimistic and say that * this will be replaced soon. */ if (vinfo->red.offset != 16 || vinfo->red.length != 8 || vinfo->green.offset != 8 || vinfo->green.length != 8 || vinfo->blue.offset != 0 || vinfo->green.length != 8 || vinfo->bits_per_pixel != 32) { log_error("device %s does not support xrgb32", disp->fbdev.node); return -EFAULT; } /* calculate monitor rate, default is 60 Hz */ quot = (vinfo->upper_margin + vinfo->lower_margin + vinfo->yres); quot *= (vinfo->left_margin + vinfo->right_margin + vinfo->xres); quot *= vinfo->pixclock; if (quot) disp->fbdev.rate = 1000000000000000LLU / quot; else disp->fbdev.rate = 60 * 1000; len = finfo->line_length * vinfo->yres; if (disp->flags & DISPLAY_DBUF) len *= 2; disp->fbdev.map = mmap(0, len, PROT_WRITE, MAP_SHARED, disp->fbdev.fd, 0); if (disp->fbdev.map == MAP_FAILED) { log_error("cannot mmap device %s (%d): %m", disp->fbdev.node, errno); return -EFAULT; } memset(disp->fbdev.map, 0, len); disp->fbdev.xres = vinfo->xres; disp->fbdev.yres = vinfo->yres; disp->fbdev.len = len; disp->fbdev.bpp = vinfo->bits_per_pixel / 8; disp->fbdev.stride = finfo->line_length; disp->fbdev.bufid = 0; ret = mode_new(&disp->modes, &fbdev_mode_ops); if (ret) { munmap(disp->fbdev.map, disp->fbdev.len); return ret; } disp->modes->fbdev.width = disp->fbdev.xres; disp->modes->fbdev.height = disp->fbdev.yres; disp->current_mode = disp->modes; disp->flags |= DISPLAY_ONLINE; 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; unsigned int width, height, i; unsigned int r, g, b; if (!disp->video || !(disp->flags & DISPLAY_ONLINE)) return -EINVAL; if (!buf || !video_is_awake(disp->video)) return -EINVAL; tmp = x + buf->width; if (tmp < x || x >= disp->fbdev.xres) return -EINVAL; if (tmp > disp->fbdev.xres) width = disp->fbdev.xres - x; else width = buf->width; tmp = y + buf->height; if (tmp < y || y >= disp->fbdev.yres) return -EINVAL; if (tmp > disp->fbdev.yres) height = disp->fbdev.yres - y; else height = buf->height; if (!(disp->flags & DISPLAY_DBUF) || disp->fbdev.bufid) dst = disp->fbdev.map; else dst = &disp->fbdev.map[disp->fbdev.yres * disp->fbdev.stride]; dst = &dst[y * disp->fbdev.stride + x * disp->fbdev.bpp]; 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 += disp->fbdev.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 hotplug(struct uterm_video *video) { drmModeRes *res; drmModeConnector *conn; struct uterm_display *disp, *tmp; int i; if (!video_is_awake(video) || !video_need_hotplug(video)) return 0; res = drmModeGetResources(video->dumb.fd); if (!res) { log_err("cannot retrieve drm resources"); return -EACCES; } for (disp = video->displays; disp; disp = disp->next) disp->flags &= ~DISPLAY_AVAILABLE; for (i = 0; i < res->count_connectors; ++i) { conn = drmModeGetConnector(video->dumb.fd, res->connectors[i]); if (!conn) continue; if (conn->connection == DRM_MODE_CONNECTED) { for (disp = video->displays; disp; disp = disp->next) { if (disp->dumb.conn_id == res->connectors[i]) { disp->flags |= DISPLAY_AVAILABLE; break; } } if (!disp) bind_display(video, res, conn); } drmModeFreeConnector(conn); } 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); } } video->flags &= ~VIDEO_HOTPLUG; 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_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_set_dpms(struct uterm_display *disp, int state) { int i, ret, set; drmModeConnector *conn; drmModePropertyRes *prop; if (!display_is_conn(disp) || !video_is_awake(disp->video)) return -EINVAL; switch (state) { case UTERM_DPMS_ON: set = DRM_MODE_DPMS_ON; break; case UTERM_DPMS_STANDBY: set = DRM_MODE_DPMS_STANDBY; break; case UTERM_DPMS_SUSPEND: set = DRM_MODE_DPMS_SUSPEND; break; case UTERM_DPMS_OFF: set = DRM_MODE_DPMS_OFF; break; default: return -EINVAL; } log_info("setting DPMS of display %p to %s", disp, uterm_dpms_to_name(state)); conn = drmModeGetConnector(disp->video->dumb.fd, disp->dumb.conn_id); if (!conn) { log_err("cannot get display connector"); return -EFAULT; } ret = 0; for (i = 0; i < conn->count_props; ++i) { prop = drmModeGetProperty(disp->video->dumb.fd, conn->props[i]); if (!prop) continue; if (!strcmp(prop->name, "DPMS")) { ret = drmModeConnectorSetProperty(disp->video->dumb.fd, disp->dumb.conn_id, prop->prop_id, set); if (ret) { log_info("cannot set DPMS"); ret = -EFAULT; } drmModeFreeProperty(prop); break; } drmModeFreeProperty(prop); } if (i == conn->count_props) { ret = 0; log_warn("display does not support DPMS"); state = UTERM_DPMS_UNKNOWN; } drmModeFreeConnector(conn); disp->dpms = state; return ret; }
bool uterm_video_is_awake(struct uterm_video *video) { return video && video_is_awake(video); }
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; }