static void bind_display(struct uterm_video *video, drmModeRes *res, drmModeConnector *conn) { struct uterm_display *disp; struct uterm_mode *mode; int ret, i; ret = display_new(&disp, &dumb_display_ops); if (ret) return; for (i = 0; i < conn->count_modes; ++i) { ret = mode_new(&mode, &dumb_mode_ops); if (ret) continue; mode->dumb.info = 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"); uterm_display_unref(disp); return; } disp->video = video; disp->dumb.conn_id = conn->connector_id; disp->flags |= DISPLAY_AVAILABLE; disp->next = video->displays; video->displays = disp; disp->dpms = get_dpms(disp, conn); log_info("display %p DPMS is %s", disp, uterm_dpms_to_name(disp->dpms)); VIDEO_CB(video, disp, UTERM_NEW); }
static gboolean fill_screen_info_from_resources (ScreenInfo *info, XRRScreenResources *resources, GError **error) { int i; GPtrArray *a; MateRRCrtc **crtc; MateRROutput **output; info->resources = resources; /* We create all the structures before initializing them, so * that they can refer to each other. */ a = g_ptr_array_new (); for (i = 0; i < resources->ncrtc; ++i) { MateRRCrtc *crtc = crtc_new (info, resources->crtcs[i]); g_ptr_array_add (a, crtc); } g_ptr_array_add (a, NULL); info->crtcs = (MateRRCrtc **)g_ptr_array_free (a, FALSE); a = g_ptr_array_new (); for (i = 0; i < resources->noutput; ++i) { MateRROutput *output = output_new (info, resources->outputs[i]); g_ptr_array_add (a, output); } g_ptr_array_add (a, NULL); info->outputs = (MateRROutput **)g_ptr_array_free (a, FALSE); a = g_ptr_array_new (); for (i = 0; i < resources->nmode; ++i) { MateRRMode *mode = mode_new (info, resources->modes[i].id); g_ptr_array_add (a, mode); } g_ptr_array_add (a, NULL); info->modes = (MateRRMode **)g_ptr_array_free (a, FALSE); /* Initialize */ for (crtc = info->crtcs; *crtc; ++crtc) { if (!crtc_initialize (*crtc, resources, error)) return FALSE; } for (output = info->outputs; *output; ++output) { if (!output_initialize (*output, resources, error)) return FALSE; } for (i = 0; i < resources->nmode; ++i) { MateRRMode *mode = mode_by_id (info, resources->modes[i].id); mode_initialize (mode, &(resources->modes[i])); } gather_clone_modes (info); return TRUE; }
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; }