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:
parent
57904e8d3d
commit
8ecb758697
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue