Пример #1
0
int main(int argc, char **argv)
{
	struct exynos_device *dev;
	struct exynos_bo *bo, *src;
	struct connector con;
	unsigned int fb_id;
	uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
	drmModeRes *resources;
	int ret, fd, c;

	memset(&con, 0, sizeof(struct connector));

	if (argc != 3) {
		usage(argv[0]);
		return -EINVAL;
	}

	while ((c = getopt(argc, argv, optstr)) != -1) {
		switch (c) {
		case 's':
			con.crtc = -1;
			if (sscanf(optarg, "%d:0x%64s",
						&con.id,
						con.mode_str) != 2 &&
					sscanf(optarg, "%d@%d:%64s",
						&con.id,
						&con.crtc,
						con.mode_str) != 3)
				usage(argv[0]);
			break;
		default:
			usage(argv[0]);
			return -EINVAL;
		}
	}

	fd = drmOpen(DRM_MODULE_NAME, NULL);
	if (fd < 0) {
		fprintf(stderr, "failed to open.\n");
		return fd;
	}

	dev = exynos_device_create(fd);
	if (!dev) {
		drmClose(dev->fd);
		return -EFAULT;
	}

	resources = drmModeGetResources(dev->fd);
	if (!resources) {
		fprintf(stderr, "drmModeGetResources failed: %s\n",
				strerror(errno));
		ret = -EFAULT;
		goto err_drm_close;
	}

	connector_find_mode(dev->fd, &con, resources);
	drmModeFreeResources(resources);

	if (!con.mode) {
		fprintf(stderr, "failed to find usable connector\n");
		ret = -EFAULT;
		goto err_drm_close;
	}

	screen_width = con.mode->hdisplay;
	screen_height = con.mode->vdisplay;

	if (screen_width == 0 || screen_height == 0) {
		fprintf(stderr, "failed to find sane resolution on connector\n");
		ret = -EFAULT;
		goto err_drm_close;
	}

	printf("screen width = %d, screen height = %d\n", screen_width,
			screen_height);

	bo = exynos_create_buffer(dev, screen_width * screen_height * 4, 0);
	if (!bo) {
		ret = -EFAULT;
		goto err_drm_close;
	}

	handles[0] = bo->handle;
	pitches[0] = screen_width * 4;
	offsets[0] = 0;

	ret = drmModeAddFB2(dev->fd, screen_width, screen_height,
				DRM_FORMAT_RGBA8888, handles,
				pitches, offsets, &fb_id, 0);
	if (ret < 0)
		goto err_destroy_buffer;

	con.plane_zpos = -1;

	memset(bo->vaddr, 0xff, screen_width * screen_height * 4);

	ret = drm_set_crtc(dev, &con, fb_id);
	if (ret < 0)
		goto err_rm_fb;

	ret = test_case.solid_fill(dev, bo);
	if (ret < 0) {
		fprintf(stderr, "failed to solid fill operation.\n");
		goto err_rm_fb;
	}

	wait_for_user_input(0);

	src = exynos_create_buffer(dev, screen_width * screen_height * 4, 0);
	if (!src) {
		ret = -EFAULT;
		goto err_rm_fb;
	}

	ret = test_case.copy(dev, src, bo, G2D_IMGBUF_GEM);
	if (ret < 0) {
		fprintf(stderr, "failed to test copy operation.\n");
		goto err_free_src;
	}

	wait_for_user_input(0);

	ret = test_case.copy_with_scale(dev, src, bo, G2D_IMGBUF_GEM);
	if (ret < 0) {
		fprintf(stderr, "failed to test copy and scale operation.\n");
		goto err_free_src;
	}

	wait_for_user_input(0);

	ret = test_case.checkerboard(dev, src, bo, G2D_IMGBUF_GEM);
	if (ret < 0) {
		fprintf(stderr, "failed to issue checkerboard test.\n");
		goto err_free_src;
	}

	wait_for_user_input(1);

	/*
	 * The blend test uses the userptr functionality of exynos-drm, which
	 * is currently not safe to use. If the kernel hasn't been build with
	 * exynos-iommu support, then the blend test is going to produce (kernel)
	 * memory corruption, eventually leading to a system crash.
	 *
	 * Disable the test for now, until the kernel code has been sanitized.
	 */
#if 0
	ret  = test_case.blend(dev, src, bo, G2D_IMGBUF_USERPTR);
	if (ret < 0)
		fprintf(stderr, "failed to test blend operation.\n");

	getchar();
#endif

err_free_src:
	if (src)
		exynos_destroy_buffer(src);

err_rm_fb:
	drmModeRmFB(dev->fd, fb_id);

err_destroy_buffer:
	exynos_destroy_buffer(bo);

err_drm_close:
	drmClose(dev->fd);
	exynos_device_destroy(dev);

	return 0;
}
Пример #2
0
static Bool
ms_do_pageflip(ScreenPtr screen,
               PixmapPtr new_front,
               struct ms_present_vblank_event *event,
               int ref_crtc_vblank_pipe,
               Bool async)
{
#ifndef GLAMOR_HAS_GBM
    return FALSE;
#else
    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    modesettingPtr ms = modesettingPTR(scrn);
    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
    drmmode_bo new_front_bo;
    uint32_t flags;
    int i;
    struct ms_flipdata *flipdata;
    glamor_block_handler(screen);

    new_front_bo.gbm = glamor_gbm_bo_from_pixmap(screen, new_front);
    new_front_bo.dumb = NULL;
    if (!new_front_bo.gbm) {
        xf86DrvMsg(scrn->scrnIndex, X_ERROR,
                   "Failed to get GBM bo for flip to new front.\n");
        return FALSE;
    }

    flipdata = calloc(1, sizeof(struct ms_flipdata));
    if (!flipdata) {
        drmmode_bo_destroy(&ms->drmmode, &new_front_bo);
        xf86DrvMsg(scrn->scrnIndex, X_ERROR,
                   "Failed to allocate flipdata.\n");
        return FALSE;
    }

    flipdata->event = event;
    flipdata->screen = screen;

    /*
     * Take a local reference on flipdata.
     * if the first flip fails, the sequence abort
     * code will free the crtc flip data, and drop
     * it's reference which would cause this to be
     * freed when we still required it.
     */
    flipdata->flip_count++;

    /* Create a new handle for the back buffer */
    flipdata->old_fb_id = ms->drmmode.fb_id;
    if (drmModeAddFB(ms->fd, scrn->virtualX, scrn->virtualY,
                     scrn->depth, scrn->bitsPerPixel,
                     drmmode_bo_get_pitch(&new_front_bo),
                     drmmode_bo_get_handle(&new_front_bo), &ms->drmmode.fb_id)) {
        goto error_out;
    }

    drmmode_bo_destroy(&ms->drmmode, &new_front_bo);

    flags = DRM_MODE_PAGE_FLIP_EVENT;
    if (async)
        flags |= DRM_MODE_PAGE_FLIP_ASYNC;

    /* Queue flips on all enabled CRTCs.
     *
     * Note that if/when we get per-CRTC buffers, we'll have to update this.
     * Right now it assumes a single shared fb across all CRTCs, with the
     * kernel fixing up the offset of each CRTC as necessary.
     *
     * Also, flips queued on disabled or incorrectly configured displays
     * may never complete; this is a configuration error.
     */
    for (i = 0; i < config->num_crtc; i++) {
        xf86CrtcPtr crtc = config->crtc[i];

        if (!ms_crtc_on(crtc))
            continue;

        if (!queue_flip_on_crtc(screen, crtc, flipdata,
                                ref_crtc_vblank_pipe,
                                flags)) {
            goto error_undo;
        }
    }

    /*
     * Do we have more than our local reference,
     * if so and no errors, then drop our local
     * reference and return now.
     */
    if (flipdata->flip_count > 1) {
        flipdata->flip_count--;
        return TRUE;
    }

error_undo:

    /*
     * Have we just got the local reference?
     * free the framebuffer if so since nobody successfully
     * submitted anything
     */
    if (flipdata->flip_count == 1) {
        drmModeRmFB(ms->fd, ms->drmmode.fb_id);
        ms->drmmode.fb_id = flipdata->old_fb_id;
    }

error_out:
    xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
               strerror(errno));
    /* if only the local reference - free the structure,
     * else drop the local reference and return */
    if (flipdata->flip_count == 1)
        free(flipdata);
    else
        flipdata->flip_count--;

    return FALSE;
