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@chris-wilson.co.uk>
This commit is contained in:
Chris Wilson 2013-08-31 19:44:50 +01:00
parent 57904e8d3d
commit 8ecb758697
5 changed files with 160 additions and 77 deletions

View File

@ -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 {

View File

@ -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) {

View File

@ -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
};
static bool add_fake_output(struct sna *sna, bool late)
{
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 (sna->mode.num_fake >= 32)
return false;
DBG(("%s(late=%d, num_fake=%d)\n", __FUNCTION__, late, sna->mode.num_fake+1));
crtc = xf86CrtcCreate(scrn, &sna_crtc_funcs);
if (crtc == NULL)
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);
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);
int n, num_real_crtc, num_real_output;
bool ret;
if (num_fake == 0)
return true;
num_real_crtc = xf86_config->num_crtc;
num_real_output = xf86_config->num_output;
sna->mode.num_real_crtc = xf86_config->num_crtc;
sna->mode.num_real_output = xf86_config->num_output;
if (num_real_crtc == 0)
if (sna->mode.num_real_crtc == 0)
xf86CrtcConfigInit(sna->scrn, &sna_mode_funcs);
for (n = 0; n < num_fake; n++) {
if (!sna_crtc_fake(sna))
return false;
if (!sna_output_fake(sna, n, num_fake,
num_real_crtc, num_real_output))
return false;
}
return true;
ret = true;
while (ret && num_fake--)
ret = add_fake_output(sna, false);
return ret;
}

View File

@ -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

View File

@ -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;
}