xf86-video-intel: 3 commits - src/sna/sna_display.c src/sna/sna_display_fake.c src/sna/sna.h tools/intel-virtual-output.man tools/virtual.c

Chris Wilson ickle at kemper.freedesktop.org
Sat Aug 31 14:13:32 PDT 2013


 src/sna/sna.h                  |    4 
 src/sna/sna_display.c          |    2 
 src/sna/sna_display_fake.c     |  177 +++++++++++-----
 tools/intel-virtual-output.man |    9 
 tools/virtual.c                |  447 ++++++++++++++++++++++++-----------------
 5 files changed, 393 insertions(+), 246 deletions(-)

New commits:
commit 7228bd391049be2d07c27dcf88edc2d5bff70898
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Aug 31 21:50:55 2013 +0100

    intel-virtual-output: Clone all outputs on the remote display
    
    Now that we allocate VirtualHeads on the fly, we can query the list of
    available outputs on the target display and clone them all, rather than
    manually passingthe  list of outputs to clone.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/tools/virtual.c b/tools/virtual.c
index acd7eab..d38c55e 100644
--- a/tools/virtual.c
+++ b/tools/virtual.c
@@ -128,8 +128,10 @@ struct clone {
 struct context {
 	struct display *display;
 	struct clone *clones;
-	int num_clones;
-	int num_display;
+	struct pollfd *pfd;
+	int nclone;
+	int ndisplay;
+	int nfd;
 };
 
 static int xlib_vendor_is_xorg(Display *dpy)
@@ -262,26 +264,6 @@ static int mode_equal(const XRRModeInfo *a, const XRRModeInfo *b)
 		a->modeFlags == b->modeFlags);
 }
 
-static RROutput find_output(Display *dpy, const char *name)
-{
-	XRRScreenResources *res;
-	RROutput ret = 0;
-	int i;
-
-	res = XRRGetScreenResourcesCurrent(dpy, DefaultRootWindow(dpy));
-	if (res == NULL)
-		return 0;
-
-	for (i = 0; ret == 0 && i < res->noutput; i++) {
-		XRROutputInfo *o = XRRGetOutputInfo(dpy, res, res->outputs[i]);
-		if (strcmp(o->name, name) == 0)
-			ret = res->outputs[i];
-		XRRFreeOutputInfo(o);
-	}
-	XRRFreeScreenResources(res);
-
-	return ret;
-}
 
 static XRRModeInfo *lookup_mode(XRRScreenResources *res, int id)
 {
@@ -383,35 +365,54 @@ err:
 	return ret;
 }
 
-static int claim_virtual(struct output *output)
+static RROutput claim_virtual(struct display *display, const char *name)
 {
 	char buf[] = "ClaimVirtualHead";
+	Display *dpy = display->dpy;
 	XRRScreenResources *res;
 	XRRModeInfo mode;
 	RRMode id;
+	RROutput rr_output;
+	int i;
 
-	/* Set any mode on the VirtualHead to make the Xserver allocate another */
-	assert(output->rr_output);
+	DBG(("%s(%s)\n", __func__, name));
 
+	res = XRRGetScreenResourcesCurrent(dpy, display->root);
+	if (res == NULL)
+		return 0;
+
+	for (i = rr_output = 0; rr_output == 0 && i < res->noutput; i++) {
+		XRROutputInfo *o = XRRGetOutputInfo(dpy, res, res->outputs[i]);
+		if (strcmp(o->name, name) == 0)
+			rr_output = res->outputs[i];
+		XRRFreeOutputInfo(o);
+	}
+	XRRFreeScreenResources(res);
+
+	DBG(("%s(%s): rr_output=%ld\n", __func__, name, (long)rr_output));
+	if (rr_output == 0)
+		return 0;
+
+	/* Set any mode on the VirtualHead to make the Xserver allocate another */
 	memset(&mode, 0, sizeof(mode));
 	mode.width = 1024;
 	mode.height = 768;
 	mode.name = buf;
 	mode.nameLength = sizeof(buf) - 1;
 
-	id = XRRCreateMode(output->dpy, output->window, &mode);
-	XRRAddOutputMode(output->dpy, output->rr_output, id);
+	id = XRRCreateMode(dpy, display->root, &mode);
+	XRRAddOutputMode(dpy, rr_output, id);
 
 	/* Force a redetection for the ddx to spot the new outputs */
-	res = XRRGetScreenResources(output->dpy, output->window);
+	res = XRRGetScreenResources(dpy, display->root);
 	if (res == NULL)
-		return ENOMEM;
-
+		return 0;
 	XRRFreeScreenResources(res);
-	XRRDeleteOutputMode(output->dpy, output->rr_output, id);
-	XRRDestroyMode(output->dpy, id);
 
-	return 0;
+	XRRDeleteOutputMode(dpy, rr_output, id);
+	XRRDestroyMode(dpy, id);
+
+	return rr_output;
 }
 
 static int get_current_config(struct output *output)
@@ -711,12 +712,6 @@ static void display_load_visible_cursor(struct display *display, XFixesCursorIma
 	display->cursor_visible += display->cursor != display->invisible_cursor;
 }
 
-static void display_start_cursor_move(struct display *display)
-{
-	display->cursor_moved = 0;
-	display->cursor_visible = 0;
-}
-
 static void display_cursor_move(struct display *display, int x, int y, int visible)
 {
 	display->cursor_moved++;
@@ -727,7 +722,7 @@ static void display_cursor_move(struct display *display, int x, int y, int visib
 	}
 }
 
-static void display_end_cursor_move(struct display *display)
+static void display_flush_cursor(struct display *display)
 {
 	Cursor cursor;
 	int x, y;
@@ -755,6 +750,9 @@ static void display_end_cursor_move(struct display *display)
 		XDefineCursor(display->dpy, display->root, cursor);
 		display->cursor = cursor;
 	}
+
+	display->cursor_moved = 0;
+	display->cursor_visible = 0;
 }
 
 static void clone_move_cursor(struct clone *c, int x, int y)
@@ -777,23 +775,25 @@ static void clone_move_cursor(struct clone *c, int x, int y)
 }
 
 static int clone_output_init(struct clone *clone, struct output *output,
-			     struct display *display, const char *name)
+			     struct display *display, const char *name,
+			     RROutput rr_output)
 {
 	Display *dpy = display->dpy;
 	int depth;
 
+	if (rr_output == 0)
+		return -ENOENT;
+
 	DBG(("%s(%s, %s)\n", __func__, DisplayString(dpy), name));
 
+	output->name = strdup(name);
+	if (output->name == NULL)
+		return -ENOMEM;
+
 	output->display = display;
 	output->dpy = dpy;
 
-	output->rr_output = find_output(dpy, name);
-	if (output->rr_output == 0)
-		return ENOENT;
-
-	output->name = strdup(name);
-	if (output->name == NULL)
-		return ENOMEM;
+	output->rr_output = rr_output;
 
 	output->window = display->root;
 	output->use_shm = display->has_shm;
@@ -998,7 +998,7 @@ static void clone_damage(struct clone *c, const XRectangle *rec)
 
 static void usage(const char *arg0)
 {
-	printf("usage: %s [-d <source display>] [<target display>] <target output>...\n", arg0);
+	printf("usage: %s [-d <source display>] [-b] [<target display>]...\n", arg0);
 }
 
 static void record_callback(XPointer closure, XRecordInterceptData *data)
@@ -1010,7 +1010,7 @@ static void record_callback(XPointer closure, XRecordInterceptData *data)
 		const xEvent *e = (const xEvent *)data->data;
 
 		if (e->u.u.type == MotionNotify) {
-			for (n = 0; n < ctx->num_clones; n++)
+			for (n = 0; n < ctx->nclone; n++)
 				clone_move_cursor(&ctx->clones[n],
 						  e->u.keyButtonPointer.rootX,
 						  e->u.keyButtonPointer.rootY);
@@ -1047,7 +1047,7 @@ static int record_mouse(struct context *ctx)
 	if (!XRecordEnableContextAsync(dpy, rc, record_callback, (XPointer)ctx))
 		return -EINVAL;
 
-	ctx->display[ctx->num_display].dpy = dpy;
+	ctx->display[ctx->ndisplay].dpy = dpy;
 	return ConnectionNumber(dpy);
 }
 
@@ -1217,7 +1217,7 @@ static int display_init_render(struct display *display, int depth, XRenderPictFo
 	if (display->root_format == 0) {
 		if (!XRenderQueryVersion(dpy, &major, &minor)) {
 			fprintf(stderr, "Render extension not supported by %s\n", DisplayString(dpy));
-			return EINVAL;
+			return -EINVAL;
 		}
 
 		display->root_format = XRenderFindVisualFormat(dpy, display->visual);
@@ -1236,7 +1236,7 @@ static int display_init_render(struct display *display, int depth, XRenderPictFo
 	case 24: *use_render = display->rgb24_format; break;
 	}
 	if (*use_render == 0)
-		return ENOENT;
+		return -ENOENT;
 
 	return 0;
 }
@@ -1295,10 +1295,31 @@ static int display_init_core(struct display *display)
 	return 0;
 }
 
-static int display_open(struct display *display, const char *name)
+static inline int is_power_of_2(unsigned long n)
+{
+	return n && ((n & (n - 1)) == 0);
+}
+
+static struct display *add_display(struct context *ctx)
 {
+	if (is_power_of_2(ctx->ndisplay)) {
+		ctx->display = realloc(ctx->display, 2*ctx->ndisplay*sizeof(struct display));
+		if (ctx->display == NULL)
+			return NULL;
+	}
+
+	return memset(&ctx->display[ctx->ndisplay++], 0, sizeof(struct display));
+}
+
+static int display_open(struct context *ctx, const char *name)
+{
+	struct display *display;
 	int ret;
 
+	display = add_display(ctx);
+	if (display == NULL)
+		return -ENOMEM;
+
 	DBG(("%s(%s)\n", __func__, name));
 
 	display->dpy = XOpenDisplay(name);
@@ -1314,10 +1335,11 @@ static int display_open(struct display *display, const char *name)
 	return ConnectionNumber(display->dpy);
 }
 
-static int bumblebee_open(struct display *display)
+static int bumblebee_open(struct context *ctx)
 {
 	char buf[256];
 	struct sockaddr_un addr;
+	struct display *display;
 	int fd, len;
 
 	fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
@@ -1350,6 +1372,10 @@ static int bumblebee_open(struct display *display)
 	while (isspace(buf[--len]))
 		buf[len] = '\0';
 
+	display = add_display(ctx);
+	if (display == NULL)
+		return -ENOMEM;
+
 	display->dpy = XOpenDisplay(buf+7);
 	if (display->dpy == NULL) {
 		fprintf(stderr, "Unable to connect to bumblebee Xserver on %s\n", buf+7);
@@ -1384,6 +1410,42 @@ static int display_init_damage(struct display *display)
 	return 0;
 }
 
+static int context_init(struct context *ctx)
+{
+	memset(ctx, 0, sizeof(*ctx));
+
+	ctx->pfd = malloc(sizeof(struct pollfd));
+	if (ctx->pfd == NULL)
+		return -ENOMEM;
+
+	ctx->clones = malloc(sizeof(struct clone));
+	if (ctx->clones == NULL)
+		return -ENOMEM;
+
+	ctx->display = malloc(sizeof(struct display));
+	if (ctx->display == NULL)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int add_fd(struct context *ctx, int fd)
+{
+	if (fd < 0)
+		return fd;
+
+	if (is_power_of_2(ctx->nfd)) {
+		ctx->pfd = realloc(ctx->pfd, 2*ctx->nfd*sizeof(struct pollfd));
+		if (ctx->pfd == NULL)
+			return -ENOMEM;
+	}
+
+	ctx->pfd[ctx->nfd].fd = fd;
+	ctx->pfd[ctx->nfd].events = POLLIN;
+	ctx->nfd++;
+	return 0;
+}
+
 static void display_init_randr_hpd(struct display *display)
 {
 	int major, minor;
@@ -1397,42 +1459,93 @@ static void display_init_randr_hpd(struct display *display)
 		XRRSelectInput(display->dpy, display->root, RROutputChangeNotifyMask);
 }
 
-static void display_flush(struct display *display)
+static struct clone *add_clone(struct context *ctx)
 {
-	if (!display->flush)
-		return;
-
-	DBG(("%s(%s)\n", __func__, DisplayString(display->dpy)));
+	if (is_power_of_2(ctx->nclone)) {
+		ctx->clones = realloc(ctx->clones, 2*ctx->nclone*sizeof(struct clone));
+		if (ctx->clones == NULL)
+			return NULL;
+	}
 
-	XFlush(display->dpy);
-	display->flush = 0;
+	return memset(&ctx->clones[ctx->nclone++], 0, sizeof(struct clone));
 }
 
-static int context_init(struct context *ctx, int num_clones)
+static int last_display_add_clones(struct context *ctx)
 {
-	memset(ctx, 0, sizeof(*ctx));
+	struct display *display = &ctx->display[ctx->ndisplay-1];
+	XRRScreenResources *res;
+	char buf[80];
+	int i, ret;
 
-	ctx->display = calloc(num_clones+2, sizeof(struct display));
-	if (ctx->display == NULL)
-		return ENOMEM;
+	display_init_randr_hpd(display);
 
-	ctx->clones = calloc(num_clones, sizeof(struct clone));
-	if (ctx->clones == NULL)
-		return ENOMEM;
+	res = XRRGetScreenResourcesCurrent(display->dpy, display->root);
+	if (res == NULL)
+		return -ENOMEM;
 
+	for (i = 0; i < res->noutput; i++) {
+		XRROutputInfo *o = XRRGetOutputInfo(display->dpy, res, res->outputs[i]);
+		struct clone *clone = add_clone(ctx);
+
+		clone->depth = 24;
+
+		sprintf(buf, "VIRTUAL%d", ctx->nclone);
+		ret = clone_output_init(clone, &clone->src, ctx->display, buf, claim_virtual(ctx->display, buf));
+		if (ret) {
+			fprintf(stderr, "Failed to find available VirtualHead for \"%s\" on display \"%s\"\n",
+				o->name, DisplayString(display->dpy));
+			return ret;
+		}
+
+		ret = clone_output_init(clone, &clone->dst, display, o->name, res->outputs[i]);
+		if (ret) {
+			fprintf(stderr, "Failed to add output \"%s\" on display \"%s\"\n",
+				o->name, DisplayString(display->dpy));
+			return ret;
+		}
+
+		ret = clone_init_depth(clone);
+		if (ret) {
+			fprintf(stderr, "Failed to negotiate image format for display \"%s\"\n",
+				DisplayString(display->dpy));
+			return ret;
+		}
+
+		ret = clone_update_dst(&clone->dst, &clone->src);
+		if (ret) {
+			fprintf(stderr, "Failed to clone output \"%s\" from display \"%s\"\n",
+				o->name, DisplayString(display->dpy));
+			return ret;
+		}
+
+		XRRFreeOutputInfo(o);
+	}
+	XRRFreeScreenResources(res);
 	return 0;
 }
 
+static void display_flush(struct display *display)
+{
+	display_flush_cursor(display);
+
+	if (!display->flush)
+		return;
+
+	DBG(("%s(%s)\n", __func__, DisplayString(display->dpy)));
+
+	XFlush(display->dpy);
+	display->flush = 0;
+}
+
 int main(int argc, char **argv)
 {
 	struct context ctx;
 	const char *src_name = NULL;
-	struct pollfd *pfd;
 	uint64_t count;
-	int nfd, enable_timer = 0;
-	int i, ret, daemonize = 1;
+	int enable_timer = 0;
+	int i, ret, daemonize = 1, bumblebee = 0;
 
-	while ((i = getopt(argc, argv, "d:fh")) != -1) {
+	while ((i = getopt(argc, argv, "bd:fh")) != -1) {
 		switch (i) {
 		case 'd':
 			src_name = optarg;
@@ -1440,6 +1553,9 @@ int main(int argc, char **argv)
 		case 'f':
 			daemonize = 0;
 			break;
+		case 'b':
+			bumblebee = 1;
+			break;
 		case 'h':
 		default:
 			usage(argv[0]);
@@ -1447,104 +1563,58 @@ int main(int argc, char **argv)
 		}
 	}
 
-	count = argc - optind;
-	if (count < 2) {
-		usage(argv[0]);
-		exit(EINVAL);
-	}
-
-	pfd = malloc(sizeof(struct pollfd) * (count+3));
-	if (pfd == NULL)
-		return ENOMEM;
-
-	ret = context_init(&ctx, count);
+	ret = context_init(&ctx);
 	if (ret)
-		return ret;
+		return -ret;
 
-	nfd = 1;
-	pfd->events = POLLIN;
-	pfd->fd = display_open(&ctx.display[0], src_name);
-	if (pfd->fd < 0)
-		return -pfd->fd;
+	ret = add_fd(&ctx, display_open(&ctx, src_name));
+	if (ret)
+		return -ret;
 
-	ret = display_init_damage(&ctx.display[0]);
+	ret = display_init_damage(ctx.display);
 	if (ret)
 		return ret;
 
-	XRRSelectInput(ctx.display[0].dpy, ctx.display[0].root, RRScreenChangeNotifyMask);
-	XFixesSelectCursorInput(ctx.display[0].dpy, ctx.display[0].root, XFixesDisplayCursorNotifyMask);
-	ctx.num_display++;
-
-	for (i = optind; i < argc; i++) {
-		char buf[80];
-
-		if (strchr(argv[i], ':')) {
-			pfd[nfd].fd = display_open(&ctx.display[ctx.num_display++], argv[i]);
-			if (pfd[nfd].fd < 0)
-				return -pfd[nfd].fd;
-			pfd[nfd].events = POLLIN;
-			nfd++;
-
-			display_init_randr_hpd(&ctx.display[ctx.num_display-1]);
-			continue;
-		}
-		if (nfd == 1) {
-			pfd[nfd].fd = bumblebee_open(&ctx.display[ctx.num_display++]);
-			if (pfd[nfd].fd < 0)
-				return -pfd[nfd].fd;
-			pfd[nfd].events = POLLIN;
-			nfd++;
-
-			display_init_randr_hpd(&ctx.display[ctx.num_display-1]);
-		}
-
-		ctx.clones[ctx.num_clones].depth = 24;
-
-		sprintf(buf, "VIRTUAL%d", ctx.num_clones+1);
-		ret = clone_output_init(&ctx.clones[ctx.num_clones], &ctx.clones[ctx.num_clones].src, &ctx.display[0], buf);
-		if (ret || claim_virtual(&ctx.clones[ctx.num_clones].src)) {
-			fprintf(stderr, "Failed to find available VirtualHead for argv[i].\n");
-			return ret;
-		}
+	XRRSelectInput(ctx.display->dpy, ctx.display->root, RRScreenChangeNotifyMask);
+	XFixesSelectCursorInput(ctx.display->dpy, ctx.display->root, XFixesDisplayCursorNotifyMask);
 
-		ret = clone_output_init(&ctx.clones[ctx.num_clones], &ctx.clones[ctx.num_clones].dst, &ctx.display[ctx.num_display-1], argv[i]);
+	if (optind == argc || bumblebee) {
+		ret = add_fd(&ctx, bumblebee_open(&ctx));
 		if (ret) {
-			fprintf(stderr, "Unable to find output \"%s\" on display \"%s\"\n",
-				argv[i], DisplayString(ctx.display[nfd-1].dpy));
-			return ret;
+			if (!bumblebee) {
+				usage(argv[0]);
+				return 0;
+			}
+			return -ret;
 		}
 
-		ret = clone_init_depth(&ctx.clones[ctx.num_clones]);
-		if (ret) {
-			fprintf(stderr, "Failed to negotiate image format for display \"%s\"\n",
-				DisplayString(ctx.display[nfd-1].dpy));
-			return ret;
-		}
+		ret = last_display_add_clones(&ctx);
+		if (ret)
+			return -ret;
+	}
 
-		ret = clone_update_dst(&ctx.clones[ctx.num_clones].dst, &ctx.clones[ctx.num_clones].src);
-		if (ret) {
-			fprintf(stderr, "Failed to clone output \"%s\" from display \"%s\"\n",
-				argv[i], DisplayString(ctx.display[nfd-1].dpy));
-			return ret;
-		}
+	for (i = optind; i < argc; i++) {
+		ret = add_fd(&ctx, display_open(&ctx, argv[i]));
+		if (ret)
+			return -ret;
 
-		ctx.num_clones++;
+		ret = last_display_add_clones(&ctx);
+		if (ret)
+			return -ret;
 	}
 
-	pfd[nfd].fd = record_mouse(&ctx);
-	if (pfd[nfd].fd < 0) {
+	ret = add_fd(&ctx, record_mouse(&ctx));
+	if (ret) {
 		fprintf(stderr, "XTEST extension not supported by display \"%s\"\n", DisplayString(ctx.display[0].dpy));
-		return -pfd[nfd].fd;
+		return -ret;
 	}
-	pfd[nfd].events = POLLIN;
-	nfd++;
 
-	pfd[nfd].fd = timer(60);
-	if (pfd[nfd].fd < 0) {
+	ret = add_fd(&ctx, timer(60));
+	if (ret) {
 		fprintf(stderr, "Failed to setup timer\n");
-		return -pfd[nfd].fd;
+		return -ret;
 	}
-	pfd[nfd].events = POLLIN;
+	ctx.nfd--; /* we only conditionally poll the timer */
 
 	if (daemonize && daemon(0, 0))
 		return EINVAL;
@@ -1553,53 +1623,50 @@ int main(int argc, char **argv)
 		XEvent e;
 		int reconfigure = 0;
 
-		ret = poll(pfd, nfd + enable_timer, -1);
+		ret = poll(ctx.pfd, ctx.nfd + enable_timer, -1);
 		if (ret <= 0)
 			break;
 
-		for (i = 1; i < ctx.num_display; i++)
-			display_start_cursor_move(&ctx.display[i]);
-
-		if (pfd[0].revents) {
+		if (ctx.pfd[0].revents) {
 			int damaged = 0;
 
 			do {
-				XNextEvent(ctx.display[0].dpy, &e);
+				XNextEvent(ctx.display->dpy, &e);
 
-				if (e.type == ctx.display[0].damage_event + XDamageNotify ) {
+				if (e.type == ctx.display->damage_event + XDamageNotify ) {
 					const XDamageNotifyEvent *de = (const XDamageNotifyEvent *)&e;
-					for (i = 0; i < ctx.num_clones; i++)
+					for (i = 0; i < ctx.nclone; i++)
 						clone_damage(&ctx.clones[i], &de->area);
 					if (!enable_timer)
-						enable_timer = read(pfd[nfd].fd, &count, sizeof(count)) > 0;
+						enable_timer = read(ctx.pfd[ctx.nfd].fd, &count, sizeof(count)) > 0;
 					damaged++;
-				} else if (e.type == ctx.display[0].xfixes_event + XFixesCursorNotify) {
+				} else if (e.type == ctx.display->xfixes_event + XFixesCursorNotify) {
 					XFixesCursorImage *cur;
 
-					cur = XFixesGetCursorImage(ctx.display[0].dpy);
+					cur = XFixesGetCursorImage(ctx.display->dpy);
 					if (cur == NULL)
 						continue;
 
-					for (i = 1; i < ctx.num_display; i++)
+					for (i = 1; i < ctx.ndisplay; i++)
 						display_load_visible_cursor(&ctx.display[i], cur);
 
 					XFree(cur);
-				} else if (e.type == ctx.display[0].rr_event + RRScreenChangeNotify) {
+				} else if (e.type == ctx.display->rr_event + RRScreenChangeNotify) {
 					reconfigure = 1;
 					if (!enable_timer)
-						enable_timer = read(pfd[nfd].fd, &count, sizeof(count)) > 0;
+						enable_timer = read(ctx.pfd[ctx.nfd].fd, &count, sizeof(count)) > 0;
 				} else {
 					DBG(("unknown event %d\n", e.type));
 				}
-			} while (XPending(ctx.display[0].dpy) || poll(pfd, 1, 0) > 0);
+			} while (XPending(ctx.display->dpy) || poll(ctx.pfd, 1, 0) > 0);
 
 			if (damaged)
-				XDamageSubtract(ctx.display[0].dpy, ctx.display[0].damage, None, None);
+				XDamageSubtract(ctx.display->dpy, ctx.display->damage, None, None);
 			ret--;
 		}
 
-		for (i = 1; ret && i < ctx.num_display; i++) {
-			if (pfd[i].revents == 0)
+		for (i = 1; ret && i < ctx.ndisplay; i++) {
+			if (ctx.pfd[i].revents == 0)
 				continue;
 
 			do {
@@ -1611,34 +1678,31 @@ int main(int argc, char **argv)
 						XRROutputPropertyNotifyEvent *ro = (XRROutputPropertyNotifyEvent *)re;
 						int j;
 
-						for (j = 0; j < ctx.num_clones; j++) {
+						for (j = 0; j < ctx.nclone; j++) {
 							if (ctx.clones[j].dst.display == &ctx.display[i] &&
 							    ctx.clones[j].dst.rr_output == ro->output)
 								ctx.clones[j].rr_update = 1;
 						}
 					}
 				}
-			} while (XPending(ctx.display[i].dpy) || poll(&pfd[i], 1, 0) > 0);
+			} while (XPending(ctx.display[i].dpy) || poll(&ctx.pfd[i], 1, 0) > 0);
 
 			ret--;
 		}
 
-		for (i = 0; i < ctx.num_clones; i++)
+		for (i = 0; i < ctx.nclone; i++)
 			clone_update(&ctx.clones[i], reconfigure);
 
-		if (enable_timer && read(pfd[nfd].fd, &count, sizeof(count)) > 0 && count > 0) {
+		if (enable_timer && read(ctx.pfd[ctx.nfd].fd, &count, sizeof(count)) > 0 && count > 0) {
 			ret = 0;
-			for (i = 0; i < ctx.num_clones; i++)
+			for (i = 0; i < ctx.nclone; i++)
 				ret |= clone_paint(&ctx.clones[i]);
 			enable_timer = ret != 0;
 		}
 
-		XPending(ctx.display[ctx.num_display].dpy);
-
-		for (i = 1; i < ctx.num_display; i++)
-			display_end_cursor_move(&ctx.display[i]);
+		XPending(ctx.display[ctx.ndisplay].dpy);
 
-		for (i = 0; i < ctx.num_display; i++)
+		for (i = 0; i < ctx.ndisplay; i++)
 			display_flush(&ctx.display[i]);
 	}
 
commit 028412faa7bb1d276e1dcdbe485c920acf73a719
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Aug 31 20:58:48 2013 +0100

    intel-virtual-output: Third time lucky for computing the correct stride?
    
    Aligning a 16-bpp image to a 32-byte boundary is tricky, apparently. Or
    at least I make it look so.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/tools/virtual.c b/tools/virtual.c
index 00342c9..acd7eab 100644
--- a/tools/virtual.c
+++ b/tools/virtual.c
@@ -513,7 +513,7 @@ static int stride_for_depth(int width, int depth)
 {
 	if (depth == 24)
 		depth = 32;
-	return (width * depth + 31) / 8;
+	return ((width * depth + 7) / 8 + 3) & ~3;
 }
 
 static void init_image(struct clone *clone)
commit 8ecb758697af42e8e68edee0d1945986470a9c04
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Aug 31 19:44:50 2013 +0100

    sna: Expand the array of fake outputs if the last is used
    
    Always maintain one spare so that we can reconfigure for any number of
    desired outputs on the fly.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna.h b/src/sna/sna.h
index 298883c..c47a8ab 100644
--- a/src/sna/sna.h
+++ b/src/sna/sna.h
@@ -265,6 +265,10 @@ struct sna {
 		DamagePtr shadow_damage;
 		struct kgem_bo *shadow;
 		int shadow_flip;
+
+		unsigned num_real_crtc;
+		unsigned num_real_output;
+		unsigned num_fake;
 	} mode;
 
 	struct sna_dri {
diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index aa445ae..263bae9 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -3211,7 +3211,7 @@ bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
 	}
 
 	if (!xf86GetOptValInteger(sna->Options, OPTION_VIRTUAL, &num_fake))
-		num_fake = 0;
+		num_fake = 1;
 
 	mode->kmode = drmModeGetResources(sna->kgem.fd);
 	if (mode->kmode) {
diff --git a/src/sna/sna_display_fake.c b/src/sna/sna_display_fake.c
index 73fca7e..3daa793 100644
--- a/src/sna/sna_display_fake.c
+++ b/src/sna/sna_display_fake.c
@@ -31,6 +31,8 @@
 
 #include "sna.h"
 
+static bool add_fake_output(struct sna *sna, bool late);
+
 static void
 sna_crtc_dpms(xf86CrtcPtr crtc, int mode)
 {
@@ -102,21 +104,6 @@ static const xf86CrtcFuncsRec sna_crtc_funcs = {
 #endif
 };
 
-static bool
-sna_crtc_fake(struct sna *sna)
-{
-	ScrnInfoPtr scrn = sna->scrn;
-	xf86CrtcPtr crtc;
-
-	DBG(("%s\n", __FUNCTION__));
-
-	crtc = xf86CrtcCreate(scrn, &sna_crtc_funcs);
-	if (crtc == NULL)
-		return false;
-
-	return true;
-}
-
 static void
 sna_output_create_resources(xf86OutputPtr output)
 {
@@ -143,8 +130,14 @@ sna_output_dpms(xf86OutputPtr output, int dpms)
 static xf86OutputStatus
 sna_output_detect(xf86OutputPtr output)
 {
-	if (output->randr_output->numUserModes)
+	if (output->randr_output->numUserModes) {
+		xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(output->scrn);
+
+		if (xf86_config->output[xf86_config->num_output-1] == output)
+			add_fake_output(to_sna(output->scrn), true);
+
 		return XF86OutputStatusConnected;
+	}
 
 	return XF86OutputStatusDisconnected;
 }
@@ -183,32 +176,6 @@ static const xf86OutputFuncsRec sna_output_funcs = {
 	.destroy = sna_output_destroy
 };
 
-static bool
-sna_output_fake(struct sna *sna, int n, int num_fake, int num_real_crtc, int num_real_output)
-{
-	ScrnInfoPtr scrn = sna->scrn;
-	xf86OutputPtr output;
-	unsigned mask;
-	char buf[80];
-
-	sprintf(buf, "VIRTUAL%d", n+1);
-	output = xf86OutputCreate(scrn, &sna_output_funcs, buf);
-	if (!output)
-		return false;
-
-	output->mm_width = 0;
-	output->mm_height = 0;
-
-	output->subpixel_order = SubPixelNone;
-
-	mask = (1 << num_fake) - 1;
-	output->possible_crtcs = mask << num_real_crtc;
-	output->possible_clones = mask << num_real_output;
-	output->interlaceAllowed = FALSE;
-
-	return true;
-}
-
 static Bool
 sna_mode_resize(ScrnInfoPtr scrn, int width, int height)
 {
@@ -251,28 +218,126 @@ static const xf86CrtcConfigFuncsRec sna_mode_funcs = {
 	sna_mode_resize
 };
 
-bool sna_mode_fake_init(struct sna *sna, int num_fake)
+static bool add_fake_output(struct sna *sna, bool late)
 {
-	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(sna->scrn);
-	int n, num_real_crtc, num_real_output;
+	ScrnInfoPtr scrn = sna->scrn;
+	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+	xf86OutputPtr output;
+	xf86CrtcPtr crtc;
+	RROutputPtr clones[32];
+	RRCrtcPtr crtcs[32];
+	unsigned mask;
+	char buf[80];
+	int i, j, len;
 
-	if (num_fake == 0)
-		return true;
+	if (sna->mode.num_fake >= 32)
+		return false;
 
-	num_real_crtc = xf86_config->num_crtc;
-	num_real_output = xf86_config->num_output;
+	DBG(("%s(late=%d, num_fake=%d)\n", __FUNCTION__, late, sna->mode.num_fake+1));
 
-	if (num_real_crtc == 0)
-		xf86CrtcConfigInit(sna->scrn, &sna_mode_funcs);
+	crtc = xf86CrtcCreate(scrn, &sna_crtc_funcs);
+	if (crtc == NULL)
+		return false;
 
-	for (n = 0; n < num_fake; n++) {
-		if (!sna_crtc_fake(sna))
-			return false;
+	len = sprintf(buf, "VIRTUAL%d", sna->mode.num_fake+1);
+	output = xf86OutputCreate(scrn, &sna_output_funcs, buf);
+	if (!output) {
+		xf86CrtcDestroy(crtc);
+		return false;
+	}
+
+	output->mm_width = 0;
+	output->mm_height = 0;
+	output->interlaceAllowed = FALSE;
+	output->subpixel_order = SubPixelNone;
+
+	if (late) {
+		ScreenPtr screen = xf86ScrnToScreen(scrn);
 
-		if (!sna_output_fake(sna, n, num_fake,
-				     num_real_crtc, num_real_output))
+		crtc->randr_crtc = RRCrtcCreate(screen, crtc);
+		output->randr_output = RROutputCreate(screen, buf, len, output);
+		if (crtc->randr_crtc == NULL || output->randr_output == NULL) {
+			xf86OutputDestroy(output);
+			xf86CrtcDestroy(crtc);
 			return false;
+		}
+
+		RRPostPendingProperties(output->randr_output);
+
+		mask = (1 << ++sna->mode.num_fake) - 1;
+		for (i = j = 0; i < xf86_config->num_output; i++) {
+			output = xf86_config->output[i];
+			if (output->driver_private)
+				continue;
+
+			output->possible_crtcs = mask << sna->mode.num_real_crtc;
+			output->possible_clones = mask << sna->mode.num_real_output;
+
+			clones[j++] = output->randr_output;
+		}
+		assert(j == sna->mode.num_fake);
+
+		for (i = j = 0; i < xf86_config->num_crtc; i++) {
+			crtc = xf86_config->crtc[i];
+			if (crtc->driver_private)
+				continue;
+
+			crtcs[j++] = crtc->randr_crtc;
+		}
+		assert(j == sna->mode.num_fake);
+
+		for (i = 0; i < xf86_config->num_output; i++) {
+			output = xf86_config->output[i];
+			if (output->driver_private)
+				continue;
+
+			if (!RROutputSetCrtcs(output->randr_output, crtcs, j) ||
+			    !RROutputSetClones(output->randr_output, clones, j))
+				goto err;
+		}
+	} else {
+		mask = (1 << ++sna->mode.num_fake) - 1;
+		output->possible_crtcs = mask << sna->mode.num_real_crtc;
+		output->possible_clones = mask << sna->mode.num_real_output;
 	}
 
 	return true;
+
+err:
+	for (i = 0; i < xf86_config->num_output; i++) {
+		output = xf86_config->output[i];
+		if (output->driver_private)
+			continue;
+
+		xf86OutputDestroy(output);
+	}
+
+	for (i = 0; i < xf86_config->num_crtc; i++) {
+		crtc = xf86_config->crtc[i];
+		if (crtc->driver_private)
+			continue;
+		xf86CrtcDestroy(crtc);
+	}
+	sna->mode.num_fake = -1;
+	return false;
+}
+
+bool sna_mode_fake_init(struct sna *sna, int num_fake)
+{
+	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(sna->scrn);
+	bool ret;
+
+	if (num_fake == 0)
+		return true;
+
+	sna->mode.num_real_crtc = xf86_config->num_crtc;
+	sna->mode.num_real_output = xf86_config->num_output;
+
+	if (sna->mode.num_real_crtc == 0)
+		xf86CrtcConfigInit(sna->scrn, &sna_mode_funcs);
+
+	ret = true;
+	while (ret && num_fake--)
+		ret = add_fake_output(sna, false);
+	return ret;
 }
diff --git a/tools/intel-virtual-output.man b/tools/intel-virtual-output.man
index 7a2e626..675238c 100644
--- a/tools/intel-virtual-output.man
+++ b/tools/intel-virtual-output.man
@@ -5,19 +5,12 @@
 intel-virtual-output \- Utility for connecting the Integrated Intel GPU to discrete outputs
 .SH SYNOPSIS
 .nf
-.B "Section \*qDevice\*q"
-.BI "  Identifier \*q"  devname \*q
-.B  "  Driver \*qintel\*q"
-.B  "  Option \*qVirtualHeads\*q" \*q<number>\*q
-\ \ ...
-.B EndSection
-.B ""
 .B "intel-virtual-output [<remote display>] <output name>..."
 .fi
 .SH DESCRIPTION
 .B intel-virtual-output
 is a utility for Intel integrated graphics chipsets on hybrid systems.
-The tool connects pre-allocated VirtualHeads to a remote output, allowing
+The tool connects local VirtualHeads to a remote output, allowing
 the primary display to extend onto the remote outputs.
 
 .SH REPORTING BUGS
diff --git a/tools/virtual.c b/tools/virtual.c
index d3f71a6..00342c9 100644
--- a/tools/virtual.c
+++ b/tools/virtual.c
@@ -383,6 +383,37 @@ err:
 	return ret;
 }
 
+static int claim_virtual(struct output *output)
+{
+	char buf[] = "ClaimVirtualHead";
+	XRRScreenResources *res;
+	XRRModeInfo mode;
+	RRMode id;
+
+	/* Set any mode on the VirtualHead to make the Xserver allocate another */
+	assert(output->rr_output);
+
+	memset(&mode, 0, sizeof(mode));
+	mode.width = 1024;
+	mode.height = 768;
+	mode.name = buf;
+	mode.nameLength = sizeof(buf) - 1;
+
+	id = XRRCreateMode(output->dpy, output->window, &mode);
+	XRRAddOutputMode(output->dpy, output->rr_output, id);
+
+	/* Force a redetection for the ddx to spot the new outputs */
+	res = XRRGetScreenResources(output->dpy, output->window);
+	if (res == NULL)
+		return ENOMEM;
+
+	XRRFreeScreenResources(res);
+	XRRDeleteOutputMode(output->dpy, output->rr_output, id);
+	XRRDestroyMode(output->dpy, id);
+
+	return 0;
+}
+
 static int get_current_config(struct output *output)
 {
 	XRRScreenResources *res;
@@ -1471,18 +1502,8 @@ int main(int argc, char **argv)
 
 		sprintf(buf, "VIRTUAL%d", ctx.num_clones+1);
 		ret = clone_output_init(&ctx.clones[ctx.num_clones], &ctx.clones[ctx.num_clones].src, &ctx.display[0], buf);
-		if (ret) {
-			while (++i < argc)
-				ctx.num_clones += strchr(argv[i], ':') == NULL;
-			fprintf(stderr,
-				"No preallocated VirtualHead found for argv[i].\n"
-				"Please increase the number of VirtualHeads in xorg.conf:\n"
-				"  Section \"Device\"\n"
-				"    Identifier \"<identifier>\"\n"
-				"    Driver \"intel\"\n"
-				"    Option \"VirtualHeads\" \"%d\"\n"
-				"    ...\n"
-				"  EndSection\n", ctx.num_clones+1);
+		if (ret || claim_virtual(&ctx.clones[ctx.num_clones].src)) {
+			fprintf(stderr, "Failed to find available VirtualHead for argv[i].\n");
 			return ret;
 		}
 


More information about the xorg-commit mailing list