#endif /* GLAMOR_HAS_GBM */
}
static Bool
nouveau_present_flip_exec(ScrnInfoPtr scrn, uint64_t event_id, int sync,
			  uint64_t target_msc, PixmapPtr pixmap, Bool vsync)
{
	ScreenPtr screen = scrn->pScreen;
	struct nouveau_pixmap *priv = NULL;
	NVPtr pNv = NVPTR(scrn);
	uint32_t next_fb;
	CARD16 stride;
	CARD32 size;
	void *token;
	int ret;

#ifdef HAVE_GLAMOR
	if (pNv->AccelMethod == GLAMOR &&
	    !(priv = nouveau_glamor_pixmap_get(pixmap))) {
		int fd = glamor_fd_from_pixmap(screen, pixmap, &stride, &size);
		if (fd < 0)
			return FALSE;

		priv = calloc(1, sizeof(*priv));
		if (!priv)
			return FALSE;

		ret = nouveau_bo_prime_handle_ref(pNv->dev, fd, &priv->bo);
		if (ret) {
			free(priv);
			return FALSE;
		}

		nouveau_glamor_pixmap_set(pixmap, priv);
	} else
#endif
	if (!priv)
		priv = nouveau_pixmap(pixmap);

	ret = drmModeAddFB(pNv->dev->fd, pixmap->drawable.width,
			   pixmap->drawable.height, pixmap->drawable.depth,
			   pixmap->drawable.bitsPerPixel, pixmap->devKind,
			   priv->bo->handle, &next_fb);
	if (ret == 0) {
		struct nouveau_present_flip *flip =
			drmmode_event_queue(scrn, event_id, sizeof(*flip),
					    nouveau_present_flip, &token);
		if (flip) {
			xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
			int last = 0, i;

			drmmode_swap(scrn, next_fb, &flip->old);
			flip->fd = pNv->dev->fd;
			flip->msc = target_msc;

			for (i = 0; i < config->num_crtc; i++) {
				if (config->crtc[i]->enabled)
					last = i;
			}

			for (i = 0; i < config->num_crtc; i++) {
				int type = vsync ? 0 : DRM_MODE_PAGE_FLIP_ASYNC;
				int crtc = drmmode_crtc(config->crtc[i]);
				void *user = NULL;

				if (!config->crtc[i]->enabled)
					continue;

				if (token && ((crtc == sync) || (i == last))) {
					type |= DRM_MODE_PAGE_FLIP_EVENT;
					user  = token;
				}

				ret = drmModePageFlip(pNv->dev->fd, crtc,
						      next_fb, type, user);
				if (ret == 0 && user) {
					token = NULL;
				}
			}

			if (token == NULL) {
				return TRUE;
			}

			drmmode_swap(scrn, flip->old, &next_fb);
			drmmode_event_abort(scrn, event_id, false);
		}

		drmModeRmFB(pNv->dev->fd, next_fb);
	}

	return FALSE;
}
Пример #4
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;
}
Пример #5
0
/**
 * igt_remove_fb:
 * @fd: open i915 drm file descriptor
 * @fb: pointer to an #igt_fb structure
 *
 * This function releases all resources allocated in igt_create_fb() for @fb.
 * Note that if this framebuffer is still in use on a primary plane the kernel
 * will disable the corresponding crtc.
 */
