예제 #1
0
static bool test(data_t *data, enum pipe pipe, igt_output_t *output)
{
	igt_plane_t *primary;
	drmModeModeInfo *mode;
	struct igt_fb fb[2];
	int fd, ret;

	/* select the pipe we want to use */
	igt_output_set_pipe(output, pipe);
	igt_display_commit(&data->display);

	if (!output->valid) {
		igt_output_set_pipe(output, PIPE_ANY);
		igt_display_commit(&data->display);
		return false;
	}

	primary = igt_output_get_plane(output, IGT_PLANE_PRIMARY);
	mode = igt_output_get_mode(output);

	igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
			    DRM_FORMAT_XRGB8888,
			    LOCAL_I915_FORMAT_MOD_X_TILED,
			    0.0, 0.0, 0.0, &fb[0]);

	igt_plane_set_fb(primary, &fb[0]);
	igt_display_commit2(&data->display, COMMIT_LEGACY);

	fd = drm_open_driver(DRIVER_INTEL);

	ret = drmDropMaster(data->drm_fd);
	igt_assert_eq(ret, 0);

	ret = drmSetMaster(fd);
	igt_assert_eq(ret, 0);

	igt_create_color_fb(fd, mode->hdisplay, mode->vdisplay,
			    DRM_FORMAT_XRGB8888,
			    LOCAL_I915_FORMAT_MOD_X_TILED,
			    0.0, 0.0, 0.0, &fb[1]);
	ret = drmModePageFlip(fd, output->config.crtc->crtc_id,
			      fb[1].fb_id, DRM_MODE_PAGE_FLIP_EVENT,
			      data);
	igt_assert_eq(ret, 0);

	ret = close(fd);
	igt_assert_eq(ret, 0);

	ret = drmSetMaster(data->drm_fd);
	igt_assert_eq(ret, 0);

	igt_plane_set_fb(primary, NULL);
	igt_output_set_pipe(output, PIPE_ANY);
	igt_display_commit(&data->display);

	igt_remove_fb(data->drm_fd, &fb[0]);

	return true;
}
예제 #2
0
static void
activate (ply_renderer_backend_t *backend)
{
  ply_list_node_t *node;

  ply_trace ("taking master and scanning out");
  backend->is_active = true;

  drmSetMaster (backend->device_fd);
  node = ply_list_get_first_node (backend->heads);
  while (node != NULL)
    {
      ply_list_node_t *next_node;
      ply_renderer_head_t *head;

      head = (ply_renderer_head_t *) ply_list_node_get_data (node);
      next_node = ply_list_get_next_node (backend->heads, node);

      if (head->scan_out_buffer_id != 0)
        {
          /* Flush out any pending drawing to the buffer
           */
          flush_head (backend, head);

          /* Then send the buffer to the monitor
           */
          ply_renderer_head_set_scan_out_buffer (backend, head,
                                                 head->scan_out_buffer_id);
        }

      node = next_node;
    }
}
static Bool
TegraScreenInit(SCREEN_INIT_ARGS_DECL)
{
    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
    TegraPtr tegra = TegraPTR(pScrn);
    VisualPtr visual;
    int ret;

    pScrn->pScreen = pScreen;

    ret = drmSetMaster(tegra->fd);
    if (ret) {
        ErrorF("Unable to set master\n");
        return FALSE;
    }

    /* HW dependent - FIXME */
    pScrn->displayWidth = pScrn->virtualX;

    if (!drmmode_create_initial_bos(pScrn, &tegra->drmmode))
        return FALSE;

    if (tegra->drmmode.shadow_enable) {
        tegra->drmmode.shadow_fb = calloc(1, pScrn->displayWidth * pScrn->virtualY *
                                             ((pScrn->bitsPerPixel + 7) >> 3));
        if (!tegra->drmmode.shadow_fb)
            tegra->drmmode.shadow_enable = FALSE;
    }
예제 #4
0
static void init(void)
{
	int fd = drmOpen("kgsl", NULL);

	drmSetMaster(fd);

	dev = fd_device_new(fd);
	pipe = fd_pipe_new(dev, FD_PIPE_2D);

	context_bos[0] = fd_bo_new(dev, 0x1000, DRM_FREEDRENO_GEM_TYPE_KMEM);
	context_bos[1] = fd_bo_new(dev, 0x9000, DRM_FREEDRENO_GEM_TYPE_KMEM);
	context_bos[2] = fd_bo_new(dev, 0x81000, DRM_FREEDRENO_GEM_TYPE_KMEM);

	next_ring();

	ring_pre(ring);

	BEGIN_RING(8);
	OUT_RING  (ring, REGM(VGV1_DIRTYBASE, 3));
	OUT_RELOC (ring, context_bos[0]); /* VGV1_DIRTYBASE */
	OUT_RELOC (ring, context_bos[1]); /* VGV1_CBASE1 */
	OUT_RELOC (ring, context_bos[2]); /* VGV1_UBASE2 */
	OUT_RING  (ring, 0x11000000);
	OUT_RING  (ring, 0x10fff000);
	OUT_RING  (ring, 0x10ffffff);
	OUT_RING  (ring, 0x0d000404);
	END_RING  ();
}
예제 #5
0
파일: plugin.c 프로젝트: pkt/pkt-plymouth
static void
activate (ply_renderer_backend_t *backend)
{
  ply_list_node_t *node;

  ply_trace ("taking master and scanning out");
  backend->is_active = true;

  drmSetMaster (backend->device_fd);
  node = ply_list_get_first_node (backend->heads);
  while (node != NULL)
    {
      ply_list_node_t *next_node;
      ply_renderer_head_t *head;

      head = (ply_renderer_head_t *) ply_list_node_get_data (node);
      next_node = ply_list_get_next_node (backend->heads, node);

      if (head->scan_out_buffer_id != 0)
        ply_renderer_head_set_scan_out_buffer (backend, head,
                                               head->scan_out_buffer_id);

      node = next_node;
    }
}
예제 #6
0
파일: DRMUtils.cpp 프로젝트: ssfdre38/xbmc
bool CDRMUtils::InitDrm()
{
  if(m_fd >= 0)
  {
    /* caps need to be set before allocating connectors, encoders, crtcs, and planes */
    auto ret = drmSetClientCap(m_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
    if (ret)
    {
      CLog::Log(LOGERROR, "CDRMUtils::%s - failed to set Universal planes capability: %s", __FUNCTION__, strerror(errno));
      return false;
    }

    if(!GetResources())
    {
      return false;
    }

    if(!GetConnector())
    {
      return false;
    }

    if(!GetEncoder())
    {
      return false;
    }

    if(!GetCrtc())
    {
      return false;
    }

    if(!GetPlanes())
    {
      return false;
    }
  }

  drmModeFreeResources(m_drm_resources);
  m_drm_resources = nullptr;

  if(m_fd < 0)
  {
    return false;
  }

  if(!GetPreferredMode())
  {
    return false;
  }

  drmSetMaster(m_fd);

  m_orig_crtc = drmModeGetCrtc(m_fd, m_crtc->crtc->crtc_id);

  return true;
}
예제 #7
0
파일: launch.c 프로젝트: michaelforney/swc
static void
start_devices(void)
{
	int i;

	for (i = 0; i < num_drm_fds; ++i) {
		if (drmSetMaster(drm_fds[i]) < 0)
			die("failed to set DRM master");
	}
}
예제 #8
0
int
weston_launcher_drm_set_master(struct weston_compositor *compositor,
			       int drm_fd, char master)
{
	struct msghdr msg;
	struct cmsghdr *cmsg;
	struct iovec iov;
	char control[CMSG_SPACE(sizeof(drm_fd))];
	int ret;
	ssize_t len;
	struct weston_launcher_set_master message;
	union cmsg_data *data;

	if (compositor->launcher_sock == -1) {
		if (master)
			return drmSetMaster(drm_fd);
		else
			return drmDropMaster(drm_fd);
	}

	memset(&msg, 0, sizeof msg);
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;
	msg.msg_control = control;
	msg.msg_controllen = sizeof control;
	cmsg = CMSG_FIRSTHDR(&msg);
	cmsg->cmsg_level = SOL_SOCKET;
	cmsg->cmsg_type = SCM_RIGHTS;
	cmsg->cmsg_len = CMSG_LEN(sizeof(drm_fd));

	data = (union cmsg_data *) CMSG_DATA(cmsg);
	data->fd = drm_fd;
	msg.msg_controllen = cmsg->cmsg_len;

	iov.iov_base = &message;
	iov.iov_len = sizeof message;

	message.header.opcode = WESTON_LAUNCHER_DRM_SET_MASTER;
	message.set_master = master;

	do {
		len = sendmsg(compositor->launcher_sock, &msg, 0);
	} while (len < 0 && errno == EINTR);
	if (len < 0)
		return -1;

	do {
		len = recv(compositor->launcher_sock, &ret, sizeof ret, 0);
	} while (len < 0 && errno == EINTR);
	if (len < 0)
		return -1;

	return ret;
}
예제 #9
0
static int
handle_signal(struct weston_launch *wl)
{
	struct signalfd_siginfo sig;
	int pid, status, ret;

	if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) {
		error(0, errno, "reading signalfd failed");
		return -1;
	}

	switch (sig.ssi_signo) {
	case SIGCHLD:
		pid = waitpid(-1, &status, 0);
		if (pid == wl->child) {
			wl->child = 0;
			if (WIFEXITED(status))
				ret = WEXITSTATUS(status);
			else if (WIFSIGNALED(status))
				/*
				 * If weston dies because of signal N, we
				 * return 10+N. This is distinct from
				 * weston-launch dying because of a signal
				 * (128+N).
				 */
				ret = 10 + WTERMSIG(status);
			else
				ret = 0;
			quit(wl, ret);
		}
		break;
	case SIGTERM:
	case SIGINT:
		if (wl->child)
			kill(wl->child, sig.ssi_signo);
		break;
	case SIGUSR1:
		send_reply(wl, WESTON_LAUNCHER_DEACTIVATE);
		close_input_fds(wl);
		drmDropMaster(wl->drm_fd);
		ioctl(wl->tty, VT_RELDISP, 1);
		break;
	case SIGUSR2:
		ioctl(wl->tty, VT_RELDISP, VT_ACKACQ);
		drmSetMaster(wl->drm_fd);
		send_reply(wl, WESTON_LAUNCHER_ACTIVATE);
		break;
	default:
		return -1;
	}

	return 0;
}
예제 #10
0
파일: drm_egl.c 프로젝트: yoimbert/mpv
static void acquire_vt(void *data)
{
    struct MPGLContext *ctx = data;
    MP_VERBOSE(ctx->vo, "Acquiring VT");
    if (USE_MASTER) {
        struct priv *p = ctx->priv;
        if (drmSetMaster(p->kms->fd)) {
            MP_WARN(ctx->vo, "Failed to acquire DRM master: %s\n", mp_strerror(errno));
        }
    }

    crtc_setup(ctx);
}
예제 #11
0
mg::PlatformPriority probe_graphics_platform(mo::ProgramOption const& options)
{
    mir::assert_entry_point_signature<mg::PlatformProbe>(&probe_graphics_platform);
    auto const unparsed_arguments = options.unparsed_command_line();
    auto platform_option_used = false;

    for (auto const& token : unparsed_arguments)
    {
        if (token == (std::string("--") + vt_option_name))
            platform_option_used = true;
    }

    if (options.is_set(vt_option_name))
        platform_option_used = true;

    auto udev = std::make_shared<mir::udev::Context>();

    mir::udev::Enumerator drm_devices{udev};
    drm_devices.match_subsystem("drm");
    drm_devices.match_sysname("card[0-9]*");
    drm_devices.scan_devices();

    if (drm_devices.begin() == drm_devices.end())
        return mg::PlatformPriority::unsupported;

    // Check for master
    int tmp_fd = -1;
    for (auto& device : drm_devices)
    {
        tmp_fd = open(device.devnode(), O_RDWR | O_CLOEXEC);
        if (tmp_fd >= 0)
            break;
    }

    if (tmp_fd >= 0)
    {
        if (drmSetMaster(tmp_fd) >= 0)
        {
            drmDropMaster(tmp_fd);
            drmClose(tmp_fd);
            return mg::PlatformPriority::best;
        }
        else
            drmClose(tmp_fd);
    }

    if (platform_option_used)
        return mg::PlatformPriority::best;

    return mg::PlatformPriority::unsupported;
}
/*
 * Set as the master of a DRM device.
 */
int gralloc_drm_set_master(struct gralloc_drm_t *drm)
{
	int ret;

	ret = drmSetMaster(drm->fd);
	if (ret) {
		LOGE("Error: drmSetMaster failed: %s\n", strerror(errno));
		return -errno;
	} else {
		drm->first_post = 1;
		drm->master = 1;
		return 0;
	}
}
/*
 * This gets called when gaining control of the VT, and from ScreenInit().
 */
static Bool
TegraEnterVT(VT_FUNC_ARGS_DECL)
{
    SCRN_INFO_PTR(arg);
    TegraPtr tegra = TegraPTR(pScrn);

    pScrn->vtSema = TRUE;

    if (drmSetMaster(tegra->fd))
        xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "drmSetMaster failed: %s\n",
                   strerror(errno));

    if (!drmmode_set_desired_modes(pScrn, &tegra->drmmode))
        return FALSE;

    return TRUE;
}
예제 #14
0
static int
handle_setmaster(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
{
	int ret = -1;
	struct cmsghdr *cmsg;
	struct weston_launcher_set_master *message;
	union cmsg_data *data;

	if (len != sizeof(*message)) {
		error(0, 0, "missing value in setmaster request");
		goto out;
	}

	message = msg->msg_iov->iov_base;

	cmsg = CMSG_FIRSTHDR(msg);
	if (!cmsg ||
	    cmsg->cmsg_level != SOL_SOCKET ||
	    cmsg->cmsg_type != SCM_RIGHTS) {
		error(0, 0, "invalid control message");
		goto out;
	}

	data = (union cmsg_data *) CMSG_DATA(cmsg);
	if (data->fd == -1) {
		error(0, 0, "missing drm fd in socket request");
		goto out;
	}

	if (message->set_master)
		ret = drmSetMaster(data->fd);
	else
		ret = drmDropMaster(data->fd);

	close(data->fd);
out:
	do {
		len = send(wl->sock[0], &ret, sizeof ret, 0);
	} while (len < 0 && errno == EINTR);
	if (len < 0)
		return -1;

	return 0;
}
예제 #15
0
static Bool
SetMaster(ScrnInfoPtr pScrn)
{
    modesettingPtr ms = modesettingPTR(pScrn);
    int ret;

#ifdef XF86_PDEV_SERVER_FD
    if (ms->pEnt->location.type == BUS_PLATFORM &&
            (ms->pEnt->location.id.plat->flags & XF86_PDEV_SERVER_FD))
        return TRUE;
#endif

    ret = drmSetMaster(ms->fd);
    if (ret)
        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "drmSetMaster failed: %s\n",
                   strerror(errno));

    return ret == 0;
}
예제 #16
0
static int
vt_handler(int signal_number, void *data)
{
	struct weston_launcher *launcher = data;
	struct weston_compositor *compositor = launcher->compositor;

	if (compositor->session_active) {
		compositor->session_active = 0;
		wl_signal_emit(&compositor->session_signal, compositor);
		drmDropMaster(launcher->drm_fd);
		ioctl(launcher->tty, VT_RELDISP, 1);
	} else {
		ioctl(launcher->tty, VT_RELDISP, VT_ACKACQ);
		drmSetMaster(launcher->drm_fd);
		compositor->session_active = 1;
		wl_signal_emit(&compositor->session_signal, compositor);
	}

	return 1;
}
/** As long as we are using our fake DRI driver inside of Mesa, we only want
 *  to implement the minimum here to make Mesa load it. */
