Example #1
0
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);
}
Example #2
0
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;
}
Example #3
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;
}