void igt_remove_fb(int fd, struct igt_fb *fb)
{
	cairo_surface_destroy(fb->cairo_surface);
	do_or_die(drmModeRmFB(fd, fb->fb_id));
	gem_close(fd, fb->gem_handle);
}
static void ricochet(int tiled, int sprite_w, int sprite_h,
		     int out_w, int out_h, int dump_info)
{
	int                                 ret;
	int                                 gfx_fd;
	int                                 keep_moving;
	const int                           num_surfaces = 3;
	uint32_t                            sprite_handles[num_surfaces];
	uint32_t                            sprite_fb_id[num_surfaces];
	int                                 *sprite_x = NULL;
	int                                 *sprite_y = NULL;
	uint32_t                            sprite_stride;
	uint32_t                            sprite_size;
	uint32_t                            handles[4],
					    pitches[4],
					    offsets[4]; /* we only use [0] */
	uint32_t                            prim_width,
					    prim_height,
					    prim_handle,
					    prim_stride,
					    prim_size,
					    prim_fb_id;
	struct drm_intel_sprite_colorkey    set;
	struct connector                    curr_connector;
	drmModeRes                          *gfx_resources;
	struct termios                      orig_term,
					    curr_term;
	int                                 c_index;
	int                                 sprite_index;
	unsigned int                        *sprite_plane_id = NULL;
	uint32_t                            plane_flags = 0;
	int                                 *delta_x = NULL,
					    *delta_y = NULL;
	struct timeval                      stTimeVal;
	long long                           currTime,
	     prevFlipTime,
	     prevMoveTime,
	     deltaFlipTime,
	     deltaMoveTime,
	     SleepTime;
	char                                key;
	int				    sprite_plane_count = 0;
	int 				    i;
	// Open up I915 graphics device
	gfx_fd = drmOpen("i915", NULL);
	if (gfx_fd < 0) {
		printf("Failed to load i915 driver: %s\n", strerror(errno));
		return;
	}

	// Obtain pointer to struct containing graphics resources
	gfx_resources = drmModeGetResources(gfx_fd);
	if (!gfx_resources) {
		printf("drmModeGetResources failed: %s\n", strerror(errno));
		return;
	}

	if (dump_info != 0) {
		dump_connectors(gfx_fd, gfx_resources);
		dump_crtcs(gfx_fd, gfx_resources);
		dump_planes(gfx_fd, gfx_resources);
	}

	// Save previous terminal settings
	if (tcgetattr( 0, &orig_term) != 0) {
		printf("tcgetattr failure: %s\n",
				strerror(errno));
		return;
	}

	// Set up input to return characters immediately
	curr_term = orig_term;
	curr_term.c_lflag &= ~(ICANON | ECHO | ECHONL);
	curr_term.c_cc[VMIN] = 0;       // No minimum number of characters
	curr_term.c_cc[VTIME] = 0 ;     // Return immediately, even if
	// nothing has been entered.
	if (tcsetattr( 0, TCSANOW, &curr_term) != 0) {
		printf("tcgetattr failure: %s\n", strerror(errno));
		return;
	}

	// Cycle through all connectors and display the flying sprite
	// where there are displays attached and the hardware will support it.
	for (c_index = 0; c_index < gfx_resources->count_connectors; c_index++)  {
		curr_connector.id = gfx_resources->connectors[c_index];

		// Find the native (preferred) display mode
		connector_find_preferred_mode(gfx_fd, gfx_resources, &curr_connector);
		if (curr_connector.mode_valid == 0) {
			printf("No valid preferred mode detected\n");
			goto out;
		}

		// Determine if sprite hardware is available on pipe
		// associated with this connector.
		sprite_plane_count = connector_find_plane(gfx_fd, &curr_connector,
							  &sprite_plane_id);
		if (!sprite_plane_count) {
			printf("Failed to find sprite plane on crtc\n");
			goto out;
		}

		// Width and height of preferred mode
		prim_width = curr_connector.mode.hdisplay;
		prim_height = curr_connector.mode.vdisplay;

		// Allocate and fill memory for primary surface
		ret = prepare_primary_surface(
				gfx_fd,
				prim_width,
				prim_height,
				&prim_handle,
				&prim_stride,
				&prim_size,
				tiled);
		if (ret != 0) {
			printf("Failed to add primary fb (%dx%d): %s\n",
				prim_width, prim_height, strerror(errno));
			goto out;
		}

		// Add the primary surface framebuffer
		ret = drmModeAddFB(gfx_fd, prim_width, prim_height, 24, 32,
				   prim_stride, prim_handle, &prim_fb_id);
		gem_close(gfx_fd, prim_handle);

		if (ret != 0) {
			printf("Failed to add primary fb (%dx%d): %s\n",
					prim_width, prim_height, strerror(errno));
			goto out;
		}

		// Allocate and fill sprite surfaces
		ret = prepare_sprite_surfaces(gfx_fd, sprite_w, sprite_h, num_surfaces,
					      &sprite_handles[0],
					      &sprite_stride, &sprite_size,
					      tiled);
		if (ret != 0) {
			printf("Preparation of sprite surfaces failed %dx%d\n",
				sprite_w, sprite_h);
			goto out;
		}

		// Add the sprite framebuffers
		for (sprite_index = 0; sprite_index < num_surfaces; sprite_index++) {
			handles[0] = sprite_handles[sprite_index];
			handles[1] = handles[0];
			handles[2] = handles[0];
			handles[3] = handles[0];
			pitches[0] = sprite_stride;
			pitches[1] = sprite_stride;
			pitches[2] = sprite_stride;
			pitches[3] = sprite_stride;
			memset(offsets, 0, sizeof(offsets));

			ret = drmModeAddFB2(gfx_fd, sprite_w, sprite_h,
					    DRM_FORMAT_XRGB8888,
					    handles, pitches, offsets,
					    &sprite_fb_id[sprite_index], plane_flags);
			gem_close(gfx_fd, sprite_handles[sprite_index]);

			if (ret) {
				printf("Failed to add sprite fb (%dx%d): %s\n",
				       sprite_w, sprite_h, strerror(errno));

				sprite_index--;
				while (sprite_index >= 0) {
					drmModeRmFB(gfx_fd, sprite_fb_id[sprite_index]);
					sprite_index--;
				}
				goto out;
			}
		}

		if (dump_info != 0) {
			printf("Displayed Mode Connector struct:\n"
				"    .id = %d\n"
				"    .mode_valid = %d\n"
				"    .crtc = %d\n"
				"    .pipe = %d\n"
				"    drmModeModeInfo ...\n"
				"        .name = %s\n"
				"        .type = %d\n"
				"        .flags = %08x\n"
				"    drmModeEncoder ...\n"
				"        .encoder_id = %d\n"
				"        .encoder_type = %d (%s)\n"
				"        .crtc_id = %d\n"
				"        .possible_crtcs = %d\n"
				"        .possible_clones = %d\n"
				"    drmModeConnector ...\n"
				"        .connector_id = %d\n"
				"        .encoder_id = %d\n"
				"        .connector_type = %d (%s)\n"
				"        .connector_type_id = %d\n\n",
				curr_connector.id,
				curr_connector.mode_valid,
				curr_connector.crtc,
				curr_connector.pipe,
				curr_connector.mode.name,
				curr_connector.mode.type,
				curr_connector.mode.flags,
				curr_connector.encoder->encoder_id,
				curr_connector.encoder->encoder_type,
				kmstest_encoder_type_str(curr_connector.encoder->encoder_type),
				curr_connector.encoder->crtc_id,
				curr_connector.encoder->possible_crtcs,
				curr_connector.encoder->possible_clones,
				curr_connector.connector->connector_id,
				curr_connector.connector->encoder_id,
				curr_connector.connector->connector_type,
				kmstest_connector_type_str(curr_connector.connector->connector_type),
				curr_connector.connector->connector_type_id);

			printf("Sprite surface dimensions = %dx%d\n"
				"Sprite output dimensions = %dx%d\n"
				"Press any key to continue >\n",
				sprite_w, sprite_h, out_w, out_h);

			// Wait for a key-press
			while( read(0, &key, 1) == 0);
			// Purge unread characters
			tcflush(0, TCIFLUSH);
		}

		// Set up the primary display mode
		ret = drmModeSetCrtc(gfx_fd, curr_connector.crtc, prim_fb_id,
				     0, 0, &curr_connector.id, 1, &curr_connector.mode);
		if (ret != 0) {
			printf("Failed to set mode (%dx%d@%dHz): %s\n",
				prim_width, prim_height, curr_connector.mode.vrefresh,
				strerror(errno));
			continue;
		}

		// Set the sprite colorkey state
		for(i = 0; i < sprite_plane_count; i++) {
			set.plane_id = sprite_plane_id[i];
			set.min_value = 0;
			set.max_value = 0;
			set.flags = I915_SET_COLORKEY_NONE;
			ret = drmCommandWrite(gfx_fd, DRM_I915_SET_SPRITE_COLORKEY, &set,
					      sizeof(set));
			assert(ret == 0);
		}

		// Set up sprite output dimensions, initial position, etc.
		if (out_w > prim_width / 2)
			out_w = prim_width / 2;
		if (out_h > prim_height / 2)
			out_h = prim_height / 2;

		delta_x = (int *) malloc(sprite_plane_count * sizeof(int));
		delta_y = (int *) malloc(sprite_plane_count * sizeof(int));
		sprite_x = (int *) malloc(sprite_plane_count * sizeof(int));
		sprite_y = (int *) malloc(sprite_plane_count * sizeof(int));

		/* Initializing the coordinates (x,y) of the available sprites on the
		 * connector, equally spaced along the diagonal of the rectangle
		 * {(0,0),(prim_width/2, prim_height/2)}.
		 */
		for(i = 0; i < sprite_plane_count; i++) {
			delta_x[i] = 3;
			delta_y[i] = 4;
			sprite_x[i] = i * (prim_width / (2 * sprite_plane_count));
			sprite_y[i] = i * (prim_height / (2 * sprite_plane_count));
		}

		currTime = 0;
		prevFlipTime = 0;       // Will force immediate sprite flip
		prevMoveTime = 0;       // Will force immediate sprite move
		deltaFlipTime = 500000; // Flip sprite surface every 1/2 second
		deltaMoveTime = 100000; // Move sprite every 100 ms
		sprite_index = num_surfaces - 1;
		keep_moving = 1;

		// Bounce sprite off the walls
		while (keep_moving) {
			// Obtain system time in usec.
			if (gettimeofday( &stTimeVal, NULL ) != 0)
				printf("gettimeofday error: %s\n", strerror(errno));
			else
				currTime = ((long long)stTimeVal.tv_sec * 1000000) + stTimeVal.tv_usec;

			// Check if it's time to flip the sprite surface
			if (currTime - prevFlipTime > deltaFlipTime) {
				sprite_index = (sprite_index + 1) % num_surfaces;

				prevFlipTime = currTime;
			}

			// Move the sprite on the screen and flip
			// the surface if the index has changed
			// NB: sprite_w and sprite_h must be 16.16 fixed point, herego << 16
			for(i = 0; i < sprite_plane_count; i++) {
				if (drmModeSetPlane(gfx_fd, sprite_plane_id[i],
						    curr_connector.crtc,
						    sprite_fb_id[sprite_index],
						    plane_flags,
						    sprite_x[i], sprite_y[i],
						    out_w, out_h,
						    0, 0,
						    sprite_w << 16, sprite_h << 16))
					printf("Failed to enable sprite plane: %s\n",
						strerror(errno));
			}

			// Check if it's time to move the sprite surface
			if (currTime - prevMoveTime > deltaMoveTime)  {

				// Compute the next position for sprite
				for(i = 0; i < sprite_plane_count; i++) {
					sprite_x[i] += delta_x[i];
					sprite_y[i] += delta_y[i];
					if (sprite_x[i] < 0) {
						sprite_x[i] = 0;
						delta_x[i] = -delta_x[i];
					}
					else if (sprite_x[i] > prim_width - out_w) {
						sprite_x[i] = prim_width - out_w;
						delta_x[i] = -delta_x[i];
					}

					if (sprite_y[i] < 0) {
						sprite_y[i] = 0;
						delta_y[i] = -delta_y[i];
					}
					else if (sprite_y[i] > prim_height - out_h) {
						sprite_y[i] = prim_height - out_h;
						delta_y[i] = -delta_y[i];
					}
				}
				prevMoveTime = currTime;
			}

			// Fetch a key from input (non-blocking)
			if (read(0, &key, 1) == 1) {
				switch (key) {
				case 'q':       // Kill the program
				case 'Q':
					goto out;
					break;
				case 's':       // Slow down sprite movement;
					deltaMoveTime = (deltaMoveTime * 100) / 90;
					if (deltaMoveTime > 800000) {
						deltaMoveTime = 800000;
					}
					break;
				case 'S':       // Speed up sprite movement;
					deltaMoveTime = (deltaMoveTime * 100) / 110;
					if (deltaMoveTime < 2000) {
						deltaMoveTime = 2000;
					}
					break;
				case 'f':       // Slow down sprite flipping;
					deltaFlipTime = (deltaFlipTime * 100) / 90;
					if (deltaFlipTime > 1000000)
						deltaFlipTime = 1000000;
					break;
				case 'F':       // Speed up sprite flipping;
					deltaFlipTime = (deltaFlipTime * 100) / 110;
					if (deltaFlipTime < 20000)
						deltaFlipTime = 20000;
					break;
				case 'n':       // Next connector
				case 'N':
					keep_moving = 0;
					break;
				default:
					break;
				}

				// Purge unread characters
				tcflush(0, TCIFLUSH);
			}

			// Wait for min of flip or move deltas
			SleepTime = (deltaFlipTime < deltaMoveTime) ?
				deltaFlipTime : deltaMoveTime;
			usleep(SleepTime);
		}

		free(sprite_plane_id);
		free(sprite_x);
		free(sprite_y);
		free(delta_x);
		free(delta_y);
		sprite_plane_id = NULL;
		sprite_plane_count = 0;
		sprite_x = sprite_y = delta_x = delta_y = NULL;
	}

out:
	// Purge unread characters
	tcflush(0, TCIFLUSH);
	// Restore previous terminal settings
	if (tcsetattr( 0, TCSANOW, &orig_term) != 0) {
		printf("tcgetattr failure: %s\n", strerror(errno));
		return;
	}

	drmModeFreeResources(gfx_resources);
}
Пример #7
0
bool Drm::setDrmMode(int index, drmModeModeInfoPtr mode)
{
    DrmOutput *output = &mOutputs[index];

    int oldFbId = 0;
    int oldFbHandle = 0;
    // reuse current frame buffer if there is no resolution change
    int fbId = -1;

    drmModeModeInfo currentMode;
    memcpy(&currentMode, &output->mode, sizeof(drmModeModeInfo));

    if (isSameDrmMode(mode, &currentMode))
        return true;

    if (currentMode.hdisplay != mode->hdisplay ||
        currentMode.vdisplay != mode->vdisplay) {

        oldFbId = output->fbId;
        oldFbHandle = output->fbHandle;

        // allocate frame buffer
        int stride = 0;
#ifdef INTEL_SUPPORT_HDMI_PRIMARY
        output->fbHandle = Hwcomposer::getInstance().getBufferManager()->allocFrameBuffer(
            DEFAULT_DRM_FB_WIDTH, DEFAULT_DRM_FB_HEIGHT, &stride);
#else
        output->fbHandle = Hwcomposer::getInstance().getBufferManager()->allocFrameBuffer(
            mode->hdisplay, mode->vdisplay, &stride);
#endif
        if (output->fbHandle == 0) {
            ELOGTRACE("failed to allocate frame buffer");
            return false;
        }

        int ret = 0;
        ret = drmModeAddFB(
            mDrmFd,
#ifdef INTEL_SUPPORT_HDMI_PRIMARY
            DEFAULT_DRM_FB_WIDTH,
            DEFAULT_DRM_FB_HEIGHT,
#else
            mode->hdisplay,
            mode->vdisplay,
#endif
            DrmConfig::getFrameBufferDepth(),
            DrmConfig::getFrameBufferBpp(),
            stride,
            output->fbHandle,
            &output->fbId);
        if (ret != 0) {
            ELOGTRACE("drmModeAddFB failed, error: %d", ret);
            return false;
        }
        fbId = output->fbId;
    }

    ILOGTRACE("mode set: %dx%d@%dHz", mode->hdisplay, mode->vdisplay, mode->vrefresh);

    int ret = drmModeSetCrtc(mDrmFd, output->crtc->crtc_id, fbId, 0, 0,
                   &output->connector->connector_id, 1, mode);

    if (ret == 0) {
        //save mode
        memcpy(&output->mode, mode, sizeof(drmModeModeInfo));
    } else {
        ELOGTRACE("drmModeSetCrtc failed. error: %d", ret);
    }

    if (oldFbId) {
        drmModeRmFB(mDrmFd, oldFbId);
    }

    if (oldFbHandle) {
        Hwcomposer::getInstance().getBufferManager()->freeFrameBuffer(oldFbHandle);
    }

    return ret == 0;
}
Пример #8
0
int main(int argc, char *argv[])
{
	EGLDisplay dpy;
	EGLContext ctx;
	EGLConfig config;
	EGLSurface surface;
	EGLint major, minor, n;
	const char *ver;
	uint32_t handle, stride;
	int ret, fd, frames = 0;
	struct gbm_device *gbm;
	drmModeCrtcPtr saved_crtc;
	time_t start, end;
	char *data;
	char j;
	int i;
	int once;
	once = 0;

	signal (SIGINT, quit_handler);

	fd = open(device_name, O_RDWR);
	if (fd < 0) {
		/* Probably permissions error */
		fprintf(stderr, "couldn't open %s, skipping\n", device_name);
		return -1;
	}

	gbm = gbm_create_device(fd);
	if (gbm == NULL) {
		fprintf(stderr, "couldn't create gbm device\n");
		ret = -1;
		goto close_fd;
	}

	dpy = eglGetDisplay(gbm);
	if (dpy == EGL_NO_DISPLAY) {
		fprintf(stderr, "eglGetDisplay() failed\n");
		ret = -1;
		goto destroy_gbm_device;
	}

	if (!eglInitialize(dpy, &major, &minor)) {
		printf("eglInitialize() failed\n");
		ret = -1;
		goto egl_terminate;
	}

	ver = eglQueryString(dpy, EGL_VERSION);
	printf("EGL_VERSION = %s\n", ver);

	if (!setup_kms(fd, &kms)) {
		ret = -1;
		goto egl_terminate;
	}

	eglBindAPI(EGL_OPENGL_API);

	if (!eglChooseConfig(dpy, attribs, &config, 1, &n) || n != 1) {
		fprintf(stderr, "failed to choose argb config\n");
		goto egl_terminate;
	}

	ctx = eglCreateContext(dpy, config, EGL_NO_CONTEXT, NULL);
	if (ctx == NULL) {
		fprintf(stderr, "failed to create context\n");
		ret = -1;
		goto egl_terminate;
	}

	gs = gbm_surface_create(gbm, kms.mode.hdisplay, kms.mode.vdisplay,
		GBM_BO_FORMAT_XRGB8888,
		GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
	if (gs == NULL) {
		fprintf(stderr, "unable to create gbm surface\n");
		ret = -1;
		goto egl_terminate;
	}


	surface = eglCreateWindowSurface(dpy, config, gs, NULL);
	if (surface == EGL_NO_SURFACE) {
		fprintf(stderr, "failed to create surface\n");
		ret = -1;
		goto destroy_gbm_surface;
	}

	if (!eglMakeCurrent(dpy, surface, surface, ctx)) {
		fprintf(stderr, "failed to make context current\n");
		ret = -1;
		goto destroy_surface;
	}

	saved_crtc = drmModeGetCrtc(fd, kms.crtc_id);
	if (saved_crtc == NULL)
	{
		fprintf(stderr, "no valid graphic configuration active (VT ?)\n");
	}
	time(&start);
	do {

		drmEventContext evctx;
		fd_set rfds;

		render_stuff(kms.mode.hdisplay, kms.mode.vdisplay);
		eglSwapBuffers(dpy, surface);
		
		if (!gbm_surface_has_free_buffers(gs))
			fprintf(stderr, "out of free buffers\n");

		next_bo = gbm_surface_lock_front_buffer(gs);
		if (!next_bo)
			fprintf(stderr, "failed to lock front buffer: %m\n");

		handle = gbm_bo_get_handle(next_bo).u32;
		stride = gbm_bo_get_stride(next_bo);
		
		ret = drmModeAddFB(fd,
				 kms.mode.hdisplay, kms.mode.vdisplay,
				 24, 32, stride, handle, &next_fb_id);
		if (ret) {
			fprintf(stderr, "failed to create fb\n");
			goto out;
		}
		  
		/* make sure to setup crtc once (fix for broken drivers) */
		if(once == 0){
			once = 1;
			drmModeSetCrtc(fd, kms.crtc_id, next_fb_id,
				0, 0,
				&kms.connector->connector_id, 1, &kms.mode);
		}
		
		ret = drmModePageFlip(fd, kms.crtc_id,
					next_fb_id,
					DRM_MODE_PAGE_FLIP_EVENT, 0);
		if (ret) {
			fprintf(stderr, "failed to page flip: %m\n");
			goto out;
		}

		FD_ZERO(&rfds);
		FD_SET(fd, &rfds);

		while (select(fd + 1, &rfds, NULL, NULL, NULL) == -1)
			NULL;

		memset(&evctx, 0, sizeof evctx);
		evctx.version = DRM_EVENT_CONTEXT_VERSION;
		evctx.page_flip_handler = page_flip_handler;

		drmHandleEvent(fd, &evctx);

		frames++;
	} while (!quit);
	time(&end);

	printf("Frames per second: %.2lf\n", frames / difftime(end, start));

out:
	if(saved_crtc){
		drmModeSetCrtc(fd, saved_crtc->crtc_id, saved_crtc->buffer_id,
			saved_crtc->x, saved_crtc->y,
			&kms.connector->connector_id, 1, &saved_crtc->mode);
		}
	drmModeFreeCrtc(saved_crtc);
	if (current_fb_id)
		drmModeRmFB(fd, current_fb_id);
	if (next_fb_id)
		drmModeRmFB(fd, next_fb_id);
	eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
destroy_context:
	eglDestroyContext(dpy, ctx);
destroy_surface:
	eglDestroySurface(dpy, surface);
destroy_gbm_surface:
	gbm_surface_destroy(gs);
egl_terminate:
	eglTerminate(dpy);
destroy_gbm_device:
	gbm_device_destroy(gbm);
close_fd:
	close(fd);

	return ret;
}
Пример #9
0
static Bool
drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
{
	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
	drmmode_crtc_private_ptr
		    drmmode_crtc = xf86_config->crtc[0]->driver_private;
	drmmode_ptr drmmode = drmmode_crtc->drmmode;
	intel_screen_private *intel = intel_get_screen_private(scrn);
	drm_intel_bo *old_front = NULL;
	Bool	    ret;
	uint32_t    old_fb_id;
	int	    i, old_width, old_height, old_pitch;
	unsigned long pitch;
	uint32_t tiling;

	if (scrn->virtualX == width && scrn->virtualY == height)
		return TRUE;

	old_width = scrn->virtualX;
	old_height = scrn->virtualY;
	old_pitch = scrn->displayWidth;
	old_fb_id = drmmode->fb_id;
	old_front = intel->front_buffer;

	intel->front_buffer = intel_allocate_framebuffer(scrn,
							 width, height,
							 intel->cpp,
							 &pitch,
							 &tiling);
	if (!intel->front_buffer)
		goto fail;

	ret = drmModeAddFB(drmmode->fd, width, height, scrn->depth,
			   scrn->bitsPerPixel, pitch,
			   intel->front_buffer->handle,
			   &drmmode->fb_id);
	if (ret)
		goto fail;

	intel->front_pitch = pitch;
	intel->front_tiling = tiling;

	scrn->virtualX = width;
	scrn->virtualY = height;

	for (i = 0; i < xf86_config->num_crtc; i++) {
		xf86CrtcPtr crtc = xf86_config->crtc[i];

		if (!crtc->enabled)
			continue;

		drmmode_set_mode_major(crtc, &crtc->mode,
				       crtc->rotation, crtc->x, crtc->y);
	}

	intel_uxa_create_screen_resources(scrn->pScreen);

	if (old_fb_id)
		drmModeRmFB(drmmode->fd, old_fb_id);
	if (old_front)
		drm_intel_bo_unreference(old_front);

	return TRUE;

 fail:
	if (intel->front_buffer)
		drm_intel_bo_unreference(intel->front_buffer);
	intel->front_buffer = old_front;
	scrn->virtualX = old_width;
	scrn->virtualY = old_height;
	scrn->displayWidth = old_pitch;
	drmmode->fb_id = old_fb_id;

	return FALSE;
}
Пример #10
0
static int init_rb(struct uterm_display *disp, struct dumb_rb *rb)
{
	int ret;
	struct uterm_video *video = disp->video;
	struct drm_mode_create_dumb req;
	struct drm_mode_destroy_dumb dreq;
	struct drm_mode_map_dumb mreq;

	memset(&req, 0, sizeof(req));
	req.width = disp->current_mode->dumb.info.hdisplay;
	req.height = disp->current_mode->dumb.info.vdisplay;
	req.bpp = 32;
	req.flags = 0;

	ret = drmIoctl(video->dumb.fd, DRM_IOCTL_MODE_CREATE_DUMB, &req);
	if (ret < 0) {
		log_err("cannot create dumb drm buffer");
		return -EFAULT;
	}

	rb->handle = req.handle;
	rb->stride = req.pitch;
	rb->size = req.size;

	ret = drmModeAddFB(video->dumb.fd,
			disp->current_mode->dumb.info.hdisplay,
			disp->current_mode->dumb.info.vdisplay,
			24, 32, rb->stride, rb->handle, &rb->fb);
	if (ret) {
		log_err("cannot add drm-fb");
		ret = -EFAULT;
		goto err_buf;
	}

	memset(&mreq, 0, sizeof(mreq));
	mreq.handle = rb->handle;

	ret = drmIoctl(video->dumb.fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
	if (ret) {
		log_err("cannot map dumb buffer");
		ret = -EFAULT;
		goto err_fb;
	}

	rb->map = mmap(0, rb->size, PROT_READ | PROT_WRITE, MAP_SHARED,
		       video->dumb.fd, mreq.offset);
	if (rb->map == MAP_FAILED) {
		log_err("cannot mmap dumb buffer");
		ret = -EFAULT;
		goto err_fb;
	}

	return 0;

err_fb:
	drmModeRmFB(video->dumb.fd, rb->fb);
err_buf:
	memset(&dreq, 0, sizeof(dreq));
	dreq.handle = rb->handle;
	ret = drmIoctl(video->dumb.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
	if (ret)
		log_warning("cannot destroy dumb buffer");

	return ret;
}
Пример #11
0
Файл: main.c Проект: yuq/gfx
int main(int argc, char **argv)
{
	int fd = drmOpen("radeon", NULL);
	assert(fd >= 0);

	// expose all planes including primary and cursor planes
	assert(!drmSetClientCap(fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1));

	drmModeResPtr res = drmModeGetResources(fd);
	assert(res);

	int i, j;
	drmModeConnectorPtr connector = NULL;
	for (i = 0; i < res->count_connectors; i++) {
		connector = drmModeGetConnector(fd, res->connectors[i]);
		assert(connector);

		if (connector->connection == DRM_MODE_CONNECTED)
			break;

		drmFree(connector);
	}

	drmModeEncoderPtr encoder = drmModeGetEncoder(fd, connector->encoder_id);
	assert(encoder);

	drmModeCrtcPtr crtc = drmModeGetCrtc(fd, encoder->crtc_id);
	assert(crtc);

	drmModeFBPtr fb = drmModeGetFB(fd, crtc->buffer_id);
	assert(fb);

	drmModePlaneResPtr plane_res = drmModeGetPlaneResources(fd);
	assert(plane_res);

	drmModePlanePtr plane = NULL;
	for (i = 0; i < plane_res->count_planes; i++) {
		plane = drmModeGetPlane(fd, plane_res->planes[i]);
		assert(plane);

		if (plane->fb_id == fb->fb_id)
			break;

		drmFree(plane);
	}

	uint64_t has_dumb;
	assert(!drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_dumb));
	assert(has_dumb);

	struct drm_mode_create_dumb creq;
	memset(&creq, 0, sizeof(creq));
	creq.width = fb->width;
	creq.height = fb->height;
	creq.bpp = fb->bpp;
	assert(!drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq));

	printf("width=%d height=%d bpp=%d pitch=%d size=%d\n",
		   creq.width, creq.height, creq.bpp, creq.pitch, creq.size);

	uint32_t my_fb;
	assert(!drmModeAddFB(fd, creq.width, creq.height, 24, creq.bpp, creq.pitch, creq.handle, &my_fb));	

	struct drm_mode_map_dumb mreq;
	memset(&mreq, 0, sizeof(mreq));
	mreq.handle = creq.handle;
	assert(!drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq));

	uint32_t *map = mmap(0, creq.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, mreq.offset);
	assert(map != MAP_FAILED);
	memset(map, 0, creq.size);

	for (i = 100; i < 500; i++)
		for (j = 200; j < 460; j++)
			map[i * (creq.pitch >> 2) + j] = 0x12345678;

	assert(!drmModeSetCrtc(fd, crtc->crtc_id, my_fb, 0, 0, &connector->connector_id, 1, &crtc->mode));
	sleep(10);
	assert(!drmModeSetCrtc(fd, crtc->crtc_id, fb->fb_id, 0, 0, &connector->connector_id, 1, &crtc->mode));

	assert(!drmModeRmFB(fd, my_fb));
	struct drm_mode_destroy_dumb dreq;
	memset(&dreq, 0, sizeof(dreq));
	dreq.handle = creq.handle;
	assert(!drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq));

	drmFree(plane);
	drmFree(plane_res);
	drmFree(fb);
	drmFree(crtc);
	drmFree(encoder);
	drmFree(connector);
	drmFree(res);
	drmClose(fd);
	return 0;
}
Пример #12
0
static Bool
dri2_page_flip(DrawablePtr draw, PixmapPtr back, void *priv,
			   xf86CrtcPtr ref_crtc)
{
	ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen);
	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
	NVPtr pNv = NVPTR(scrn);
	uint32_t next_fb;
	int emitted = 0;
	int ret, i;
	dri2_flipdata_ptr flipdata;
	dri2_flipevtcarrier_ptr flipcarrier;

	ret = drmModeAddFB(pNv->dev->fd, scrn->virtualX, scrn->virtualY,
			   scrn->depth, scrn->bitsPerPixel,
			   scrn->displayWidth * scrn->bitsPerPixel / 8,
			   nouveau_pixmap(back)->bo->handle, &next_fb);
	if (ret) {
		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
			   "add fb failed: %s\n", strerror(errno));
		return FALSE;
	}

	flipdata = calloc(1, sizeof(dri2_flipdata_rec));
	if (!flipdata) {
		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
		"flip queue: data alloc failed.\n");
		goto error_undo;
	}

	flipdata->event_data = priv;
	flipdata->fd = pNv->dev->fd;

	for (i = 0; i < config->num_crtc; i++) {
		int head = drmmode_crtc(config->crtc[i]);
		void *token;

		if (!drmmode_crtc_on(config->crtc[i]))
			continue;

		flipdata->flip_count++;

		flipcarrier = drmmode_event_queue(scrn, ++dri2_sequence,
						  sizeof(*flipcarrier),
						  nouveau_dri2_flip_handler,
						  &token);
		if (!flipcarrier) {
			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
				   "flip queue: carrier alloc failed.\n");
			if (emitted == 0)
				free(flipdata);
			goto error_undo;
		}

		/* Only the reference crtc will finally deliver its page flip
		 * completion event. All other crtc's events will be discarded.
		 */
		flipcarrier->dispatch_me = (config->crtc[i] == ref_crtc);
		flipcarrier->flipdata = flipdata;

		ret = drmModePageFlip(pNv->dev->fd, head, next_fb,
				      DRM_MODE_PAGE_FLIP_EVENT, token);
		if (ret) {
			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
				   "flip queue failed: %s\n", strerror(errno));
			drmmode_event_abort(scrn, dri2_sequence--, false);
			if (emitted == 0)
				free(flipdata);
			goto error_undo;
		}

		emitted++;
	}

	/* Will release old fb after all crtc's completed flip. */
	drmmode_swap(scrn, next_fb, &flipdata->old_fb_id);
	return TRUE;