Bool VBOXDRIScreenInit(ScrnInfoPtr pScrn, ScreenPtr pScreen, VBOXPtr pVBox)
{
    DRI2InfoRec DRI2Info;
    unsigned i;

    memset(&DRI2Info, 0, sizeof(DRI2Info));
    pVBox->drmFD = -1;
    for (i = 0; i < RT_ELEMENTS(devicePaths); ++i)
    {
        int fd = open(devicePaths[i], O_RDWR);
        if (fd >= 0)
        {
            drmVersionPtr pVersion = drmGetVersion(fd);
            if (   pVersion
                && pVersion->name_len
                && !strcmp(pVersion->name, VBOX_DRM_DRIVER_NAME)
                && drmSetMaster(fd) == 0)
            {
                TRACE_LOG("Opened drm device %s\n", devicePaths[i]);
                DRI2Info.deviceName = devicePaths[i];
                /* Keep the driver open and hope that the path won't change. */
                pVBox->drmFD = fd;
                drmFreeVersion(pVersion);
                break;
            }
            close(fd);
            drmFreeVersion(pVersion);
        }
    }
    if (!DRI2Info.deviceName)
        return FALSE;
    DRI2Info.version = 3;
    DRI2Info.fd = pVBox->drmFD;
    DRI2Info.driverName = VBOX_DRI_DRIVER_NAME;
    DRI2Info.CopyRegion = VBOXDRICopyRegion;
    DRI2Info.Wait = NULL;
    DRI2Info.CreateBuffer = VBOXDRICreateBuffer;
    DRI2Info.DestroyBuffer = VBOXDRIDestroyBuffer;
    return DRI2ScreenInit(pScreen, &DRI2Info);
}
예제 #18
0
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;
}
예제 #19
0
int main(int argc, char *argv[])
{
	uint64_t has_dumb;
	int ret, fd, opt, i;
	void *map;

	struct drm_mode_destroy_dumb dreq;
	struct drm_mode_create_dumb creq;
	struct drm_mode_map_dumb mreq;

	drmModePlaneRes *resources;
	drmModePlane *plane = NULL;

	uint32_t handle, stride, size;
	uint32_t plane_id, crtc_id;
	uint32_t width, height;
	uint32_t posx, posy;
	uint32_t fb;

	/* parse command line */

	while ((opt = getopt(argc, argv, "x:y:w:v:c:p:h")) != -1) {
		switch (opt) {
			case 'x':
				posx = atoi(optarg);
				break;
			case 'y':
				posy = atoi(optarg);
				break;
			case 'w':
				width = atoi(optarg);
				break;
			case 'v':
				height = atoi(optarg);
				break;
			case 'p':
				plane_id = atoi(optarg);
				break;
			case 'c':
				crtc_id = atoi(optarg);
				break;
			case 'h':
			default:
				printf("usage: -h] -c <connector> -e <encoder> -m <mode>\n");
				printf("\t-h: this help message\n");
				printf("\t-c <crtc>			crtc id, default is 0\n");
				printf("\t-p <plane>		plane id, default is 0\n");
				printf("\t-x <posx>			plane top left corner xpos, default is 0'\n");
				printf("\t-y <posy>			plane top left corner ypos, default is 0'\n");
				printf("\t-w <width>		plane width, default is 0'\n");
				printf("\t-v <height>		plane height, default is 0'\n");
				exit(0);
		}
	}

	/* open drm device */

	fd = open(device_name, O_RDWR | O_CLOEXEC);
	if (fd < 0) {
		perror("cannot open drm device");
		exit(-1);
	}

	drmSetMaster(fd);

    /* check dumb buffer support */

	if (drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0) {
		perror("DRM_CAP_DUMB_BUFFER ioctl");
		ret = -EFAULT;
		goto err_close;
	}

	if (!has_dumb) {
		fprintf(stderr, "driver does not support dumb buffers\n");
		ret = -EFAULT;
		goto err_close;
	}

	/* get plane */

	resources = drmModeGetPlaneResources(fd);
	if (!resources || resources->count_planes == 0) {
		fprintf(stderr, "drmModeGetPlaneResources failed\n");
		ret = -ENODEV;
		goto err_close;
	}

	for (i = 0; i < resources->count_planes; i++) {
		drmModePlane *p = drmModeGetPlane(fd, resources->planes[i]);
		if (!p)
			continue;

		if (p->plane_id == plane_id) {
			plane = p;
			break;
		}

		drmModeFreePlane(plane);
	}

	if (!plane) {
		fprintf(stderr, "couldn't find specified plane\n");
		ret = -ENODEV;
		goto err_close;
	}

	/* create dumb buffer object */

	memset(&creq, 0, sizeof(creq));

	creq.height = height;
	creq.width = width;
	creq.bpp = 32;

	ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq);
	if (ret) {
		fprintf(stderr, "failed drmIoctl(DRM_IOCTL_MODE_CREATE_DUMB)\n");
		goto err_close;
	}

	handle = creq.handle;
	stride = creq.pitch;
	size = creq.size;

	/* create framebuffer for dumb buffer object */

	ret = drmModeAddFB(fd, width, height, 24, 32, stride, handle, &fb);
	if (ret) {
		fprintf(stderr, "cannot add drm framebuffer for dumb buffer object\n");
		goto err_destroy_dumb;
	}

	/* map dumb buffer object */

	memset(&mreq, 0, sizeof(mreq));

	mreq.handle = handle;

	ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
	if (ret) {
		fprintf(stderr, "failed drmIoctl(DRM_IOCTL_MODE_MAP_DUMB)\n");
		goto err_destroy_fb;
	}

	map = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, mreq.offset);
	if (map == MAP_FAILED) {
		fprintf(stderr, "cannot mmap dumb buffer\n");
		goto err_destroy_fb;
	}

	/* setup new plane */

	ret = drmModeSetPlane(fd, plane_id, crtc_id, fb, 0, posx, posy,
		width, height, 0, 0, width << 16, height << 16);
	if (ret) {
		fprintf(stderr, "cannot set plane\n");
		goto err_unmap;
	}

	/* draw on the screen */
	draw_test_image((uint32_t *) map, width, height);
	getchar();

	draw_fancy_image((uint32_t *) map, width, height);
	getchar();

	drmModeSetPlane(fd, plane_id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);

