summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Packard <keithp@neko.keithp.com>2006-11-16 21:09:23 -0800
committerKeith Packard <keithp@neko.keithp.com>2006-11-16 21:09:23 -0800
commitc4508c1cadf323e9ef1d0e69dd77d5e841a6a978 (patch)
tree61e788425ab287988a5eea19c124aaa6cdaf618a
parent45a27f80e1c783627f570c309e7a853dcc9af0c1 (diff)
RandR-based initial output configuration.
Using pre-init computed RandR information, make reasonable default choices for the output configuration at startup time. Either some preferred size or a size which yields 96dpi is chosen, from which other monitors are set to a similar size. The largest size sets the screen size. This needs to be extended to respect config file settings, but those have not been defined yet.
-rw-r--r--src/i830.h3
-rw-r--r--src/i830_display.c2
-rw-r--r--src/i830_display.h2
-rw-r--r--src/i830_driver.c25
-rw-r--r--src/i830_modes.c4
-rw-r--r--src/i830_randr.c377
6 files changed, 387 insertions, 26 deletions
diff --git a/src/i830.h b/src/i830.h
index 96f0c29c..f22be408 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -283,6 +283,7 @@ typedef struct _I830PipeRec {
Bool cursorInRange;
Bool cursorShown;
DisplayModeRec curMode;
+ DisplayModeRec desiredMode;
#ifdef RANDR_12_INTERFACE
RRCrtcPtr randr_crtc;
#endif
@@ -673,6 +674,8 @@ DisplayModePtr i830GetGTF(int h_pixels, int v_lines, float freq,
/* i830_modes.c */
int I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time);
void i830_reprobe_output_modes(ScrnInfoPtr pScrn);
+void i830_set_xf86_modes_from_outputs(ScrnInfoPtr pScrn);
+void i830_set_default_screen_size(ScrnInfoPtr pScrn);
DisplayModePtr i830_ddc_get_modes(ScrnInfoPtr pScrn, I830OutputPtr output);
/* i830_randr.c */
diff --git a/src/i830_display.c b/src/i830_display.c
index a0809eb0..bd40e4ee 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -290,7 +290,7 @@ i830PipeSetBase(ScrnInfoPtr pScrn, int pipe, int x, int y)
* - Closer in size to the requested mode, but no larger
* - Closer in refresh rate to the requested mode.
*/
-static DisplayModePtr
+DisplayModePtr
i830PipeFindClosestMode(ScrnInfoPtr pScrn, int pipe, DisplayModePtr pMode)
{
I830Ptr pI830 = I830PTR(pScrn);
diff --git a/src/i830_display.h b/src/i830_display.h
index 67f3c7b8..361a3c67 100644
--- a/src/i830_display.h
+++ b/src/i830_display.h
@@ -26,6 +26,8 @@
*/
/* i830_display.c */
+DisplayModePtr
+i830PipeFindClosestMode(ScrnInfoPtr pScrn, int pipe, DisplayModePtr pMode);
Bool i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe,
Bool plane_enable);
void i830DisableUnusedFunctions(ScrnInfoPtr pScrn);
diff --git a/src/i830_driver.c b/src/i830_driver.c
index 0ea20e4c..5da47424 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -3304,12 +3304,33 @@ I830EnterVT(int scrnIndex, int flags)
ResetState(pScrn, FALSE);
SetHWOperatingState(pScrn);
- /* Mark that we'll need to re-set the mode for sure */
for (i = 0; i < pI830->num_pipes; i++)
- memset(&pI830->pipes[i].curMode, 0, sizeof(pI830->pipes[i].curMode));
+ {
+ I830PipePtr pipe = &pI830->pipes[i];
+ /* Mark that we'll need to re-set the mode for sure */
+ memset(&pipe->curMode, 0, sizeof(pipe->curMode));
+ if (!pipe->desiredMode.CrtcHDisplay)
+ {
+ pipe->desiredMode = *i830PipeFindClosestMode (pScrn, i,
+ pScrn->currentMode);
+ }
+ if (!i830PipeSetMode (pScrn, &pipe->desiredMode, i, TRUE))
+ return FALSE;
+ i830PipeSetBase(pScrn, i, pipe->x, pipe->y);
+ }
+
+ i830DisableUnusedFunctions(pScrn);
+
+ i830DescribeOutputConfiguration(pScrn);
+#ifdef XF86DRI
+ I830DRISetVBlankInterrupt (pScrn, TRUE);
+#endif
+
+#if 0
if (!i830SetMode(pScrn, pScrn->currentMode))
return FALSE;
+#endif
#ifdef I830_XV
I830VideoSwitchModeAfter(pScrn, pScrn->currentMode);
diff --git a/src/i830_modes.c b/src/i830_modes.c
index 77db66cf..7fdd40ed 100644
--- a/src/i830_modes.c
+++ b/src/i830_modes.c
@@ -490,7 +490,7 @@ i830_reprobe_output_modes(ScrnInfoPtr pScrn)
*
* This should be obsoleted by RandR 1.2 hopefully.
*/
-static void
+void
i830_set_xf86_modes_from_outputs(ScrnInfoPtr pScrn)
{
I830Ptr pI830 = I830PTR(pScrn);
@@ -557,7 +557,7 @@ i830_set_xf86_modes_from_outputs(ScrnInfoPtr pScrn)
* Takes the output mode lists and decides the default root window size
* and framebuffer pitch.
*/
-static void
+void
i830_set_default_screen_size(ScrnInfoPtr pScrn)
{
I830Ptr pI830 = I830PTR(pScrn);
diff --git a/src/i830_randr.c b/src/i830_randr.c
index f579f411..e01ac1e1 100644
--- a/src/i830_randr.c
+++ b/src/i830_randr.c
@@ -609,6 +609,7 @@ I830RandRCrtcSet (ScreenPtr pScreen,
}
return FALSE;
}
+ pI830Pipe->desiredMode = *display_mode;
i830PipeSetBase(pScrn, pipe, x, y);
}
randrp->modes[pipe] = display_mode;
@@ -840,11 +841,6 @@ I830RandRCreateObjects12 (ScrnInfoPtr pScrn)
return FALSE;
output->randr_output = randr_output;
}
- /*
- * Configure output modes
- */
- if (!I830RandRSetInfo12 (pScrn))
- return FALSE;
return TRUE;
}
@@ -855,7 +851,7 @@ I830RandRCreateScreenResources12 (ScreenPtr pScreen)
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
I830Ptr pI830 = I830PTR(pScrn);
int p, o;
- DisplayModePtr mode;
+ int width, height;
/*
* Attach RandR objects to screen
@@ -868,33 +864,43 @@ I830RandRCreateScreenResources12 (ScreenPtr pScreen)
if (!RROutputAttachScreen (pI830->output[o].randr_output, pScreen))
return FALSE;
- mode = pScrn->currentMode;
- if (mode)
+ /*
+ * Compute width of screen
+ */
+ width = 0; height = 0;
+ for (p = 0; p < pI830->num_pipes; p++)
+ {
+ I830PipePtr pipe = &pI830->pipes[p];
+ int pipe_width = pipe->x + pipe->curMode.HDisplay;
+ int pipe_height = pipe->y + pipe->curMode.VDisplay;
+ if (pipe->enabled && pipe_width > width)
+ width = pipe_width;
+ if (pipe->enabled && pipe_height > height)
+ height = pipe_height;
+ }
+
+ if (width && height)
{
int mmWidth, mmHeight;
mmWidth = pScreen->mmWidth;
mmHeight = pScreen->mmHeight;
- if (mode->HDisplay != pScreen->width)
- mmWidth = mmWidth * mode->HDisplay / pScreen->width;
- if (mode->VDisplay != pScreen->height)
- mmHeight = mmHeight * mode->VDisplay / pScreen->height;
+ if (width != pScreen->width)
+ mmWidth = mmWidth * width / pScreen->width;
+ if (height != pScreen->height)
+ mmHeight = mmHeight * height / pScreen->height;
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"Setting screen physical size to %d x %d\n",
mmWidth, mmHeight);
I830RandRScreenSetSize (pScreen,
- mode->HDisplay,
- mode->VDisplay,
+ width,
+ height,
mmWidth,
mmHeight);
}
for (p = 0; p < pI830->num_pipes; p++)
- {
- i830PipeSetBase(pScrn, p, 0, 0);
I830RandRCrtcNotify (pI830->pipes[p].randr_crtc);
- }
-
if (randrp->virtualX == -1 || randrp->virtualY == -1)
{
@@ -926,19 +932,348 @@ I830RandRInit12 (ScreenPtr pScreen)
pScrn->PointerMoved = I830RandRPointerMoved;
return TRUE;
}
+
+static RRModePtr
+I830RRDefaultMode (RROutputPtr output)
+{
+ RRModePtr target_mode = NULL;
+ int target_diff = 0;
+ int mmHeight;
+ int num_modes;
+ int m;
+
+ num_modes = output->numPreferred ? output->numPreferred : output->numModes;
+ mmHeight = output->mmHeight;
+ if (!mmHeight)
+ mmHeight = 203; /* 768 pixels at 96dpi */
+ /*
+ * Pick a mode closest to 96dpi
+ */
+ for (m = 0; m < num_modes; m++)
+ {
+ RRModePtr mode = output->modes[m];
+ int dpi;
+ int diff;
+
+ dpi = (mode->mode.height * 254) / (mmHeight * 10);
+ diff = dpi - 96;
+ diff = diff < 0 ? -diff : diff;
+ if (target_mode == NULL || diff < target_diff)
+ {
+ target_mode = mode;
+ target_diff = diff;
+ }
+ }
+ return target_mode;
+}
+
+static RRModePtr
+I830ClosestMode (RROutputPtr output, RRModePtr match)
+{
+ RRModePtr target_mode = NULL;
+ int target_diff = 0;
+ int m;
+
+ /*
+ * Pick a mode closest to the specified mode
+ */
+ for (m = 0; m < output->numModes; m++)
+ {
+ RRModePtr mode = output->modes[m];
+ int dx, dy;
+ int diff;
+
+ /* exact matches are preferred */
+ if (mode == match)
+ return mode;
+
+ dx = match->mode.width - mode->mode.width;
+ dy = match->mode.height - mode->mode.height;
+ diff = dx * dx + dy * dy;
+ if (target_mode == NULL || diff < target_diff)
+ {
+ target_mode = mode;
+ target_diff = diff;
+ }
+ }
+ return target_mode;
+}
+
+static int
+I830RRPickCrtcs (RROutputPtr *outputs,
+ RRCrtcPtr *best_crtcs,
+ RRModePtr *modes,
+ int num_outputs,
+ int n)
+{
+ int c, o, l;
+ RROutputPtr output;
+ RRCrtcPtr crtc;
+ RRCrtcPtr *crtcs;
+ RRCrtcPtr best_crtc;
+ int best_score;
+ int score;
+ int my_score;
+
+ if (n == num_outputs)
+ return 0;
+ output = outputs[n];
+
+ /*
+ * Compute score with this output disabled
+ */
+ best_crtcs[n] = NULL;
+ best_crtc = NULL;
+ best_score = I830RRPickCrtcs (outputs, best_crtcs, modes, num_outputs, n+1);
+ if (modes[n] == NULL)
+ return best_score;
+
+ crtcs = xalloc (num_outputs * sizeof (RRCrtcPtr));
+ if (!crtcs)
+ return best_score;
+
+ my_score = 1;
+ /* Score outputs that are known to be connected higher */
+ if (output->connection == RR_Connected)
+ my_score++;
+ /* Score outputs with preferred modes higher */
+ if (output->numPreferred)
+ my_score++;
+ /*
+ * Select a crtc for this output and
+ * then attempt to configure the remaining
+ * outputs
+ */
+ for (c = 0; c < output->numCrtcs; c++)
+ {
+ crtc = output->crtcs[c];
+ /*
+ * Check to see if some other output is
+ * using this crtc
+ */
+ for (o = 0; o < n; o++)
+ if (best_crtcs[o] == crtc)
+ break;
+ if (o < n)
+ {
+ /*
+ * If the two outputs desire the same mode,
+ * see if they can be cloned
+ */
+ if (modes[o] == modes[n])
+ {
+ for (l = 0; l < output->numClones; l++)
+ if (output->clones[l] == outputs[o])
+ break;
+ if (l == output->numClones)
+ continue; /* nope, try next CRTC */
+ }
+ else
+ continue; /* different modes, can't clone */
+ }
+ crtcs[n] = crtc;
+ memcpy (crtcs, best_crtcs, n * sizeof (RRCrtcPtr));
+ score = my_score + I830RRPickCrtcs (outputs, crtcs, modes,
+ num_outputs, n+1);
+ if (score >= best_score)
+ {
+ best_crtc = crtc;
+ best_score = score;
+ memcpy (best_crtcs, crtcs, num_outputs * sizeof (RRCrtcPtr));
+ }
+ }
+ xfree (crtcs);
+ return best_score;
+}
+
+static Bool
+I830RRInitialConfiguration (RROutputPtr *outputs,
+ RRCrtcPtr *crtcs,
+ RRModePtr *modes,
+ int num_outputs)
+{
+ int o;
+ RRModePtr target_mode = NULL;
+
+ for (o = 0; o < num_outputs; o++)
+ modes[o] = NULL;
+
+ /*
+ * Let outputs with preferred modes drive screen size
+ */
+ for (o = 0; o < num_outputs; o++)
+ {
+ RROutputPtr output = outputs[o];
+
+ if (output->connection != RR_Disconnected && output->numPreferred)
+ {
+ target_mode = I830RRDefaultMode (output);
+ if (target_mode)
+ {
+ modes[o] = target_mode;
+ break;
+ }
+ }
+ }
+ if (!target_mode)
+ {
+ for (o = 0; o < num_outputs; o++)
+ {
+ RROutputPtr output = outputs[o];
+ if (output->connection != RR_Disconnected)
+ {
+ target_mode = I830RRDefaultMode (output);
+ if (target_mode)
+ {
+ modes[o] = target_mode;
+ break;
+ }
+ }
+ }
+ }
+ for (o = 0; o < num_outputs; o++)
+ {
+ RROutputPtr output = outputs[o];
+
+ if (output->connection != RR_Disconnected && !modes[o])
+ modes[o] = I830ClosestMode (output, target_mode);
+ }
+
+ if (!I830RRPickCrtcs (outputs, crtcs, modes, num_outputs, 0))
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Compute the virtual size necessary to place all of the available
+ * crtcs in a panorama configuration
+ */
+
+static void
+I830RRDefaultScreenLimits (RROutputPtr *outputs, int num_outputs,
+ RRCrtcPtr *crtcs, int num_crtc,
+ int *widthp, int *heightp)
+{
+ int width = 0, height = 0;
+ int o;
+ int c;
+ int m;
+ int s;
+
+ for (c = 0; c < num_crtc; c++)
+ {
+ RRCrtcPtr crtc = crtcs[c];
+ int crtc_width = 1600, crtc_height = 1200;
+
+ for (o = 0; o < num_outputs; o++)
+ {
+ RROutputPtr output = outputs[o];
+
+ for (s = 0; s < output->numCrtcs; s++)
+ if (output->crtcs[s] == crtc)
+ break;
+ if (s == output->numCrtcs)
+ continue;
+ for (m = 0; m < output->numModes; m++)
+ {
+ RRModePtr mode = output->modes[m];
+ if (mode->mode.width > crtc_width)
+ crtc_width = mode->mode.width;
+ if (mode->mode.height > crtc_width)
+ crtc_height = mode->mode.height;
+ }
+ }
+ width += crtc_width;
+ if (crtc_height > height)
+ height = crtc_height;
+ }
+ *widthp = width;
+ *heightp = height;
+}
+
#endif
Bool
I830RandRPreInit (ScrnInfoPtr pScrn)
{
- int n;
+ I830Ptr pI830 = I830PTR(pScrn);
+#if RANDR_12_INTERFACE
+ RROutputPtr outputs[MAX_OUTPUTS];
+ RRCrtcPtr output_crtcs[MAX_OUTPUTS];
+ RRModePtr output_modes[MAX_OUTPUTS];
+ RRCrtcPtr crtcs[MAX_DISPLAY_PIPES];
+ int width, height;
+ int o;
+ int c;
+#endif
- n = I830ValidateXF86ModeList(pScrn, TRUE);
- if (n <= 0)
+ if (pI830->num_outputs <= 0)
return FALSE;
+
+ i830_reprobe_output_modes(pScrn);
+
#if RANDR_12_INTERFACE
if (!I830RandRCreateObjects12 (pScrn))
return FALSE;
+
+ /*
+ * Configure output modes
+ */
+ if (!I830RandRSetInfo12 (pScrn))
+ return FALSE;
+ /*
+ * With RandR info set up, let RandR choose
+ * the initial configuration
+ */
+ for (o = 0; o < pI830->num_outputs; o++)
+ outputs[o] = pI830->output[o].randr_output;
+ for (c = 0; c < pI830->num_pipes; c++)
+ crtcs[c] = pI830->pipes[c].randr_crtc;
+
+ if (!I830RRInitialConfiguration (outputs, output_crtcs, output_modes,
+ pI830->num_outputs))
+ return FALSE;
+
+ I830RRDefaultScreenLimits (outputs, pI830->num_outputs,
+ crtcs, pI830->num_pipes,
+ &width, &height);
+
+ if (width > pScrn->virtualX)
+ pScrn->virtualX = width;
+ if (height > pScrn->virtualY)
+ pScrn->virtualY = height;
+
+ for (o = 0; o < pI830->num_outputs; o++)
+ {
+ RRModePtr randr_mode = output_modes[o];
+ DisplayModePtr mode;
+ RRCrtcPtr randr_crtc = output_crtcs[o];
+ int pipe;
+ Bool enabled;
+
+ if (randr_mode)
+ mode = (DisplayModePtr) randr_mode->devPrivate;
+ else
+ mode = NULL;
+ if (randr_crtc)
+ {
+ pipe = (int) randr_crtc->devPrivate;
+ enabled = TRUE;
+ }
+ else
+ {
+ pipe = 0;
+ enabled = FALSE;
+ }
+ pI830->pipes[pipe].desiredMode = *mode;
+ pI830->output[o].pipe = pipe;
+ pI830->output[o].enabled = enabled;
+ }
#endif
+ i830_set_xf86_modes_from_outputs (pScrn);
+
+ i830_set_default_screen_size(pScrn);
+
return TRUE;
}