error_undo:
	drmModeRmFB(pNv->dev->fd, next_fb);
	return FALSE;
}
Пример #13
0
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) {
Пример #14
0
static void
_cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen)
{
  CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
  CoglDisplayEGL *egl_display = context->display->winsys;
  CoglDisplayKMS *kms_display = egl_display->platform;
  CoglRenderer *renderer = context->display->renderer;
  CoglRendererEGL *egl_renderer = renderer->winsys;
  CoglRendererKMS *kms_renderer = egl_renderer->platform;
  CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
  CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform;
  uint32_t handle, stride;
  CoglFlipKMS *flip;
  GList *l;

  /* If we already have a pending swap then block until it completes */
  while (kms_onscreen->next_fb_id != 0)
    handle_drm_event (kms_renderer);

  /* First chain-up. This will call eglSwapBuffers */
  parent_vtable->onscreen_swap_buffers (onscreen);

  /* Now we need to set the CRTC to whatever is the front buffer */
  kms_onscreen->next_bo = gbm_surface_lock_front_buffer (kms_onscreen->surface);

#if (COGL_VERSION_ENCODE (COGL_GBM_MAJOR, COGL_GBM_MINOR, COGL_GBM_MICRO) >= \
     COGL_VERSION_ENCODE (8, 1, 0))
  stride = gbm_bo_get_stride (kms_onscreen->next_bo);