err_unmap:
	if (map)
		munmap(map, size);

err_destroy_fb:
	drmModeRmFB(fd, fb);

err_destroy_dumb:
	memset(&dreq, 0, sizeof(dreq));

	dreq.handle = handle;

	ret = drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
	if (ret) {
		fprintf(stderr, "cannot destroy dumb buffer\n");
	}

err_close:
	close(fd);

	return ret;
}
예제 #20
0
int
main(int argc, char **argv)
{
    int fd;
    uint32_t handle[MAX_VMS], stride[MAX_VMS];
    drmModeRes *resources;
    drmModeConnector *connector;
    drmModeEncoder *encoder;
    drmModeModeInfo *mode;
    int i;
    uint32_t fb_id[MAX_VMS], total_vms = 0, current_vm;

    struct drm_i915_gem_vgtfb create;

    fd = open("/dev/dri/card0", O_RDWR);
    drmSetMaster(fd);

    /* Find the first available connector with modes */

    resources = drmModeGetResources(fd);
    if (!resources) {
        fprintf(stderr, "drmModeGetResources failed\n");
        return -1;
    }

    for (i = 0; i < resources->count_connectors; i++) {
        connector = drmModeGetConnector(fd, resources->connectors[i]);
        if (connector == NULL)
            continue;

        if (connector->connection == DRM_MODE_CONNECTED &&
                connector->count_modes > 0)
            break;

        drmModeFreeConnector(connector);
    }

    if (i == resources->count_connectors) {
        fprintf(stderr, "No currently active connector found.\n");
        return -1;
    }

    printf("Using connector: %s\n", connector_type_str(connector->connector_type));

    for (i = 0; i < resources->count_encoders; i++) {
        encoder = drmModeGetEncoder(fd, resources->encoders[i]);

        if (encoder == NULL)
            continue;

        if (encoder->encoder_id == connector->encoder_id)
            break;

        drmModeFreeEncoder(encoder);
    }

    for (i = 0; i < connector->count_modes; i++) {
        mode = &connector->modes[i];
        if (!strcmp(mode->name, "1680x1050"))
            break;
    }

    printf("Using mode: %s\n", mode->name);


    for (i = 0; i < (argc - 1) && i < MAX_VMS; i++) {
        int ret;
        create.vmid = atoi(argv[i+1]);

        printf("Requesting object for VM %d\n", create.vmid);

        if (ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_VGTFB, &create)) {
            printf("drmIoctl failed for domain %d. ret = %d\n", create.vmid, ret);
            continue;
        }
        handle[i] = create.handle;
        stride[i] = create.stride;

        /* Create a KMS framebuffer handle to set a mode with */
        if (ret = drmModeAddFB(fd, mode->hdisplay, mode->vdisplay, 24, 32, stride[i], handle[i], &fb_id[i])) {
            printf("drmModeAddFB failed for handle %d. ret = %d\n", handle[i], ret);
            continue;
        }
        total_vms++;
    }

    drmDropMaster(fd);

    if (total_vms == 0)
        return -1;

    current_vm = 0;
    do {
        drmSetMaster(fd);
        drmModeSetCrtc(fd, encoder->crtc_id, fb_id[current_vm], 0, 0, &connector->connector_id, 1, mode);
        current_vm++;
        current_vm %= total_vms;
        drmDropMaster(fd);
    } while (getchar() != EOF);


    return 0;
}
예제 #21
0
파일: vo_drm.c 프로젝트: AppleNuts/mpv
static void modeset_destroy_fb(int fd, struct modeset_buf *buf)
{
    if (buf->map) {
        munmap(buf->map, buf->size);
    }
    if (buf->fb) {
        drmModeRmFB(fd, buf->fb);
    }
    if (buf->handle) {
        struct drm_mode_destroy_dumb dreq = {
            .handle = buf->handle,
        };
        drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
    }
}

static int modeset_create_fb(struct vo *vo, int fd, struct modeset_buf *buf)
{
    int ret = 0;

    buf->handle = 0;

    // create dumb buffer
    struct drm_mode_create_dumb creq = {
        .width = buf->width,
        .height = buf->height,
        .bpp = 32,
    };
    ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq);
    if (ret < 0) {
        MP_ERR(vo, "Cannot create dumb buffer: %s\n", mp_strerror(errno));
        ret = -errno;
        goto end;
    }
    buf->stride = creq.pitch;
    buf->size = creq.size;
    buf->handle = creq.handle;

    // create framebuffer object for the dumb-buffer
    ret = drmModeAddFB(fd, buf->width, buf->height, 24, 32, buf->stride,
                       buf->handle, &buf->fb);
    if (ret) {
        MP_ERR(vo, "Cannot create framebuffer: %s\n", mp_strerror(errno));
        ret = -errno;
        goto end;
    }

    // prepare buffer for memory mapping
    struct drm_mode_map_dumb mreq = {
        .handle = buf->handle,
    };
    ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
    if (ret) {
        MP_ERR(vo, "Cannot map dumb buffer: %s\n", mp_strerror(errno));
        ret = -errno;
        goto end;
    }

    // perform actual memory mapping
    buf->map = mmap(0, buf->size, PROT_READ | PROT_WRITE, MAP_SHARED,
                    fd, mreq.offset);
    if (buf->map == MAP_FAILED) {
        MP_ERR(vo, "Cannot map dumb buffer: %s\n", mp_strerror(errno));
        ret = -errno;
        goto end;
    }

    memset(buf->map, 0, buf->size);

end:
    if (ret == 0) {
        return 0;
    }

    modeset_destroy_fb(fd, buf);
    return ret;
}

static int modeset_find_crtc(struct vo *vo, int fd, drmModeRes *res,
                             drmModeConnector *conn, struct modeset_dev *dev)
{
    for (unsigned int i = 0; i < conn->count_encoders; ++i) {
        drmModeEncoder *enc = drmModeGetEncoder(fd, conn->encoders[i]);
        if (!enc) {
            MP_WARN(vo, "Cannot retrieve encoder %u:%u: %s\n",
                    i, conn->encoders[i], mp_strerror(errno));
            continue;
        }

        // iterate all global CRTCs
        for (unsigned int j = 0; j < res->count_crtcs; ++j) {
            // check whether this CRTC works with the encoder
            if (!(enc->possible_crtcs & (1 << j)))
                continue;

            dev->enc = enc;
            dev->crtc = enc->crtc_id;
            return 0;
        }

        drmModeFreeEncoder(enc);
    }

    MP_ERR(vo, "Connector %u has no suitable CRTC\n", conn->connector_id);
    return -ENOENT;
}

static bool is_connector_valid(struct vo *vo, int conn_id,
                               drmModeConnector *conn, bool silent)
{
    if (!conn) {
        if (!silent) {
            MP_ERR(vo, "Cannot get connector %d: %s\n", conn_id,
                   mp_strerror(errno));
        }
        return false;
    }

    if (conn->connection != DRM_MODE_CONNECTED) {
        if (!silent) {
            MP_ERR(vo, "Connector %d is disconnected\n", conn_id);
        }
        return false;
    }

    if (conn->count_modes == 0) {
        if (!silent) {
            MP_ERR(vo, "Connector %d has no valid modes\n", conn_id);
        }
        return false;
    }

    return true;
}

static int modeset_prepare_dev(struct vo *vo, int fd, int conn_id,
                               struct modeset_dev **out)
{
    struct modeset_dev *dev = NULL;
    drmModeConnector *conn = NULL;

    int ret = 0;
    *out = NULL;

    drmModeRes *res = drmModeGetResources(fd);
    if (!res) {
        MP_ERR(vo, "Cannot retrieve DRM resources: %s\n", mp_strerror(errno));
        ret = -errno;
        goto end;
    }

    if (conn_id == -1) {
        // get the first connected connector
        for (int i = 0; i < res->count_connectors; i++) {
            conn = drmModeGetConnector(fd, res->connectors[i]);
            if (is_connector_valid(vo, i, conn, true)) {
                conn_id = i;
                break;
            }
            if (conn) {
                drmModeFreeConnector(conn);
                conn = NULL;
            }
        }
        if (conn_id == -1) {
            MP_ERR(vo, "No connected connectors found\n");
            ret = -ENODEV;
            goto end;
        }
    }

    if (conn_id < 0 || conn_id >= res->count_connectors) {
        MP_ERR(vo, "Bad connector ID. Max valid connector ID = %u\n",
               res->count_connectors);
        ret = -ENODEV;
        goto end;
    }

    conn = drmModeGetConnector(fd, res->connectors[conn_id]);
    if (!is_connector_valid(vo, conn_id, conn, false)) {
        ret = -ENODEV;
        goto end;
    }

    dev = talloc_zero(vo->priv, struct modeset_dev);
    dev->conn = conn->connector_id;
    dev->front_buf = 0;
    dev->mode = conn->modes[0];
    dev->bufs[0].width = conn->modes[0].hdisplay;
    dev->bufs[0].height = conn->modes[0].vdisplay;
    dev->bufs[1].width = conn->modes[0].hdisplay;
    dev->bufs[1].height = conn->modes[0].vdisplay;

    MP_INFO(vo, "Connector using mode %ux%u\n",
            dev->bufs[0].width, dev->bufs[0].height);

    ret = modeset_find_crtc(vo, fd, res, conn, dev);
    if (ret) {
        MP_ERR(vo, "Connector %d has no valid CRTC\n", conn_id);
        goto end;
    }

