summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2013-08-29 23:00:05 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2013-08-30 08:57:25 +0100
commit68d139388a2a037347fa5c838391e67e006793ee (patch)
treefcac6d4c98fd88b1c9bd24483972da6a95cbd739
parent92a43caab96e7f49c541fb999b75925914d9981a (diff)
sna: Allow user specification of number of VirtualHeads
Previously, we instantiated a fake output in case we had a machine with no output. (For certain server-class products.) The Bumblee project were also doing something very similar in order to fake an extended desktop on the Intel igfx and copy portions onto a discrete GPU. (The preferred method for doing this upstream is through the use of PRIME). As the code is very similar, we can support both use-cases simultaneously. This adds the option: Section "Device" Driver "intel" Option "VirtualHeads" "<count>" EndSection to allow the user to specify an additional set of fake outputs, which can then be controlled using xrandr. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r--man/intel.man12
-rw-r--r--src/intel_options.c1
-rw-r--r--src/intel_options.h1
-rw-r--r--src/sna/sna.h2
-rw-r--r--src/sna/sna_display.c62
-rw-r--r--src/sna/sna_display_fake.c40
6 files changed, 93 insertions, 25 deletions
diff --git a/man/intel.man b/man/intel.man
index 9e19687b..0a265114 100644
--- a/man/intel.man
+++ b/man/intel.man
@@ -261,6 +261,18 @@ applications when monitors are connected or disconnected.
.IP
Default: enabled.
.TP
+.BI "Option \*qVirtualheads\*q \*q" integer \*q
+This option controls specifies the number of fake outputs to create in
+addition to the normal outputs detected on your hardware. These outputs
+cannot be assigned to the regular displays attached to the GPU, but do
+otherwise act as any other xrandr output and share a portion of the
+regular framebuffer. One use case for these extra heads is for extending
+your desktop onto a discrete GPU using the Bumblebee project. However,
+the recommendation here is to use PRIME instead to create a single
+Xserver that can addresses and coordinate between multiple GPUs.
+.IP
+Default: 0
+.TP
.BI "Option \*qZaphodHeads\*q \*q" string \*q
.IP
Specify the randr output(s) to use with zaphod mode for a particular driver
diff --git a/src/intel_options.c b/src/intel_options.c
index b81bde6e..153cc629 100644
--- a/src/intel_options.c
+++ b/src/intel_options.c
@@ -23,6 +23,7 @@ const OptionInfoRec intel_options[] = {
#endif
#ifdef USE_SNA
{OPTION_ZAPHOD, "ZaphodHeads", OPTV_STRING, {0}, 0},
+ {OPTION_VIRTUAL, "VirtualHeads", OPTV_INTEGER, {0}, 0},
{OPTION_TEAR_FREE, "TearFree", OPTV_BOOLEAN, {0}, 0},
{OPTION_CRTC_PIXMAPS, "PerCrtcPixmaps", OPTV_BOOLEAN, {0}, 0},
#endif
diff --git a/src/intel_options.h b/src/intel_options.h
index 112983d5..095660c3 100644
--- a/src/intel_options.h
+++ b/src/intel_options.h
@@ -30,6 +30,7 @@ enum intel_options {
#endif
#ifdef USE_SNA
OPTION_ZAPHOD,
+ OPTION_VIRTUAL,
OPTION_TEAR_FREE,
OPTION_CRTC_PIXMAPS,
#endif
diff --git a/src/sna/sna.h b/src/sna/sna.h
index 337ebc89..5b26ebfd 100644
--- a/src/sna/sna.h
+++ b/src/sna/sna.h
@@ -330,7 +330,7 @@ struct sna {
};
bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna);
-bool sna_mode_fake_init(struct sna *sna);
+bool sna_mode_fake_init(struct sna *sna, int num_fake);
void sna_mode_adjust_frame(struct sna *sna, int x, int y);
extern void sna_mode_update(struct sna *sna);
extern void sna_mode_wakeup(struct sna *sna);
diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index da3475ff..aa445ae3 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -2758,8 +2758,15 @@ sna_mode_resize(ScrnInfoPtr scrn, int width, int height)
"resizing framebuffer to %dx%d\n",
width, height);
- for (i = 0; i < xf86_config->num_crtc; i++)
- sna_crtc_disable_shadow(sna, to_sna_crtc(xf86_config->crtc[i]));
+ for (i = 0; i < xf86_config->num_crtc; i++) {
+ struct sna_crtc *crtc;
+
+ crtc = to_sna_crtc(xf86_config->crtc[i]);
+ if (crtc == NULL)
+ continue;
+
+ sna_crtc_disable_shadow(sna, crtc);
+ }
assert(sna->mode.shadow_active == 0);
assert(sna->mode.shadow_damage == NULL);
assert(sna->mode.shadow == NULL);
@@ -2778,7 +2785,7 @@ sna_mode_resize(ScrnInfoPtr scrn, int width, int height)
for (i = 0; i < xf86_config->num_crtc; i++) {
xf86CrtcPtr crtc = xf86_config->crtc[i];
- if (!crtc->enabled)
+ if (!crtc->enabled || to_sna_crtc(crtc) == NULL)
continue;
if (!sna_crtc_set_mode_major(crtc,
@@ -2818,8 +2825,8 @@ static int do_page_flip(struct sna *sna, struct kgem_bo *bo,
struct drm_mode_crtc_page_flip arg;
DBG(("%s: crtc %d active? %d\n",
- __FUNCTION__, i, crtc->bo != NULL));
- if (crtc->bo == NULL)
+ __FUNCTION__, i, crtc && crtc->bo));
+ if (crtc == NULL || crtc->bo == NULL)
continue;
arg.crtc_id = crtc->id;
@@ -3019,6 +3026,9 @@ static bool sna_probe_initial_configuration(struct sna *sna)
struct drm_mode_crtc mode;
uint16_t *gamma;
+ if (sna_crtc == NULL)
+ continue;
+
crtc->enabled = FALSE;
crtc->desiredMode.status = MODE_NOMODE;
@@ -3088,6 +3098,9 @@ static bool sna_probe_initial_configuration(struct sna *sna)
xf86OutputPtr output = config->output[i];
uint32_t crtc_id;
+ if (to_sna_output(output) == NULL)
+ continue;
+
crtc_id = (uintptr_t)output->crtc;
output->crtc = NULL;
@@ -3189,6 +3202,7 @@ sna_crtc_config_notify(ScreenPtr screen)
bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
{
struct sna_mode *mode = &sna->mode;
+ int num_fake = 0;
int i;
if (sna->flags & SNA_IS_HOSTED) {
@@ -3196,6 +3210,9 @@ bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
return true;
}
+ if (!xf86GetOptValInteger(sna->Options, OPTION_VIRTUAL, &num_fake))
+ num_fake = 0;
+
mode->kmode = drmModeGetResources(sna->kgem.fd);
if (mode->kmode) {
xf86CrtcConfigInit(scrn, &sna_mode_funcs);
@@ -3211,17 +3228,20 @@ bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
if (!xf86IsEntityShared(scrn->entityList[0]))
sna_mode_compute_possible_clones(scrn);
-
- sna_setup_provider(scrn);
} else {
- if (!sna_mode_fake_init(sna))
- return false;
+ if (num_fake == 0)
+ num_fake = 1;
}
set_size_range(sna);
+ if (!sna_mode_fake_init(sna, num_fake))
+ return false;
+
if (!sna_probe_initial_configuration(sna))
xf86InitialConfiguration(scrn, TRUE);
+
+ sna_setup_provider(scrn);
return scrn->modes != NULL;
}
@@ -3241,8 +3261,15 @@ sna_mode_close(struct sna *sna)
if (sna->flags & SNA_IS_HOSTED)
return;
- for (i = 0; i < xf86_config->num_crtc; i++)
- sna_crtc_disable_shadow(sna, to_sna_crtc(xf86_config->crtc[i]));
+ for (i = 0; i < xf86_config->num_crtc; i++) {
+ struct sna_crtc *crtc;
+
+ crtc = to_sna_crtc(xf86_config->crtc[i]);
+ if (crtc == NULL)
+ continue;
+
+ sna_crtc_disable_shadow(sna, crtc);
+ }
}
void
@@ -3567,7 +3594,8 @@ sna_wait_for_scanline(struct sna *sna,
int y1, y2, pipe;
bool ret;
- assert(crtc);
+ assert(crtc != NULL);
+ assert(to_sna_crtc(crtc) != NULL);
assert(to_sna_crtc(crtc)->bo != NULL);
assert(pixmap == sna->front);
@@ -3930,7 +3958,7 @@ void sna_mode_redisplay(struct sna *sna)
struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
RegionRec damage;
- if (!sna_crtc->shadow)
+ if (sna_crtc == NULL || !sna_crtc->shadow)
continue;
assert(crtc->enabled);
@@ -3953,7 +3981,9 @@ void sna_mode_redisplay(struct sna *sna)
struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
RegionRec damage;
- if (!sna_crtc->shadow || sna_crtc->bo == sna->mode.shadow)
+ if (sna_crtc == NULL ||
+ !sna_crtc->shadow ||
+ sna_crtc->bo == sna->mode.shadow)
continue;
assert(crtc->enabled);
@@ -3987,8 +4017,8 @@ void sna_mode_redisplay(struct sna *sna)
struct drm_mode_crtc_page_flip arg;
DBG(("%s: crtc %d [%d, pipe=%d] active? %d\n",
- __FUNCTION__, i, crtc->id, crtc->pipe, crtc->bo != NULL));
- if (crtc->bo != old)
+ __FUNCTION__, i, crtc->id, crtc->pipe, crtc && crtc->bo));
+ if (crtc == NULL || crtc->bo != old)
continue;
assert(config->crtc[i]->enabled);
diff --git a/src/sna/sna_display_fake.c b/src/sna/sna_display_fake.c
index 6231eb52..afd5588f 100644
--- a/src/sna/sna_display_fake.c
+++ b/src/sna/sna_display_fake.c
@@ -143,7 +143,7 @@ sna_output_dpms(xf86OutputPtr output, int dpms)
static xf86OutputStatus
sna_output_detect(xf86OutputPtr output)
{
- return XF86OutputStatusDisconnected;
+ return XF86OutputStatusUnknown;
}
static Bool
@@ -178,12 +178,15 @@ static const xf86OutputFuncsRec sna_output_funcs = {
};
static bool
-sna_output_fake(struct sna *sna)
+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];
- output = xf86OutputCreate(scrn, &sna_output_funcs, "FAKE");
+ sprintf(buf, "VIRTUAL%d", n+1);
+ output = xf86OutputCreate(scrn, &sna_output_funcs, buf);
if (!output)
return false;
@@ -192,8 +195,9 @@ sna_output_fake(struct sna *sna)
output->subpixel_order = SubPixelNone;
- output->possible_crtcs = 1;
- output->possible_clones = 0;
+ mask = (1 << num_fake) - 1;
+ output->possible_crtcs = mask << num_real_crtc;
+ output->possible_clones = mask << num_real_output;
output->interlaceAllowed = FALSE;
return true;
@@ -241,8 +245,28 @@ static const xf86CrtcConfigFuncsRec sna_mode_funcs = {
sna_mode_resize
};
-bool sna_mode_fake_init(struct sna *sna)
+bool sna_mode_fake_init(struct sna *sna, int num_fake)
{
- xf86CrtcConfigInit(sna->scrn, &sna_mode_funcs);
- return sna_crtc_fake(sna) && sna_output_fake(sna);
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(sna->scrn);
+ int n, num_real_crtc, num_real_output;
+
+ if (num_fake == 0)
+ return true;
+
+ num_real_crtc = xf86_config->num_crtc;
+ num_real_output = xf86_config->num_output;
+
+ if (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;
}