#else
  stride = gbm_bo_get_pitch (kms_onscreen->next_bo);
#endif
  handle = gbm_bo_get_handle (kms_onscreen->next_bo).u32;

  if (drmModeAddFB (kms_renderer->fd,
                    kms_display->width,
                    kms_display->height,
                    24, /* depth */
                    32, /* bpp */
                    stride,
                    handle,
                    &kms_onscreen->next_fb_id))
    {
      g_warning ("Failed to create new back buffer handle: %m");
      gbm_surface_release_buffer (kms_onscreen->surface,
                                  kms_onscreen->next_bo);
      kms_onscreen->next_bo = NULL;
      kms_onscreen->next_fb_id = 0;
      return;
    }

  /* If this is the first framebuffer to be presented then we now setup the
   * crtc modes... */
  if (kms_display->pending_set_crtc)
    {
      setup_crtc_modes (context->display, kms_onscreen->next_fb_id);
      kms_display->pending_set_crtc = FALSE;
    }

  flip = g_slice_new0 (CoglFlipKMS);
  flip->onscreen = onscreen;

  for (l = kms_display->outputs; l; l = l->next)
    {
      CoglOutputKMS *output = l->data;

      if (drmModePageFlip (kms_renderer->fd,
                           output->encoder->crtc_id,
                           kms_onscreen->next_fb_id,
                           DRM_MODE_PAGE_FLIP_EVENT,
                           flip))
        {
          g_warning ("Failed to flip: %m");
          continue;
        }

      flip->pending++;
    }

  if (flip->pending == 0)
    {
      drmModeRmFB (kms_renderer->fd, kms_onscreen->next_fb_id);
      gbm_surface_release_buffer (kms_onscreen->surface,
                                  kms_onscreen->next_bo);
      kms_onscreen->next_bo = NULL;
      kms_onscreen->next_fb_id = 0;
      g_slice_free (CoglFlipKMS, flip);
      flip = NULL;
    }
  else
    {
      /* Ensure the onscreen remains valid while it has any pending flips... */
      cogl_object_ref (flip->onscreen);
    }
}
Пример #15
0
static drm_overlay_fb * drm_create_fb_internal(struct drm_tegra *drm,
                                               int drm_fd,
                                               uint32_t drm_format,
                                               uint32_t width, uint32_t height,
                                               uint32_t *bo_handles,
                                               uint32_t *pitches,
                                               uint32_t *offsets,
                                               Bool dont_map)
{
    struct drm_tegra_bo *bo    = NULL;
    struct drm_tegra_bo *bo_cb = NULL;
    struct drm_tegra_bo *bo_cr = NULL;
    drm_overlay_fb *fb         = NULL;
    uint32_t fb_id             = HANDLE_INVALID;
    Bool from_handle;
    int err;

    if (width == 0 || height == 0)
        return NULL;

    if (!pitches) {
        pitches = alloca(sizeof(uint32_t) * 4);

        pitches[0] = fb_pitch_aligned(drm_format, width);
        pitches[1] = fb_pitch_c_aligned(drm_format, width);
        pitches[2] = fb_pitch_c_aligned(drm_format, width);
        pitches[3] = 0;
    }

    if (!offsets) {
        offsets = alloca(sizeof(uint32_t) * 4);

        offsets[0] = 0;
        offsets[1] = 0;
        offsets[2] = 0;
        offsets[3] = 0;
    }

    from_handle = !!(bo_handles);

    if (from_handle) {
        err = drm_tegra_bo_wrap(&bo, drm, bo_handles[0], 0,
                                pitches[0] * height);
        if (err)
            goto error_cleanup;

        drm_tegra_bo_forbid_caching(bo);

        if (format_planar(drm_format)) {
            err = drm_tegra_bo_wrap(&bo_cb, drm, bo_handles[1], 0,
                                    pitches[1] * height / 2);
            if (err)
                goto error_cleanup;

            drm_tegra_bo_forbid_caching(bo_cb);

            err = drm_tegra_bo_wrap(&bo_cr, drm, bo_handles[2], 0,
                                    pitches[2] * height / 2);
            if (err)
                goto error_cleanup;

            drm_tegra_bo_forbid_caching(bo_cr);
        }

        goto create_framebuffer;
    }

    bo_handles = alloca(sizeof(uint32_t) * 4);

    bo_handles[1] = HANDLE_INVALID;
    bo_handles[2] = HANDLE_INVALID;
    bo_handles[3] = HANDLE_INVALID;

    /* Allocate PLANE[0] */
    err = drm_tegra_bo_new(&bo, drm, 0, offsets[0] +
                           fb_size_aligned(drm_format, width, height));
    if (err)
        goto error_cleanup;

    drm_tegra_bo_get_handle(bo, &bo_handles[0]);

    if (!format_planar(drm_format))
        goto create_framebuffer;

    /* Allocate PLANE[1] */
    err = drm_tegra_bo_new(&bo_cb, drm, 0, offsets[1] +
                           fb_size_c_aligned(drm_format, width, height));
    if (err)
        goto error_cleanup;

    drm_tegra_bo_get_handle(bo_cb, &bo_handles[1]);

    /* Allocate PLANE[2] */
    err = drm_tegra_bo_new(&bo_cr, drm, 0, offsets[2] +
                           fb_size_c_aligned(drm_format, width, height));
    if (err)
        goto error_cleanup;

    drm_tegra_bo_get_handle(bo_cr, &bo_handles[2]);

create_framebuffer:
    err = drmModeAddFB2(drm_fd, width, height, drm_format,
                        bo_handles, pitches, offsets, &fb_id, 0);
    if (err) {
        ErrorMsg("Failed to create DRM framebuffer: %s\n", strerror(-err));
        goto error_cleanup;
    }

    fb = calloc(1, sizeof(*fb));
    if (!fb)
        goto error_cleanup;

    fb->fb_id           = fb_id;
    fb->format          = drm_format;
    fb->width           = width;
    fb->height          = height;
    fb->width_c         = fb_width_c(drm_format, width);
    fb->height_c        = fb_height_c(drm_format, height);
    fb->bpp             = fb_bpp(drm_format);
    fb->bpp_c           = fb_bpp_c(drm_format);
    fb->bo_y_id         = bo_handles[0];
    fb->bo_cb_id        = bo_handles[1];
    fb->bo_cr_id        = bo_handles[2];
    fb->bo_y            = bo;
    fb->bo_cb           = bo_cb;
    fb->bo_cr           = bo_cr;
    fb->pitch_y         = pitches[0];
    fb->pitch_cb        = pitches[1];
    fb->pitch_cr        = pitches[2];
    fb->offset_y        = offsets[0];
    fb->offset_cb       = offsets[1];
    fb->offset_cr       = offsets[2];

    fb->width_pad       = (fb_pitch_aligned(drm_format, width) -
                            fb_pitch(drm_format, width)) *
                                fb_height_aligned(drm_format, height);

    fb->height_pad      = (fb_height_aligned(drm_format, height) - height) *
                            fb_pitch_aligned(drm_format, width);

    fb->height_offset   = (fb_height_aligned(drm_format, height) - height) *
                            fb->bpp / 8;

    fb->width_c_pad     = (fb_pitch_c_aligned(drm_format, width) -
                            fb_pitch_c(drm_format, width)) *
                                fb_height_c_aligned(drm_format, height);

    fb->height_c_pad    = (fb_height_c_aligned(drm_format, height) - fb->height_c) *
                            fb_pitch_c_aligned(drm_format, width);

    fb->height_c_offset = (fb_height_c_aligned(drm_format, height) - fb->height_c) *
                            fb->bpp_c / 8;

    if (dont_map)
        return fb;

    err = drm_tegra_bo_map(fb->bo_y, (void **)&fb->bo_y_mmap);
    if (err)
        goto error_cleanup;

    fb->bo_y_mmap += fb->offset_y;

    if (!format_planar(drm_format))
        return fb;

    err = drm_tegra_bo_map(fb->bo_cb, (void **)&fb->bo_cb_mmap);
    if (err)
        goto error_cleanup;

    err = drm_tegra_bo_map(fb->bo_cr, (void **)&fb->bo_cr_mmap);
    if (err)
        goto error_cleanup;

    fb->bo_cb_mmap += fb->offset_cb;
    fb->bo_cr_mmap += fb->offset_cr;

    return fb;

error_cleanup:
    if (from_handle)
        return NULL;

    if (fb_id != HANDLE_INVALID)
        drmModeRmFB(drm_fd, fb_id);

    drm_tegra_bo_unref(bo);
    drm_tegra_bo_unref(bo_cb);
    drm_tegra_bo_unref(bo_cr);

    free(fb);

    return NULL;
}
Пример #16
0
int main(int argc, char *argv[])
{
   EGLDisplay dpy;
   EGLContext ctx;
   EGLSurface surface;
   EGLConfig config;
   EGLint major, minor, n;
   const char *ver;
   uint32_t handle, stride;
   struct kms kms;
   int ret, fd;
   struct gbm_device *gbm;
   struct gbm_bo *bo;
   drmModeCrtcPtr saved_crtc;
   struct gbm_surface *gs;

   fd = open(device_name, O_RDWR);
   if (fd < 0) {
      /* Probably permissions error */
      fprintf(stderr, "couldn't open %s, skipping\n", device_name);
      return -1;
   }

   gbm = gbm_create_device(fd);
   if (gbm == NULL) {
      fprintf(stderr, "couldn't create gbm device\n");
      ret = -1;
      goto close_fd;
   }

   dpy = eglGetDisplay(gbm);
   if (dpy == EGL_NO_DISPLAY) {
      fprintf(stderr, "eglGetDisplay() failed\n");
      ret = -1;
      goto destroy_gbm_device;
   }
	
   if (!eglInitialize(dpy, &major, &minor)) {
      printf("eglInitialize() failed\n");
      ret = -1;
      goto egl_terminate;
   }

   ver = eglQueryString(dpy, EGL_VERSION);
   printf("EGL_VERSION = %s\n", ver);

   if (!setup_kms(fd, &kms)) {
      ret = -1;
      goto egl_terminate;
   }

   eglBindAPI(EGL_OPENGL_API);

   if (!eglChooseConfig(dpy, attribs, &config, 1, &n) || n != 1) {
      fprintf(stderr, "failed to choose argb config\n");
      goto egl_terminate;
   }
   
   ctx = eglCreateContext(dpy, config, EGL_NO_CONTEXT, NULL);
   if (ctx == NULL) {
      fprintf(stderr, "failed to create context\n");
      ret = -1;
      goto egl_terminate;
   }

   gs = gbm_surface_create(gbm, kms.mode.hdisplay, kms.mode.vdisplay,
			   GBM_BO_FORMAT_XRGB8888,
			   GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
   surface = eglCreateWindowSurface(dpy, config, gs, NULL);

   if (!eglMakeCurrent(dpy, surface, surface, ctx)) {
      fprintf(stderr, "failed to make context current\n");
      ret = -1;
      goto destroy_context;
   }

   render_stuff(kms.mode.hdisplay, kms.mode.vdisplay);

   eglSwapBuffers(dpy, surface);

   bo = gbm_surface_lock_front_buffer(gs);
   handle = gbm_bo_get_handle(bo).u32;
   stride = gbm_bo_get_stride(bo);

   printf("handle=%d, stride=%d\n", handle, stride);

   ret = drmModeAddFB(fd,
		      kms.mode.hdisplay, kms.mode.vdisplay,
		      24, 32, stride, handle, &kms.fb_id);
   if (ret) {
      fprintf(stderr, "failed to create fb\n");
      goto rm_fb;
   }

   saved_crtc = drmModeGetCrtc(fd, kms.encoder->crtc_id);
   if (saved_crtc == NULL)
      goto rm_fb;

   ret = drmModeSetCrtc(fd, kms.encoder->crtc_id, kms.fb_id, 0, 0,
			&kms.connector->connector_id, 1, &kms.mode);
   if (ret) {
      fprintf(stderr, "failed to set mode: %m\n");
      goto free_saved_crtc;
   }

   getchar();

   ret = drmModeSetCrtc(fd, saved_crtc->crtc_id, saved_crtc->buffer_id,
                        saved_crtc->x, saved_crtc->y,
                        &kms.connector->connector_id, 1, &saved_crtc->mode);
   if (ret) {
      fprintf(stderr, "failed to restore crtc: %m\n");
   }

free_saved_crtc:
   drmModeFreeCrtc(saved_crtc);
rm_fb:
   drmModeRmFB(fd, kms.fb_id);
   eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
destroy_context:
   eglDestroyContext(dpy, ctx);
egl_terminate:
   eglTerminate(dpy);
destroy_gbm_device:
   gbm_device_destroy(gbm);
close_fd:
   close(fd);

   return ret;
}
Пример #17
0
ExtFramebuffer::~ExtFramebuffer()
{
	drmModeRmFB(card().fd(), id());
}