    for (unsigned int i = 0; i < BUF_COUNT; i++) {
        ret = modeset_create_fb(vo, fd, &dev->bufs[i]);
        if (ret) {
            MP_ERR(vo, "Cannot create framebuffer for connector %d\n",
                   conn_id);
            for (unsigned int j = 0; j < i; j++) {
                modeset_destroy_fb(fd, &dev->bufs[j]);
            }
            goto end;
        }
    }

end:
    if (conn) {
        drmModeFreeConnector(conn);
        conn = NULL;
    }
    if (res) {
        drmModeFreeResources(res);
        res = NULL;
    }
    if (ret == 0) {
        *out = dev;
    } else {
        talloc_free(dev);
    }
    return ret;
}

static void modeset_page_flipped(int fd, unsigned int frame, unsigned int sec,
                                 unsigned int usec, void *data)
{
    struct priv *p = data;
    p->pflip_happening = false;
}



static int setup_vo_crtc(struct vo *vo)
{
    struct priv *p = vo->priv;
    if (p->active)
        return 0;
    p->old_crtc = drmModeGetCrtc(p->fd, p->dev->crtc);
    int ret = drmModeSetCrtc(p->fd, p->dev->crtc,
                          p->dev->bufs[p->dev->front_buf + BUF_COUNT - 1].fb,
                          0, 0, &p->dev->conn, 1, &p->dev->mode);
    p->active = true;
    return ret;
}

static void release_vo_crtc(struct vo *vo)
{
    struct priv *p = vo->priv;

    if (!p->active)
        return;
    p->active = false;

    // wait for current page flip
    while (p->pflip_happening) {
        int ret = drmHandleEvent(p->fd, &p->ev);
        if (ret) {
            MP_ERR(vo, "drmHandleEvent failed: %i\n", ret);
            break;
        }
    }

    if (p->old_crtc) {
        drmModeSetCrtc(p->fd,
                       p->old_crtc->crtc_id,
                       p->old_crtc->buffer_id,
                       p->old_crtc->x,
                       p->old_crtc->y,
                       &p->dev->conn,
                       1,
                       &p->dev->mode);
        drmModeFreeCrtc(p->old_crtc);
        p->old_crtc = NULL;
    }
}

static void release_vt(void *data)
{
    struct vo *vo = data;
    release_vo_crtc(vo);
    if (USE_MASTER) {
        //this function enables support for switching to x, weston etc.
        //however, for whatever reason, it can be called only by root users.
        //until things change, this is commented.
        struct priv *p = vo->priv;
        if (drmDropMaster(p->fd)) {
            MP_WARN(vo, "Failed to drop DRM master: %s\n", mp_strerror(errno));
        }
    }
}

static void acquire_vt(void *data)
{
    struct vo *vo = data;
    if (USE_MASTER) {
        struct priv *p = vo->priv;
        if (drmSetMaster(p->fd)) {
            MP_WARN(vo, "Failed to acquire DRM master: %s\n", mp_strerror(errno));
        }
    }

    setup_vo_crtc(vo);
}



static int wait_events(struct vo *vo, int64_t until_time_us)
{
    struct priv *p = vo->priv;
    int64_t wait_us = until_time_us - mp_time_us();
    int timeout_ms = MPCLAMP((wait_us + 500) / 1000, 0, 10000);
    vt_switcher_poll(&p->vt_switcher, timeout_ms);
    return 0;
}

static void wakeup(struct vo *vo)
{
    struct priv *p = vo->priv;
    vt_switcher_interrupt_poll(&p->vt_switcher);
}

static int reconfig(struct vo *vo, struct mp_image_params *params, int flags)
{
    struct priv *p = vo->priv;

    vo->dwidth = p->device_w;
    vo->dheight = p->device_h;
    vo_get_src_dst_rects(vo, &p->src, &p->dst, &p->osd);

    int32_t w = p->dst.x1 - p->dst.x0;
    int32_t h = p->dst.y1 - p->dst.y0;

    // p->osd contains the parameters assuming OSD rendering in window
    // coordinates, but OSD can only be rendered in the intersection
    // between window and video rectangle (i.e. not into panscan borders).
    p->osd.w = w;
    p->osd.h = h;
    p->osd.mt = MPMIN(0, p->osd.mt);
    p->osd.mb = MPMIN(0, p->osd.mb);
    p->osd.mr = MPMIN(0, p->osd.mr);
    p->osd.ml = MPMIN(0, p->osd.ml);

    p->x = (p->device_w - w) >> 1;
    p->y = (p->device_h - h) >> 1;

    mp_sws_set_from_cmdline(p->sws, vo->opts->sws_opts);
    p->sws->src = *params;
    p->sws->dst = (struct mp_image_params) {
        .imgfmt = IMGFMT_BGR0,
        .w = w,
        .h = h,
        .d_w = w,
        .d_h = h,
    };

    talloc_free(p->cur_frame);
    p->cur_frame = mp_image_alloc(IMGFMT_BGR0, p->device_w, p->device_h);
    mp_image_params_guess_csp(&p->sws->dst);
    mp_image_set_params(p->cur_frame, &p->sws->dst);

    struct modeset_buf *buf = p->dev->bufs;
    memset(buf[0].map, 0, buf[0].size);
    memset(buf[1].map, 0, buf[1].size);

    if (mp_sws_reinit(p->sws) < 0)
        return -1;

    vo->want_redraw = true;
    return 0;
}

static void draw_image(struct vo *vo, mp_image_t *mpi)
{
    struct priv *p = vo->priv;

    if (p->active) {
        struct mp_image src = *mpi;
        struct mp_rect src_rc = p->src;
        src_rc.x0 = MP_ALIGN_DOWN(src_rc.x0, mpi->fmt.align_x);
        src_rc.y0 = MP_ALIGN_DOWN(src_rc.y0, mpi->fmt.align_y);
        mp_image_crop_rc(&src, src_rc);
        mp_sws_scale(p->sws, p->cur_frame, &src);
        osd_draw_on_image(vo->osd, p->osd, src.pts, 0, p->cur_frame);

        struct modeset_buf *front_buf = &p->dev->bufs[p->dev->front_buf];
        int32_t shift = (p->device_w * p->y + p->x) * 4;
        memcpy_pic(front_buf->map + shift,
                   p->cur_frame->planes[0],
                   (p->dst.x1 - p->dst.x0) * 4,
                   p->dst.y1 - p->dst.y0,
                   p->device_w * 4,
                   p->cur_frame->stride[0]);
    }

    if (mpi != p->last_input) {
        talloc_free(p->last_input);
        p->last_input = mpi;
    }
}

static void flip_page(struct vo *vo)
{
    struct priv *p = vo->priv;
    if (!p->active || p->pflip_happening)
        return;

    int ret = drmModePageFlip(p->fd, p->dev->crtc,
                              p->dev->bufs[p->dev->front_buf].fb,
                              DRM_MODE_PAGE_FLIP_EVENT, p);
    if (ret) {
        MP_WARN(vo, "Cannot flip page for connector\n");
    } else {
        p->dev->front_buf++;
        p->dev->front_buf %= BUF_COUNT;
        p->pflip_happening = true;
    }

    // poll page flip finish event
    const int timeout_ms = 3000;
    struct pollfd fds[1] = {
        { .events = POLLIN, .fd = p->fd },
    };
    poll(fds, 1, timeout_ms);
    if (fds[0].revents & POLLIN) {
        ret = drmHandleEvent(p->fd, &p->ev);
        if (ret != 0) {
            MP_ERR(vo, "drmHandleEvent failed: %i\n", ret);
            return;
        }
    }
}

static void uninit(struct vo *vo)
{
    struct priv *p = vo->priv;

    if (p->dev) {
        release_vo_crtc(vo);

        modeset_destroy_fb(p->fd, &p->dev->bufs[1]);
        modeset_destroy_fb(p->fd, &p->dev->bufs[0]);
        drmModeFreeEncoder(p->dev->enc);
    }

    vt_switcher_destroy(&p->vt_switcher);
    talloc_free(p->last_input);
    talloc_free(p->cur_frame);
    talloc_free(p->dev);
    close(p->fd);
}

static int preinit(struct vo *vo)
{
    struct priv *p = vo->priv;
    p->sws = mp_sws_alloc(vo);
    p->fd = -1;
    p->ev.version = DRM_EVENT_CONTEXT_VERSION;
    p->ev.page_flip_handler = modeset_page_flipped;

    if (vt_switcher_init(&p->vt_switcher, vo->log))
        goto err;

    vt_switcher_acquire(&p->vt_switcher, acquire_vt, vo);
    vt_switcher_release(&p->vt_switcher, release_vt, vo);

    if (modeset_open(vo, &p->fd, p->device_path))
        goto err;

    if (modeset_prepare_dev(vo, p->fd, p->connector_id, &p->dev))
        goto err;

    assert(p->dev);
    p->device_w = p->dev->bufs[0].width;
    p->device_h = p->dev->bufs[0].height;

    if (setup_vo_crtc(vo)) {
        MP_ERR(vo, "Cannot set CRTC for connector %u: %s\n", p->connector_id,
               mp_strerror(errno));
        goto err;
    }

    return 0;

err:
    uninit(vo);
    return -1;
}

static int query_format(struct vo *vo, int format)
{
    return sws_isSupportedInput(imgfmt2pixfmt(format));
}

static int control(struct vo *vo, uint32_t request, void *data)
{
    struct priv *p = vo->priv;
    switch (request) {
    case VOCTRL_SCREENSHOT_WIN:
        *(struct mp_image**)data = mp_image_new_copy(p->cur_frame);
        return VO_TRUE;
    case VOCTRL_REDRAW_FRAME:
        draw_image(vo, p->last_input);
        return VO_TRUE;
    case VOCTRL_GET_PANSCAN:
        return VO_TRUE;
    case VOCTRL_SET_PANSCAN:
        if (vo->config_ok)
            reconfig(vo, vo->params, 0);
        return VO_TRUE;
    }
    return VO_NOTIMPL;
}

#define OPT_BASE_STRUCT struct priv

const struct vo_driver video_out_drm = {
    .name = "drm",
    .description = "Direct Rendering Manager",
    .preinit = preinit,
    .query_format = query_format,
    .reconfig = reconfig,
    .control = control,
    .draw_image = draw_image,
    .flip_page = flip_page,
    .uninit = uninit,
    .wait_events = wait_events,
    .wakeup = wakeup,
    .priv_size = sizeof(struct priv),
    .options = (const struct m_option[]) {
        OPT_STRING("devpath", device_path, 0),
        OPT_INT("connector", connector_id, 0),
        {0},
    },
    .priv_defaults = &(const struct priv) {