xserver-multidpi/hw/xfree86/modes/xf86Crtc.c

3461 lines
103 KiB
C
Raw Normal View History

/*
* Copyright © 2006 Keith Packard
* Copyright © 2008 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifdef HAVE_XORG_CONFIG_H
#include <xorg-config.h>
#endif
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include "xf86.h"
#include "xf86DDC.h"
#include "xf86Crtc.h"
#include "xf86Modes.h"
2007-11-19 15:53:49 +01:00
#include "xf86Priv.h"
#include "xf86RandR12.h"
#include "X11/extensions/render.h"
#include "X11/extensions/dpmsconst.h"
#include "X11/Xatom.h"
#include "picturestr.h"
#ifdef XV
#include "xf86xv.h"
#endif
#define NO_OUTPUT_DEFAULT_WIDTH 1024
#define NO_OUTPUT_DEFAULT_HEIGHT 768
/*
* Initialize xf86CrtcConfig structure
*/
int xf86CrtcConfigPrivateIndex = -1;
void
xf86CrtcConfigInit(ScrnInfoPtr scrn, const xf86CrtcConfigFuncsRec * funcs)
{
xf86CrtcConfigPtr config;
if (xf86CrtcConfigPrivateIndex == -1)
xf86CrtcConfigPrivateIndex = xf86AllocateScrnInfoPrivateIndex();
config = xnfcalloc(1, sizeof(xf86CrtcConfigRec));
config->funcs = funcs;
config->compat_output = -1;
scrn->privates[xf86CrtcConfigPrivateIndex].ptr = config;
}
void
xf86CrtcSetSizeRange(ScrnInfoPtr scrn,
int minWidth, int minHeight, int maxWidth, int maxHeight)
{
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
config->minWidth = minWidth;
config->minHeight = minHeight;
config->maxWidth = maxWidth;
config->maxHeight = maxHeight;
}
/*
* Crtc functions
*/
xf86CrtcPtr
xf86CrtcCreate(ScrnInfoPtr scrn, const xf86CrtcFuncsRec * funcs)
{
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
xf86CrtcPtr crtc, *crtcs;
crtc = calloc(sizeof(xf86CrtcRec), 1);
if (!crtc)
return NULL;
crtc->version = XF86_CRTC_VERSION;
crtc->scrn = scrn;
crtc->funcs = funcs;
#ifdef RANDR_12_INTERFACE
crtc->randr_crtc = NULL;
#endif
crtc->rotation = RR_Rotate_0;
crtc->desiredRotation = RR_Rotate_0;
pixman_transform_init_identity(&crtc->crtc_to_framebuffer);
pixman_f_transform_init_identity(&crtc->f_crtc_to_framebuffer);
pixman_f_transform_init_identity(&crtc->f_framebuffer_to_crtc);
crtc->filter = NULL;
crtc->params = NULL;
crtc->nparams = 0;
crtc->filter_width = 0;
crtc->filter_height = 0;
crtc->transform_in_use = FALSE;
crtc->transformPresent = FALSE;
crtc->desiredTransformPresent = FALSE;
memset(&crtc->bounds, '\0', sizeof(crtc->bounds));
/* Preallocate gamma at a sensible size. */
crtc->gamma_size = 256;
crtc->gamma_red = xallocarray(crtc->gamma_size, 3 * sizeof(CARD16));
2008-12-18 16:11:21 +01:00
if (!crtc->gamma_red) {
free(crtc);
return NULL;
2008-12-18 16:11:21 +01:00
}
crtc->gamma_green = crtc->gamma_red + crtc->gamma_size;
crtc->gamma_blue = crtc->gamma_green + crtc->gamma_size;
if (xf86_config->crtc)
crtcs = reallocarray(xf86_config->crtc,
xf86_config->num_crtc + 1, sizeof(xf86CrtcPtr));
else
crtcs = xallocarray(xf86_config->num_crtc + 1, sizeof(xf86CrtcPtr));
if (!crtcs) {
free(crtc->gamma_red);
free(crtc);
return NULL;
}
xf86_config->crtc = crtcs;
xf86_config->crtc[xf86_config->num_crtc++] = crtc;
return crtc;
}
void
xf86CrtcDestroy(xf86CrtcPtr crtc)
{
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
int c;
(*crtc->funcs->destroy) (crtc);
for (c = 0; c < xf86_config->num_crtc; c++)
if (xf86_config->crtc[c] == crtc) {
memmove(&xf86_config->crtc[c],
&xf86_config->crtc[c + 1],
((xf86_config->num_crtc - (c + 1)) * sizeof(void *)));
xf86_config->num_crtc--;
break;
}
free(crtc->params);
free(crtc->gamma_red);
free(crtc);
}
/**
* Return whether any outputs are connected to the specified pipe
*/
Bool
xf86CrtcInUse(xf86CrtcPtr crtc)
{
ScrnInfoPtr pScrn = crtc->scrn;
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
int o;
for (o = 0; o < xf86_config->num_output; o++)
if (xf86_config->output[o]->crtc == crtc)
return TRUE;
return FALSE;
}
void
xf86CrtcSetScreenSubpixelOrder(ScreenPtr pScreen)
{
int subpixel_order = SubPixelUnknown;
Bool has_none = FALSE;
ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
int icrtc, o;
for (icrtc = 0; icrtc < xf86_config->num_crtc; icrtc++) {
xf86CrtcPtr crtc = xf86_config->crtc[icrtc];
for (o = 0; o < xf86_config->num_output; o++) {
xf86OutputPtr output = xf86_config->output[o];
if (output->crtc == crtc) {
switch (output->subpixel_order) {
case SubPixelNone:
has_none = TRUE;
break;
case SubPixelUnknown:
break;
default:
subpixel_order = output->subpixel_order;
break;
}
}
if (subpixel_order != SubPixelUnknown)
break;
}
if (subpixel_order != SubPixelUnknown) {
static const int circle[4] = {
SubPixelHorizontalRGB,
SubPixelVerticalRGB,
SubPixelHorizontalBGR,
SubPixelVerticalBGR,
};
int rotate;
int sc;
for (rotate = 0; rotate < 4; rotate++)
if (crtc->rotation & (1 << rotate))
break;
for (sc = 0; sc < 4; sc++)
if (circle[sc] == subpixel_order)
break;
sc = (sc + rotate) & 0x3;
if ((crtc->rotation & RR_Reflect_X) && !(sc & 1))
sc ^= 2;
if ((crtc->rotation & RR_Reflect_Y) && (sc & 1))
sc ^= 2;
subpixel_order = circle[sc];
break;
}
}
if (subpixel_order == SubPixelUnknown && has_none)
subpixel_order = SubPixelNone;
PictureSetSubpixelOrder(pScreen, subpixel_order);
}
/**
* Sets the given video mode on the given crtc
*/
Bool
xf86CrtcSetModeTransform(xf86CrtcPtr crtc, DisplayModePtr mode,
Rotation rotation, RRTransformPtr transform, int x,
int y)
{
ScrnInfoPtr scrn = crtc->scrn;
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
int i;
Bool ret = FALSE;
Bool didLock = FALSE;
DisplayModePtr adjusted_mode;
DisplayModeRec saved_mode;
int saved_x, saved_y;
Rotation saved_rotation;
RRTransformRec saved_transform;
Bool saved_transform_present;
crtc->enabled = xf86CrtcInUse(crtc);
/* We only hit this if someone explicitly sends a "disabled" modeset. */
if (!crtc->enabled) {
/* Check everything for stuff that should be off. */
xf86DisableUnusedFunctions(scrn);
return TRUE;
}
adjusted_mode = xf86DuplicateMode(mode);
saved_mode = crtc->mode;
saved_x = crtc->x;
saved_y = crtc->y;
saved_rotation = crtc->rotation;
if (crtc->transformPresent) {
RRTransformInit(&saved_transform);
RRTransformCopy(&saved_transform, &crtc->transform);
}
saved_transform_present = crtc->transformPresent;
/* Update crtc values up front so the driver can rely on them for mode
* setting.
*/
crtc->mode = *mode;
crtc->x = x;
crtc->y = y;
crtc->rotation = rotation;
if (transform) {
RRTransformCopy(&crtc->transform, transform);
crtc->transformPresent = TRUE;
}
else
crtc->transformPresent = FALSE;
if (crtc->funcs->set_mode_major) {
ret = crtc->funcs->set_mode_major(crtc, mode, rotation, x, y);
goto done;
}
didLock = crtc->funcs->lock(crtc);
/* Pass our mode to the outputs and the CRTC to give them a chance to
* adjust it according to limitations or output properties, and also
* a chance to reject the mode entirely.
*/
for (i = 0; i < xf86_config->num_output; i++) {
xf86OutputPtr output = xf86_config->output[i];
if (output->crtc != crtc)
continue;
if (!output->funcs->mode_fixup(output, mode, adjusted_mode)) {
goto done;
}
}
if (!crtc->funcs->mode_fixup(crtc, mode, adjusted_mode)) {
goto done;
}
if (!xf86CrtcRotate(crtc))
goto done;
2007-02-25 23:40:00 +01:00
/* Prepare the outputs and CRTCs before setting the mode. */
for (i = 0; i < xf86_config->num_output; i++) {
xf86OutputPtr output = xf86_config->output[i];
if (output->crtc != crtc)
continue;
/* Disable the output as the first thing we do. */
output->funcs->prepare(output);
}
2007-02-25 23:40:00 +01:00
crtc->funcs->prepare(crtc);
/* Set up the DPLL and any output state that needs to adjust or depend
* on the DPLL.
*/
crtc->funcs->mode_set(crtc, mode, adjusted_mode, crtc->x, crtc->y);
for (i = 0; i < xf86_config->num_output; i++) {
xf86OutputPtr output = xf86_config->output[i];
if (output->crtc == crtc)
output->funcs->mode_set(output, mode, adjusted_mode);
}
/* Only upload when needed, to avoid unneeded delays. */
if (!crtc->active && crtc->funcs->gamma_set)
crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
crtc->gamma_blue, crtc->gamma_size);
/* Now, enable the clocks, plane, pipe, and outputs that we set up. */
2007-02-25 23:40:00 +01:00
crtc->funcs->commit(crtc);
for (i = 0; i < xf86_config->num_output; i++) {
xf86OutputPtr output = xf86_config->output[i];
if (output->crtc == crtc)
output->funcs->commit(output);
}
ret = TRUE;
done:
if (ret) {
crtc->active = TRUE;
if (scrn->pScreen)
xf86CrtcSetScreenSubpixelOrder(scrn->pScreen);
if (scrn->ModeSet)
scrn->ModeSet(scrn);
/* Make sure the HW cursor is hidden if it's supposed to be, in case
* it was hidden while the CRTC was disabled
*/
if (!xf86_config->cursor_on)
xf86_hide_cursors(scrn);
}
else {
crtc->x = saved_x;
crtc->y = saved_y;
crtc->rotation = saved_rotation;
crtc->mode = saved_mode;
if (saved_transform_present)
RRTransformCopy(&crtc->transform, &saved_transform);
crtc->transformPresent = saved_transform_present;
}
free((void *) adjusted_mode->name);
free(adjusted_mode);
if (didLock)
crtc->funcs->unlock(crtc);
return ret;
}
/**
* Sets the given video mode on the given crtc, but without providing
* a transform
*/
Bool
xf86CrtcSetMode(xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation,
int x, int y)
{
return xf86CrtcSetModeTransform(crtc, mode, rotation, NULL, x, y);
}
2008-11-28 17:49:31 +01:00
/**
* Pans the screen, does not change the mode
*/
void
xf86CrtcSetOrigin(xf86CrtcPtr crtc, int x, int y)
2008-11-28 17:49:31 +01:00
{
ScrnInfoPtr scrn = crtc->scrn;
crtc->x = x;
crtc->y = y;
if (crtc->funcs->set_origin) {
if (!xf86CrtcRotate(crtc))
return;
crtc->funcs->set_origin(crtc, x, y);
if (scrn->ModeSet)
scrn->ModeSet(scrn);
}
else
xf86CrtcSetMode(crtc, &crtc->mode, crtc->rotation, x, y);
2008-11-28 17:49:31 +01:00
}
/*
* Output functions
*/
extern XF86ConfigPtr xf86configptr;
typedef enum {
OPTION_PREFERRED_MODE,
OPTION_ZOOM_MODES,
OPTION_POSITION,
OPTION_BELOW,
OPTION_RIGHT_OF,
OPTION_ABOVE,
OPTION_LEFT_OF,
OPTION_ENABLE,
OPTION_DISABLE,
OPTION_MIN_CLOCK,
OPTION_MAX_CLOCK,
OPTION_IGNORE,
OPTION_ROTATE,
OPTION_PANNING,
OPTION_PRIMARY,
OPTION_DEFAULT_MODES,
} OutputOpts;
static OptionInfoRec xf86OutputOptions[] = {
{OPTION_PREFERRED_MODE, "PreferredMode", OPTV_STRING, {0}, FALSE},
{OPTION_ZOOM_MODES, "ZoomModes", OPTV_STRING, {0}, FALSE },
{OPTION_POSITION, "Position", OPTV_STRING, {0}, FALSE},
{OPTION_BELOW, "Below", OPTV_STRING, {0}, FALSE},
{OPTION_RIGHT_OF, "RightOf", OPTV_STRING, {0}, FALSE},
{OPTION_ABOVE, "Above", OPTV_STRING, {0}, FALSE},
{OPTION_LEFT_OF, "LeftOf", OPTV_STRING, {0}, FALSE},
{OPTION_ENABLE, "Enable", OPTV_BOOLEAN, {0}, FALSE},
{OPTION_DISABLE, "Disable", OPTV_BOOLEAN, {0}, FALSE},
{OPTION_MIN_CLOCK, "MinClock", OPTV_FREQ, {0}, FALSE},
{OPTION_MAX_CLOCK, "MaxClock", OPTV_FREQ, {0}, FALSE},
{OPTION_IGNORE, "Ignore", OPTV_BOOLEAN, {0}, FALSE},
{OPTION_ROTATE, "Rotate", OPTV_STRING, {0}, FALSE},
{OPTION_PANNING, "Panning", OPTV_STRING, {0}, FALSE},
{OPTION_PRIMARY, "Primary", OPTV_BOOLEAN, {0}, FALSE},
{OPTION_DEFAULT_MODES, "DefaultModes", OPTV_BOOLEAN, {0}, FALSE},
{-1, NULL, OPTV_NONE, {0}, FALSE},
};
enum {
OPTION_MODEDEBUG,
};
static OptionInfoRec xf86DeviceOptions[] = {
{OPTION_MODEDEBUG, "ModeDebug", OPTV_BOOLEAN, {0}, FALSE},
{-1, NULL, OPTV_NONE, {0}, FALSE},
};
static void
xf86OutputSetMonitor(xf86OutputPtr output)
{
char *option_name;
const char *monitor;
if (!output->name)
return;
free(output->options);
output->options = xnfalloc(sizeof(xf86OutputOptions));
memcpy(output->options, xf86OutputOptions, sizeof(xf86OutputOptions));
XNFasprintf(&option_name, "monitor-%s", output->name);
monitor = xf86findOptionValue(output->scrn->options, option_name);
if (!monitor)
monitor = output->name;
else
xf86MarkOptionUsedByName(output->scrn->options, option_name);
free(option_name);
output->conf_monitor = xf86findMonitor(monitor,
xf86configptr->conf_monitor_lst);
/*
* Find the monitor section of the screen and use that
*/
if (!output->conf_monitor && output->use_screen_monitor)
output->conf_monitor = xf86findMonitor(output->scrn->monitor->id,
xf86configptr->conf_monitor_lst);
if (output->conf_monitor) {
xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
"Output %s using monitor section %s\n",
output->name, output->conf_monitor->mon_identifier);
xf86ProcessOptions(output->scrn->scrnIndex,
output->conf_monitor->mon_option_lst,
output->options);
}
else
xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
"Output %s has no monitor section\n", output->name);
}
static Bool
xf86OutputEnabled(xf86OutputPtr output, Bool strict)
{
Bool enable, disable;
/* check to see if this output was enabled in the config file */
if (xf86GetOptValBool(output->options, OPTION_ENABLE, &enable) && enable) {
xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
"Output %s enabled by config file\n", output->name);
return TRUE;
}
/* or if this output was disabled in the config file */
if (xf86GetOptValBool(output->options, OPTION_DISABLE, &disable) && disable) {
xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
"Output %s disabled by config file\n", output->name);
return FALSE;
}
/* If not, try to only light up the ones we know are connected */
if (strict) {
enable = output->status == XF86OutputStatusConnected;
}
/* But if that fails, try to light up even outputs we're unsure of */
else {
enable = output->status != XF86OutputStatusDisconnected;
}
xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
"Output %s %sconnected\n", output->name, enable ? "" : "dis");
return enable;
}
static Bool
xf86OutputIgnored(xf86OutputPtr output)
{
return xf86ReturnOptValBool(output->options, OPTION_IGNORE, FALSE);
}
static const char *direction[4] = {
"normal",
"left",
"inverted",
"right"
};
static Rotation
xf86OutputInitialRotation(xf86OutputPtr output)
{
const char *rotate_name = xf86GetOptValString(output->options,
OPTION_ROTATE);
int i;
if (!rotate_name) {
if (output->initial_rotation)
return output->initial_rotation;
return RR_Rotate_0;
}
for (i = 0; i < 4; i++)
if (xf86nameCompare(direction[i], rotate_name) == 0)
return 1 << i;
return RR_Rotate_0;
}
xf86OutputPtr
xf86OutputCreate(ScrnInfoPtr scrn,
const xf86OutputFuncsRec * funcs, const char *name)
{
xf86OutputPtr output, *outputs;
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
int len;
Bool primary;
if (name)
len = strlen(name) + 1;
else
len = 0;
output = calloc(sizeof(xf86OutputRec) + len, 1);
if (!output)
return NULL;
output->scrn = scrn;
output->funcs = funcs;
if (name) {
output->name = (char *) (output + 1);
strcpy(output->name, name);
}
output->subpixel_order = SubPixelUnknown;
/*
* Use the old per-screen monitor section for the first output
*/
output->use_screen_monitor = (xf86_config->num_output == 0);
#ifdef RANDR_12_INTERFACE
output->randr_output = NULL;
#endif
if (name) {
xf86OutputSetMonitor(output);
if (xf86OutputIgnored(output)) {
free(output);
return FALSE;
}
}
if (xf86_config->output)
outputs = reallocarray(xf86_config->output,
xf86_config->num_output + 1,
sizeof(xf86OutputPtr));
else
outputs = xallocarray(xf86_config->num_output + 1,
sizeof(xf86OutputPtr));
if (!outputs) {
free(output);
return NULL;
}
xf86_config->output = outputs;
if (xf86GetOptValBool(output->options, OPTION_PRIMARY, &primary) && primary) {
memmove(xf86_config->output + 1, xf86_config->output,
xf86_config->num_output * sizeof(xf86OutputPtr));
xf86_config->output[0] = output;
}
else {
xf86_config->output[xf86_config->num_output] = output;
}
xf86_config->num_output++;
return output;
}
Bool
xf86OutputRename(xf86OutputPtr output, const char *name)
{
char *newname = strdup(name);
if (!newname)
return FALSE; /* so sorry... */
if (output->name && output->name != (char *) (output + 1))
free(output->name);
output->name = newname;
xf86OutputSetMonitor(output);
if (xf86OutputIgnored(output))
return FALSE;
return TRUE;
}
void
xf86OutputUseScreenMonitor(xf86OutputPtr output, Bool use_screen_monitor)
{
if (use_screen_monitor != output->use_screen_monitor) {
output->use_screen_monitor = use_screen_monitor;
xf86OutputSetMonitor(output);
}
}
void
xf86OutputDestroy(xf86OutputPtr output)
{
ScrnInfoPtr scrn = output->scrn;
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
int o;
(*output->funcs->destroy) (output);
while (output->probed_modes)
xf86DeleteMode(&output->probed_modes, output->probed_modes);
for (o = 0; o < xf86_config->num_output; o++)
if (xf86_config->output[o] == output) {
memmove(&xf86_config->output[o],
&xf86_config->output[o + 1],
((xf86_config->num_output - (o + 1)) * sizeof(void *)));
xf86_config->num_output--;
break;
}
if (output->name && output->name != (char *) (output + 1))
free(output->name);
free(output);
}
/*
* Called during CreateScreenResources to hook up RandR
*/
static Bool
xf86CrtcCreateScreenResources(ScreenPtr screen)
{
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
screen->CreateScreenResources = config->CreateScreenResources;
if (!(*screen->CreateScreenResources) (screen))
return FALSE;
if (!xf86RandR12CreateScreenResources(screen))
return FALSE;
return TRUE;
}
/*
* Clean up config on server reset
*/
static Bool
api: rework the X server driver API to avoid global arrays. This is a squash merge containing all the API changes, as well as the video ABI bump. Its been squashed to make bisection easier. Full patch log below: commit b202738bbf0c5a1c1172767119c2c71f1e7f8070 Author: Aaron Plattner <aplattner@nvidia.com> Date: Mon May 14 15:16:11 2012 -0700 xfree86: Bump video ABI to 13.0 The ABI was broken by changes to convert from screen index numbers to ScreenPtr / ScrnInfoPtr in various structures and function signatures. Signed-off-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Dave Airlie <airlied@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 3d5f7d9f8d408bcad3f83277d255f25d3b0edbf3 Author: Dave Airlie <airlied@redhat.com> Date: Thu May 24 10:56:57 2012 +0100 xf86: xf86ClearEntityListForScreen should take a pScrn When adding GPU screens this make life easier. (also fix comment, as pointed out by Alan) Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net> Signed-off-by: Dave Airlie <airlied@redhat.com> commit afee8b5ab4501597ecc1ade34124d7ca227ab055 Author: Dave Airlie <airlied@redhat.com> Date: Thu May 24 07:07:32 2012 +0100 xf86i2c: add pscrn for drivers to use This just adds a pScrn pointer into the struct for the drivers to use instead of scrnIndex. Mostly scrnIndex is used for logging, but some drivers use it to lookup xf86Screens, so let them stash a pScrn instead. Removing the scrnIndex is a bit more involved and I'm not sure its worth the effort. Doing i2c in the X server is legacy code as far as I'm concerned. Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit ea5092f1f679691d187f1eee9427e6057beec56e Author: Dave Airlie <airlied@redhat.com> Date: Wed May 23 19:25:20 2012 +0100 dix/gc: consolidate GC object creation in one place The standard GC create and scratch GC create were 90% the same really, and I have a need in the future for creating GC objects without the other bits, so wanted to avoid a third copy. Reviewed-by: Keith Packard <keithp@keithp.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 3d91482ea9b4883e64e496f2768168e0ffa21ba1 Author: Dave Airlie <airlied@redhat.com> Date: Wed May 23 10:24:06 2012 +0100 xf86: add a define to denote the new non-index interfaces are being used This can be used by drivers to provide compatible APIs. Reviewed-by: Keith Packard <keithp@keithp.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 37c3ae3e6cd4f3dedc72f371096d6743f8f99df3 Author: Dave Airlie <airlied@redhat.com> Date: Wed May 23 15:09:12 2012 +0100 dix: make Create/Free scratch pixmaps take a ScreenPtr While technically an API/ABI change I doubt anyone uses it, but it helps in splitting screens up. Reviewed-by: Keith Packard <keithp@keithp.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 75f2062a3fe94f04764ecc7d2ff2fbbeccb9da60 Author: Dave Airlie <airlied@redhat.com> Date: Wed May 23 14:57:55 2012 +0100 xf86/xv: remove scrnIndexfrom xf86FindXvOptions. Move this interface to taking an ScrnInfoPtr. Reviewed-by: Keith Packard <keithp@keithp.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit f80c2374f40ea7b2ee0556e2e76cc07406f3d843 Author: Dave Airlie <airlied@redhat.com> Date: Wed May 23 14:53:59 2012 +0100 xf86: make xf86DeleteScreen take a ScrnInfoPtr (v2) stop passing indices into this function. v2: drop flags argument. Reviewed-by: Keith Packard <keithp@keithp.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 58824e414f35682435f15bfe6c4b656bd90b9235 Author: Dave Airlie <airlied@redhat.com> Date: Wed May 23 14:48:09 2012 +0100 xf86: fix xf86IsScreenPrimary interface to take a pScrn (API/ABI) Reviewed-by: Keith Packard <keithp@keithp.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 6b4fc1f9d391bcdf7ca288766e49bce60f4635cd Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 14:18:59 2012 +0100 xserver: convert block/wakeup handlers to passing ScreenPtr (ABI/API) (v2) Instead of passing an index, pass the actual ScreenPtr. This allows more moving towards not abusing xf86Screens + screenInfo. v2: drop the blockData/wakeupData args as per ajax's suggestion., fix docs. Reviewed-by: Keith Packard <keithp@keithp.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 790d003de20fb47674420a24dadd92412d78620d Author: Dave Airlie <airlied@gmail.com> Date: Wed Apr 11 09:53:14 2012 +0100 xf86/common: remove some more pScrn->pScreen uses remove some more conversions that appeared after api cleanups. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit aac85e18d1dd093f2cad6bd29375e40bd7af0b8f Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 16:34:53 2012 +0100 ddc: change API to take ScrnInfoPtr (v2) This removes all xf86Screens usage from ddc code, it modifies the API for some functions to avoid taking indices. v2: address Alan's comments about dropping DDC2Init parameter. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit fe3f57b6eaf6860a33876a54f9439f69578f03a5 Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 16:31:26 2012 +0100 vbe: don't use index for VBEInterpretPanelID (API) Remove use of xf86screens from vbe module. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit abf1965f4ed91529036d3fdb470d6a3ce6f29675 Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 16:25:11 2012 +0100 int10/vbe: don't use xf86Screens. (ABI) (v3) Pass the ScrnInfoPtr instead of the index in the int10 struct. This saves us using it to dereference xf86Screens. v2: address Alan's comment to fix struct alignment. v3: squash in all the int10 fixes, test the vm86 code builds, after comments by Keith. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 23cca612b4fb5efc33683c7624b803b457387e3d Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 15:30:18 2012 +0100 xserver: drop index argument to ScreenInit (ABI/API) (v2) This drops the index argument, its the same as pScreen->myNum, and its the last major index abuse I can find. v2: address Alan's review - update docs, fix xwin/xnest/darwin Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 40d360e2d7e832407f3ed64e3a02c27ecc89a960 Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 15:23:01 2012 +0100 xf86: migrate PointerMoved from index to ScrnInfoPtr (ABI/API) This migrates PointerMoved from an index to ScrnInfoPtr. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit aa60a2f38679d0eeb979a9c2648c9bc771409bf9 Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 15:20:46 2012 +0100 xf86: migrate PMEvent to a ScrnInfoPtr (ABI/API) This migrates the PMEvent from index to ScrnInfoPtr. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit d3f28ef44371ed4a039ffc5dd7eb6408d1269ba2 Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 15:18:30 2012 +0100 xf86: migrate SetDGAMode from index to ScrnInfoPtr (ABI/API) This migrates the SetDGAMode callback from an index to ScrnInfoPtr. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit baf5e4818a74f2b68c3dfdcc56f54322351039a0 Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 15:14:11 2012 +0100 xf86: migrate ChangeGamma from index to ScrnInfoPtr (ABI/API) (v2) This migrates the ChangeGamma interface to avoid passing a index. v2: fix xf86RandR12.c + xf86cmap.c call Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 51e5f90ada929d6b23176090badbb42fdb3fa550 Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 15:11:09 2012 +0100 xf86/exa: migrate index to screen types for EnableDisableFBAccess (ABI/API) The EXA interface migrates to ScreenPtr, and the xf86 interface migrated to ScrnInfoPtr. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 94f1f21d17e86f96d4a54292a399160950087675 Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 15:02:11 2012 +0100 xf86: migrate ValidMode callback to ScrnInfoPtr (ABI/API) This migrates the ValidMode to passing a ScrnInfoPtr instead of an index. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 3f8f18198fed4f39ec805b508a3482e91eea26b2 Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 14:59:46 2012 +0100 xf86: migrate SwitchMode to taking ScrnInfoPtr (ABI/API) (v2) This migrate the SwitchMode interface to take a ScrnInfoPtr instead of an index. v2: drop flags. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit d06a038a5c49328ab3a8d969d24f9fcd22c63202 Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 14:50:37 2012 +0100 xf86: move AdjustFrame to passing ScrnInfoPtr (ABI/API) (v2) This converts AdjustFrame code paths to passing a ScrnInfoPtr instead of an integer index. v2: drop flags args. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 53d2f8608ffd4090d08e7d5cf2e92fb954959b90 Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 14:41:27 2012 +0100 xf86: modify FreeScreen callback to take pScrn instead of index. (ABI/API) (v2) Another index->pScrn conversion. v2: drop flags arg. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 60db37c0b247052e0f5c54b1921fe58a3609c2e3 Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 14:35:41 2012 +0100 xf86: change EnterVT/LeaveVT to take a ScrnInfoPtr (ABI/API break) (v2) This modifies the EnterVT/LeaveVT interfaces to take a ScrnInfoPtr instead of an index into xf86Screens. This allows dropping more public dereferences of the xf86Screens and screenInfo. v2: drop flags args as suggested by Keith, fix docs. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 06729dbbc804a20242e6499f446acb5d94023c3c Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 14:04:59 2012 +0100 xserver: remove index from CloseScreen (API/ABI breakage) This drops the index from the CloseScreen callback, its always been useless really, since the pScreen contains it. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
2012-06-05 14:22:18 +02:00
xf86CrtcCloseScreen(ScreenPtr screen)
{
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
int o, c;
screen->CloseScreen = config->CloseScreen;
xf86RotateCloseScreen(screen);
xf86RandR12CloseScreen(screen);
screen->CloseScreen(screen);
for (o = 0; o < config->num_output; o++) {
xf86OutputPtr output = config->output[o];
output->randr_output = NULL;
}
for (c = 0; c < config->num_crtc; c++) {
xf86CrtcPtr crtc = config->crtc[c];
crtc->randr_crtc = NULL;
}
/* detach any providers */
if (config->randr_provider) {
RRProviderDestroy(config->randr_provider);
config->randr_provider = NULL;
}
return TRUE;
}
/*
* Called at ScreenInit time to set up
*/
#ifdef RANDR_13_INTERFACE
int
#else
Bool
#endif
xf86CrtcScreenInit(ScreenPtr screen)
{
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
int c;
/* Rotation */
xf86DrvMsg(scrn->scrnIndex, X_INFO,
"RandR 1.2 enabled, ignore the following RandR disabled message.\n");
xf86DisableRandR(); /* Disable old RandR extension support */
xf86RandR12Init(screen);
/* support all rotations if every crtc has the shadow alloc funcs */
for (c = 0; c < config->num_crtc; c++) {
xf86CrtcPtr crtc = config->crtc[c];
if (!crtc->funcs->shadow_allocate || !crtc->funcs->shadow_create)
break;
}
if (c == config->num_crtc) {
xf86RandR12SetRotations(screen, RR_Rotate_0 | RR_Rotate_90 |
RR_Rotate_180 | RR_Rotate_270 |
RR_Reflect_X | RR_Reflect_Y);
xf86RandR12SetTransformSupport(screen, TRUE);
}
else {
xf86RandR12SetRotations(screen, RR_Rotate_0);
xf86RandR12SetTransformSupport(screen, FALSE);
}
/* Wrap CreateScreenResources so we can initialize the RandR code */
config->CreateScreenResources = screen->CreateScreenResources;
screen->CreateScreenResources = xf86CrtcCreateScreenResources;
config->CloseScreen = screen->CloseScreen;
screen->CloseScreen = xf86CrtcCloseScreen;
/* This might still be marked wrapped from a previous generation */
config->BlockHandler = NULL;
#ifdef XFreeXDGA
_xf86_di_dga_init_internal(screen);
#endif
#ifdef RANDR_13_INTERFACE
return RANDR_INTERFACE_VERSION;
#else
return TRUE;
#endif
}
static DisplayModePtr
xf86DefaultMode(xf86OutputPtr output, int width, int height)
{
DisplayModePtr target_mode = NULL;
DisplayModePtr mode;
int target_diff = 0;
int target_preferred = 0;
int mm_height;
mm_height = output->mm_height;
if (!mm_height)
mm_height = (768 * 25.4) / DEFAULT_DPI;
/*
* Pick a mode closest to DEFAULT_DPI
*/
for (mode = output->probed_modes; mode; mode = mode->next) {
int dpi;
int preferred = (((mode->type & M_T_PREFERRED) != 0) +
((mode->type & M_T_USERPREF) != 0));
int diff;
if (xf86ModeWidth(mode, output->initial_rotation) > width ||
xf86ModeHeight(mode, output->initial_rotation) > height)
continue;
/* yes, use VDisplay here, not xf86ModeHeight */
dpi = (mode->VDisplay * 254) / (mm_height * 10);
diff = dpi - DEFAULT_DPI;
diff = diff < 0 ? -diff : diff;
if (target_mode == NULL || (preferred > target_preferred) ||
(preferred == target_preferred && diff < target_diff)) {
target_mode = mode;
target_diff = diff;
target_preferred = preferred;
}
}
return target_mode;
}
static DisplayModePtr
xf86ClosestMode(xf86OutputPtr output,
DisplayModePtr match, Rotation match_rotation,
int width, int height)
{
DisplayModePtr target_mode = NULL;
DisplayModePtr mode;
int target_diff = 0;
/*
* Pick a mode closest to the specified mode
*/
for (mode = output->probed_modes; mode; mode = mode->next) {
int dx, dy;
int diff;
if (xf86ModeWidth(mode, output->initial_rotation) > width ||
xf86ModeHeight(mode, output->initial_rotation) > height)
continue;
/* exact matches are preferred */
if (output->initial_rotation == match_rotation &&
xf86ModesEqual(mode, match))
return mode;
dx = xf86ModeWidth(match, match_rotation) - xf86ModeWidth(mode,
output->
initial_rotation);
dy = xf86ModeHeight(match, match_rotation) - xf86ModeHeight(mode,
output->
initial_rotation);
diff = dx * dx + dy * dy;
if (target_mode == NULL || diff < target_diff) {
target_mode = mode;
target_diff = diff;
}
}
return target_mode;
}
static DisplayModePtr
xf86OutputHasPreferredMode(xf86OutputPtr output, int width, int height)
{
DisplayModePtr mode;
for (mode = output->probed_modes; mode; mode = mode->next) {
if (xf86ModeWidth(mode, output->initial_rotation) > width ||
xf86ModeHeight(mode, output->initial_rotation) > height)
continue;
if (mode->type & M_T_PREFERRED)
return mode;
}
return NULL;
}
static DisplayModePtr
xf86OutputHasUserPreferredMode(xf86OutputPtr output)
{
DisplayModePtr mode, first = output->probed_modes;
for (mode = first; mode && mode->next != first; mode = mode->next)
if (mode->type & M_T_USERPREF)
return mode;
return NULL;
}
static int
xf86PickCrtcs(ScrnInfoPtr scrn,
xf86CrtcPtr * best_crtcs,
DisplayModePtr * modes, int n, int width, int height)
{
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
int c, o;
xf86OutputPtr output;
xf86CrtcPtr crtc;
xf86CrtcPtr *crtcs;
int best_score;
int score;
int my_score;
if (n == config->num_output)
return 0;
output = config->output[n];
/*
* Compute score with this output disabled
*/
best_crtcs[n] = NULL;
best_score = xf86PickCrtcs(scrn, best_crtcs, modes, n + 1, width, height);
if (modes[n] == NULL)
return best_score;
crtcs = xallocarray(config->num_output, sizeof(xf86CrtcPtr));
if (!crtcs)
return best_score;
my_score = 1;
/* Score outputs that are known to be connected higher */
if (output->status == XF86OutputStatusConnected)
my_score++;
/* Score outputs with preferred modes higher */
if (xf86OutputHasPreferredMode(output, width, height))
my_score++;
/*
* Select a crtc for this output and
* then attempt to configure the remaining
* outputs
*/
for (c = 0; c < config->num_crtc; c++) {
if ((output->possible_crtcs & (1 << c)) == 0)
continue;
crtc = config->crtc[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 (xf86ModesEqual(modes[o], modes[n]) &&
config->output[o]->initial_rotation ==
config->output[n]->initial_rotation &&
config->output[o]->initial_x == config->output[n]->initial_x &&
config->output[o]->initial_y == config->output[n]->initial_y) {
if ((output->possible_clones & (1 << o)) == 0)
continue; /* nope, try next CRTC */
}
else
continue; /* different modes, can't clone */
}
crtcs[n] = crtc;
memcpy(crtcs, best_crtcs, n * sizeof(xf86CrtcPtr));
score =
my_score + xf86PickCrtcs(scrn, crtcs, modes, n + 1, width, height);
if (score > best_score) {
best_score = score;
memcpy(best_crtcs, crtcs, config->num_output * sizeof(xf86CrtcPtr));
}
}
free(crtcs);
return best_score;
}
/*
* Compute the virtual size necessary to place all of the available
* crtcs in the specified configuration.
*
* canGrow indicates that the driver can make the screen larger than its initial
* configuration. If FALSE, this function will enlarge the screen to include
* the largest available mode.
*/
static void
xf86DefaultScreenLimits(ScrnInfoPtr scrn, int *widthp, int *heightp,
Bool canGrow)
{
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
int width = 0, height = 0;
int o;
int c;
int s;
for (c = 0; c < config->num_crtc; c++) {
int crtc_width = 0, crtc_height = 0;
xf86CrtcPtr crtc = config->crtc[c];
if (crtc->enabled) {
crtc_width =
crtc->desiredX + xf86ModeWidth(&crtc->desiredMode,
crtc->desiredRotation);
crtc_height =
crtc->desiredY + xf86ModeHeight(&crtc->desiredMode,
crtc->desiredRotation);
}
if (!canGrow) {
for (o = 0; o < config->num_output; o++) {
xf86OutputPtr output = config->output[o];
for (s = 0; s < config->num_crtc; s++)
if (output->possible_crtcs & (1 << s)) {
DisplayModePtr mode;
for (mode = output->probed_modes; mode;
mode = mode->next) {
if (mode->HDisplay > crtc_width)
crtc_width = mode->HDisplay;
if (mode->VDisplay > crtc_width)
crtc_width = mode->VDisplay;
if (mode->VDisplay > crtc_height)
crtc_height = mode->VDisplay;
if (mode->HDisplay > crtc_height)
crtc_height = mode->HDisplay;
}
}
}
}
if (crtc_width > width)
width = crtc_width;
if (crtc_height > height)
height = crtc_height;
}
if (config->maxWidth && width > config->maxWidth)
width = config->maxWidth;
if (config->maxHeight && height > config->maxHeight)
height = config->maxHeight;
if (config->minWidth && width < config->minWidth)
width = config->minWidth;
if (config->minHeight && height < config->minHeight)
height = config->minHeight;
*widthp = width;
*heightp = height;
}
#define POSITION_UNSET -100000
/*
* check if the user configured any outputs at all
* with either a position or a relative setting or a mode.
*/
static Bool
xf86UserConfiguredOutputs(ScrnInfoPtr scrn, DisplayModePtr * modes)
{
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
int o;
Bool user_conf = FALSE;
for (o = 0; o < config->num_output; o++) {
xf86OutputPtr output = config->output[o];
const char *position;
const char *relative_name;
OutputOpts relation;
int r;
static const OutputOpts relations[] = {
OPTION_BELOW, OPTION_RIGHT_OF, OPTION_ABOVE, OPTION_LEFT_OF
};
position = xf86GetOptValString(output->options, OPTION_POSITION);
if (position)
user_conf = TRUE;
relation = 0;
relative_name = NULL;
for (r = 0; r < 4; r++) {
relation = relations[r];
relative_name = xf86GetOptValString(output->options, relation);
if (relative_name)
break;
}
if (relative_name)
user_conf = TRUE;
modes[o] = xf86OutputHasUserPreferredMode(output);
if (modes[o])
user_conf = TRUE;
}
return user_conf;
}
static Bool
xf86InitialOutputPositions(ScrnInfoPtr scrn, DisplayModePtr * modes)
{
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
int o;
int min_x, min_y;
/* check for initial right-of heuristic */
for (o = 0; o < config->num_output; o++)
{
xf86OutputPtr output = config->output[o];
if (output->initial_x || output->initial_y)
return TRUE;
}
for (o = 0; o < config->num_output; o++) {
xf86OutputPtr output = config->output[o];
output->initial_x = output->initial_y = POSITION_UNSET;
}
/*
* Loop until all outputs are set
*/
for (;;) {
Bool any_set = FALSE;
Bool keep_going = FALSE;
for (o = 0; o < config->num_output; o++) {
static const OutputOpts relations[] = {
OPTION_BELOW, OPTION_RIGHT_OF, OPTION_ABOVE, OPTION_LEFT_OF
};
xf86OutputPtr output = config->output[o];
xf86OutputPtr relative;
const char *relative_name;
const char *position;
OutputOpts relation;
int r;
if (output->initial_x != POSITION_UNSET)
continue;
position = xf86GetOptValString(output->options, OPTION_POSITION);
/*
* Absolute position wins
*/
if (position) {
int x, y;
if (sscanf(position, "%d %d", &x, &y) == 2) {
output->initial_x = x;
output->initial_y = y;
}
else {
xf86DrvMsg(scrn->scrnIndex, X_ERROR,
"Output %s position not of form \"x y\"\n",
output->name);
output->initial_x = output->initial_y = 0;
}
any_set = TRUE;
continue;
}
/*
* Next comes relative positions
*/
relation = 0;
relative_name = NULL;
for (r = 0; r < 4; r++) {
relation = relations[r];
relative_name = xf86GetOptValString(output->options, relation);
if (relative_name)
break;
}
if (relative_name) {
int or;
relative = NULL;
for (or = 0; or < config->num_output; or++) {
xf86OutputPtr out_rel = config->output[or];
XF86ConfMonitorPtr rel_mon = out_rel->conf_monitor;
if (rel_mon) {
if (xf86nameCompare(rel_mon->mon_identifier,
relative_name) == 0) {
relative = config->output[or];
break;
}
}
if (strcmp(out_rel->name, relative_name) == 0) {
relative = config->output[or];
break;
}
}
if (!relative) {
xf86DrvMsg(scrn->scrnIndex, X_ERROR,
"Cannot position output %s relative to unknown output %s\n",
output->name, relative_name);
output->initial_x = 0;
output->initial_y = 0;
any_set = TRUE;
continue;
}
if (!modes[or]) {
xf86DrvMsg(scrn->scrnIndex, X_ERROR,
"Cannot position output %s relative to output %s without modes\n",
output->name, relative_name);
output->initial_x = 0;
output->initial_y = 0;
any_set = TRUE;
continue;
}
if (relative->initial_x == POSITION_UNSET) {
keep_going = TRUE;
continue;
}
output->initial_x = relative->initial_x;
output->initial_y = relative->initial_y;
switch (relation) {
case OPTION_BELOW:
output->initial_y +=
xf86ModeHeight(modes[or], relative->initial_rotation);
break;
case OPTION_RIGHT_OF:
output->initial_x +=
xf86ModeWidth(modes[or], relative->initial_rotation);
break;
case OPTION_ABOVE:
if (modes[o])
output->initial_y -=
xf86ModeHeight(modes[o], output->initial_rotation);
break;
case OPTION_LEFT_OF:
if (modes[o])
output->initial_x -=
xf86ModeWidth(modes[o], output->initial_rotation);
break;
default:
break;
}
any_set = TRUE;
continue;
}
/* Nothing set, just stick them at 0,0 */
output->initial_x = 0;
output->initial_y = 0;
any_set = TRUE;
}
if (!keep_going)
break;
if (!any_set) {
for (o = 0; o < config->num_output; o++) {
xf86OutputPtr output = config->output[o];
if (output->initial_x == POSITION_UNSET) {
xf86DrvMsg(scrn->scrnIndex, X_ERROR,
"Output position loop. Moving %s to 0,0\n",
output->name);
output->initial_x = output->initial_y = 0;
break;
}
}
}
}
/*
* normalize positions
*/
min_x = 1000000;
min_y = 1000000;
for (o = 0; o < config->num_output; o++) {
xf86OutputPtr output = config->output[o];
if (output->initial_x < min_x)
min_x = output->initial_x;
if (output->initial_y < min_y)
min_y = output->initial_y;
}
for (o = 0; o < config->num_output; o++) {
xf86OutputPtr output = config->output[o];
output->initial_x -= min_x;
output->initial_y -= min_y;
}
return TRUE;
}
static void
xf86InitialPanning(ScrnInfoPtr scrn)
{
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
int o;
for (o = 0; o < config->num_output; o++) {
xf86OutputPtr output = config->output[o];
const char *panning = xf86GetOptValString(output->options, OPTION_PANNING);
int width, height, left, top;
int track_width, track_height, track_left, track_top;
int brdr[4];
memset(&output->initialTotalArea, 0, sizeof(BoxRec));
memset(&output->initialTrackingArea, 0, sizeof(BoxRec));
memset(output->initialBorder, 0, 4 * sizeof(INT16));
if (!panning)
continue;
switch (sscanf(panning, "%dx%d+%d+%d/%dx%d+%d+%d/%d/%d/%d/%d",
&width, &height, &left, &top,
&track_width, &track_height, &track_left, &track_top,
&brdr[0], &brdr[1], &brdr[2], &brdr[3])) {
case 12:
output->initialBorder[0] = brdr[0];
output->initialBorder[1] = brdr[1];
output->initialBorder[2] = brdr[2];
output->initialBorder[3] = brdr[3];
/* fall through */
case 8:
output->initialTrackingArea.x1 = track_left;
output->initialTrackingArea.y1 = track_top;
output->initialTrackingArea.x2 = track_left + track_width;
output->initialTrackingArea.y2 = track_top + track_height;
/* fall through */
case 4:
output->initialTotalArea.x1 = left;
output->initialTotalArea.y1 = top;
/* fall through */
case 2:
output->initialTotalArea.x2 = output->initialTotalArea.x1 + width;
output->initialTotalArea.y2 = output->initialTotalArea.y1 + height;
break;
default:
xf86DrvMsg(scrn->scrnIndex, X_ERROR,
"Broken panning specification '%s' for output %s in config file\n",
panning, output->name);
}
}
}
/** Return - 0 + if a should be earlier, same or later than b in list
*/
static int
xf86ModeCompare(DisplayModePtr a, DisplayModePtr b)
{
int diff;
diff = ((b->type & M_T_PREFERRED) != 0) - ((a->type & M_T_PREFERRED) != 0);
if (diff)
return diff;
diff = b->HDisplay * b->VDisplay - a->HDisplay * a->VDisplay;
if (diff)
return diff;
diff = b->Clock - a->Clock;
return diff;
}
/**
* Insertion sort input in-place and return the resulting head
*/
static DisplayModePtr
xf86SortModes(DisplayModePtr input)
{
DisplayModePtr output = NULL, i, o, n, *op, prev;
/* sort by preferred status and pixel area */
while (input) {
i = input;
input = input->next;
for (op = &output; (o = *op); op = &o->next)
if (xf86ModeCompare(o, i) > 0)
break;
i->next = *op;
*op = i;
}
/* prune identical modes */
for (o = output; o && (n = o->next); o = n) {
if (!strcmp(o->name, n->name) && xf86ModesEqual(o, n)) {
o->next = n->next;
free((void *) n->name);
free(n);
n = o;
}
}
/* hook up backward links */
prev = NULL;
for (o = output; o; o = o->next) {
o->prev = prev;
prev = o;
}
return output;
}
static const char *
preferredMode(ScrnInfoPtr pScrn, xf86OutputPtr output)
{
const char *preferred_mode = NULL;
/* Check for a configured preference for a particular mode */
preferred_mode = xf86GetOptValString(output->options,
OPTION_PREFERRED_MODE);
if (preferred_mode)
return preferred_mode;
if (pScrn->display->modes && *pScrn->display->modes)
preferred_mode = *pScrn->display->modes;
return preferred_mode;
}
/** identify a token
* args
* *src a string with zero or more tokens, e.g. "tok0 tok1",
* **token stores a pointer to the first token character,
* *len stores the token length.
* return
* a pointer into src[] at the token terminating character, or
* NULL if no token is found.
*/
static const char *
gettoken(const char *src, const char **token, int *len)
{
const char *delim = " \t";
int skip;
if (!src)
return NULL;
skip = strspn(src, delim);
*token = &src[skip];
*len = strcspn(*token, delim);
/* Support for backslash escaped delimiters could be implemented
* here.
*/
/* (*token)[0] != '\0' <==> *len > 0 */
if (*len > 0)
return &(*token)[*len];
else
return NULL;
}
/** Check for a user configured zoom mode list, Option "ZoomModes":
*
* Section "Monitor"
* Identifier "a21inch"
* Option "ZoomModes" "1600x1200 1280x1024 1280x1024 640x480"
* EndSection
*
* Each user mode name is searched for independently so the list
* specification order is free. An output mode is matched at most
* once, a mode with an already set M_T_USERDEF type bit is skipped.
* Thus a repeat mode name specification matches the next output mode
* with the same name.
*
* Ctrl+Alt+Keypad-{Plus,Minus} zooms {in,out} by selecting the
* {next,previous} M_T_USERDEF mode in the screen modes list, itself
* sorted toward lower dot area or lower dot clock frequency, see
* modes/xf86Crtc.c: xf86SortModes() xf86SetScrnInfoModes(), and
* common/xf86Cursor.c: xf86ZoomViewport().
*/
static int
processZoomModes(xf86OutputPtr output)
{
const char *zoom_modes;
int count = 0;
zoom_modes = xf86GetOptValString(output->options, OPTION_ZOOM_MODES);
if (zoom_modes) {
const char *token, *next;
int len;
next = gettoken(zoom_modes, &token, &len);
while (next) {
DisplayModePtr mode;
for (mode = output->probed_modes; mode; mode = mode->next)
if (!strncmp(token, mode->name, len) /* prefix match */
&& mode->name[len] == '\0' /* equal length */
&& !(mode->type & M_T_USERDEF)) { /* no rematch */
mode->type |= M_T_USERDEF;
break;
}
count++;
next = gettoken(next, &token, &len);
}
}
return count;
}
static void
GuessRangeFromModes(MonPtr mon, DisplayModePtr mode)
{
if (!mon || !mode)
return;
mon->nHsync = 1;
mon->hsync[0].lo = 1024.0;
mon->hsync[0].hi = 0.0;
mon->nVrefresh = 1;
mon->vrefresh[0].lo = 1024.0;
mon->vrefresh[0].hi = 0.0;
while (mode) {
if (!mode->HSync)
mode->HSync = ((float) mode->Clock) / ((float) mode->HTotal);
if (!mode->VRefresh)
mode->VRefresh = (1000.0 * ((float) mode->Clock)) /
((float) (mode->HTotal * mode->VTotal));
if (mode->HSync < mon->hsync[0].lo)
mon->hsync[0].lo = mode->HSync;
if (mode->HSync > mon->hsync[0].hi)
mon->hsync[0].hi = mode->HSync;
if (mode->VRefresh < mon->vrefresh[0].lo)
mon->vrefresh[0].lo = mode->VRefresh;
if (mode->VRefresh > mon->vrefresh[0].hi)
mon->vrefresh[0].hi = mode->VRefresh;
mode = mode->next;
}
/* stretch out the bottom to fit 640x480@60 */
if (mon->hsync[0].lo > 31.0)
mon->hsync[0].lo = 31.0;
if (mon->vrefresh[0].lo > 58.0)
mon->vrefresh[0].lo = 58.0;
}
enum det_monrec_source {
sync_config, sync_edid, sync_default
};
struct det_monrec_parameter {
MonRec *mon_rec;
int *max_clock;
Bool set_hsync;
Bool set_vrefresh;
enum det_monrec_source *sync_source;
};
static void
handle_detailed_monrec(struct detailed_monitor_section *det_mon, void *data)
{
struct det_monrec_parameter *p;
p = (struct det_monrec_parameter *) data;
if (det_mon->type == DS_RANGES) {
struct monitor_ranges *ranges = &det_mon->section.ranges;
if (p->set_hsync && ranges->max_h) {
p->mon_rec->hsync[p->mon_rec->nHsync].lo = ranges->min_h;
p->mon_rec->hsync[p->mon_rec->nHsync].hi = ranges->max_h;
p->mon_rec->nHsync++;
if (*p->sync_source == sync_default)
*p->sync_source = sync_edid;
}
if (p->set_vrefresh && ranges->max_v) {
p->mon_rec->vrefresh[p->mon_rec->nVrefresh].lo = ranges->min_v;
p->mon_rec->vrefresh[p->mon_rec->nVrefresh].hi = ranges->max_v;
p->mon_rec->nVrefresh++;
if (*p->sync_source == sync_default)
*p->sync_source = sync_edid;
}
if (ranges->max_clock * 1000 > *p->max_clock)
*p->max_clock = ranges->max_clock * 1000;
}
}
void
xf86ProbeOutputModes(ScrnInfoPtr scrn, int maxX, int maxY)
{
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
int o;
/* When canGrow was TRUE in the initial configuration we have to
* compare against the maximum values so that we don't drop modes.
* When canGrow was FALSE, the maximum values would have been clamped
* anyway.
*/
if (maxX == 0 || maxY == 0) {
maxX = config->maxWidth;
maxY = config->maxHeight;
}
/* Probe the list of modes for each output. */
for (o = 0; o < config->num_output; o++) {
xf86OutputPtr output = config->output[o];
DisplayModePtr mode;
DisplayModePtr config_modes = NULL, output_modes, default_modes = NULL;
const char *preferred_mode;
xf86MonPtr edid_monitor;
XF86ConfMonitorPtr conf_monitor;
MonRec mon_rec;
int min_clock = 0;
int max_clock = 0;
double clock;
Bool add_default_modes;
Bool debug_modes = config->debug_modes || xf86Initialising;
enum det_monrec_source sync_source = sync_default;
while (output->probed_modes != NULL)
xf86DeleteMode(&output->probed_modes, output->probed_modes);
/*
* Check connection status
*/
output->status = (*output->funcs->detect) (output);
if (output->status == XF86OutputStatusDisconnected &&
!xf86ReturnOptValBool(output->options, OPTION_ENABLE, FALSE)) {
xf86OutputSetEDID(output, NULL);
continue;
}
memset(&mon_rec, '\0', sizeof(mon_rec));
conf_monitor = output->conf_monitor;
if (conf_monitor) {
int i;
for (i = 0; i < conf_monitor->mon_n_hsync; i++) {
mon_rec.hsync[mon_rec.nHsync].lo =
conf_monitor->mon_hsync[i].lo;
mon_rec.hsync[mon_rec.nHsync].hi =
conf_monitor->mon_hsync[i].hi;
mon_rec.nHsync++;
sync_source = sync_config;
}
for (i = 0; i < conf_monitor->mon_n_vrefresh; i++) {
mon_rec.vrefresh[mon_rec.nVrefresh].lo =
conf_monitor->mon_vrefresh[i].lo;
mon_rec.vrefresh[mon_rec.nVrefresh].hi =
conf_monitor->mon_vrefresh[i].hi;
mon_rec.nVrefresh++;
sync_source = sync_config;
}
config_modes = xf86GetMonitorModes(scrn, conf_monitor);
}
output_modes = (*output->funcs->get_modes) (output);
/*
* If the user has a preference, respect it.
* Otherwise, don't second-guess the driver.
*/
if (!xf86GetOptValBool(output->options, OPTION_DEFAULT_MODES,
&add_default_modes))
add_default_modes = (output_modes == NULL);
edid_monitor = output->MonInfo;
if (edid_monitor) {
struct det_monrec_parameter p;
struct disp_features *features = &edid_monitor->features;
struct cea_data_block *hdmi_db;
/* if display is not continuous-frequency, don't add default modes */
if (!GTF_SUPPORTED(features->msc))
add_default_modes = FALSE;
p.mon_rec = &mon_rec;
p.max_clock = &max_clock;
p.set_hsync = mon_rec.nHsync == 0;
p.set_vrefresh = mon_rec.nVrefresh == 0;
p.sync_source = &sync_source;
xf86ForEachDetailedBlock(edid_monitor, handle_detailed_monrec, &p);
/* Look at the CEA HDMI vendor block for the max TMDS freq */
hdmi_db = xf86MonitorFindHDMIBlock(edid_monitor);
if (hdmi_db && hdmi_db->len >= 7) {
int tmds_freq = hdmi_db->u.vendor.hdmi.max_tmds_clock * 5000;
xf86DrvMsg(scrn->scrnIndex, X_PROBED,
"HDMI max TMDS frequency %dKHz\n", tmds_freq);
if (tmds_freq > max_clock)
max_clock = tmds_freq;
}
}
if (xf86GetOptValFreq(output->options, OPTION_MIN_CLOCK,
OPTUNITS_KHZ, &clock))
min_clock = (int) clock;
if (xf86GetOptValFreq(output->options, OPTION_MAX_CLOCK,
OPTUNITS_KHZ, &clock))
max_clock = (int) clock;
/* If we still don't have a sync range, guess wildly */
if (!mon_rec.nHsync || !mon_rec.nVrefresh)
GuessRangeFromModes(&mon_rec, output_modes);
/*
* These limits will end up setting a 1024x768@60Hz mode by default,
* which seems like a fairly good mode to use when nothing else is
* specified
*/
if (mon_rec.nHsync == 0) {
mon_rec.hsync[0].lo = 31.0;
mon_rec.hsync[0].hi = 55.0;
mon_rec.nHsync = 1;
}
if (mon_rec.nVrefresh == 0) {
mon_rec.vrefresh[0].lo = 58.0;
mon_rec.vrefresh[0].hi = 62.0;
mon_rec.nVrefresh = 1;
}
if (add_default_modes)
default_modes = xf86GetDefaultModes();
/*
* If this is not an RB monitor, remove RB modes from the default
* pool. RB modes from the config or the monitor itself are fine.
*/
if (!mon_rec.reducedblanking)
xf86ValidateModesReducedBlanking(scrn, default_modes);
if (sync_source == sync_config) {
/*
* Check output and config modes against sync range from config file
*/
xf86ValidateModesSync(scrn, output_modes, &mon_rec);
xf86ValidateModesSync(scrn, config_modes, &mon_rec);
}
/*
* Check default modes against sync range
*/
xf86ValidateModesSync(scrn, default_modes, &mon_rec);
/*
* Check default modes against monitor max clock
*/
if (max_clock) {
xf86ValidateModesClocks(scrn, default_modes,
&min_clock, &max_clock, 1);
xf86ValidateModesClocks(scrn, output_modes,
&min_clock, &max_clock, 1);
}
output->probed_modes = NULL;
output->probed_modes = xf86ModesAdd(output->probed_modes, config_modes);
output->probed_modes = xf86ModesAdd(output->probed_modes, output_modes);
output->probed_modes =
xf86ModesAdd(output->probed_modes, default_modes);
/*
* Check all modes against max size, interlace, and doublescan
*/
if (maxX && maxY)
xf86ValidateModesSize(scrn, output->probed_modes, maxX, maxY, 0);
{
int flags = (output->interlaceAllowed ? V_INTERLACE : 0) |
(output->doubleScanAllowed ? V_DBLSCAN : 0);
xf86ValidateModesFlags(scrn, output->probed_modes, flags);
}
/*
* Check all modes against output
*/
for (mode = output->probed_modes; mode != NULL; mode = mode->next)
if (mode->status == MODE_OK)
mode->status = (*output->funcs->mode_valid) (output, mode);
xf86PruneInvalidModes(scrn, &output->probed_modes, debug_modes);
output->probed_modes = xf86SortModes(output->probed_modes);
/* Check for a configured preference for a particular mode */
preferred_mode = preferredMode(scrn, output);
if (preferred_mode) {
for (mode = output->probed_modes; mode; mode = mode->next) {
if (!strcmp(preferred_mode, mode->name)) {
if (mode != output->probed_modes) {
if (mode->prev)
mode->prev->next = mode->next;
if (mode->next)
mode->next->prev = mode->prev;
mode->next = output->probed_modes;
output->probed_modes->prev = mode;
mode->prev = NULL;
output->probed_modes = mode;
}
mode->type |= (M_T_PREFERRED | M_T_USERPREF);
break;
}
}
}
/* Ctrl+Alt+Keypad-{Plus,Minus} zoom mode: M_T_USERDEF mode type */
processZoomModes(output);
output->initial_rotation = xf86OutputInitialRotation(output);
if (debug_modes) {
if (output->probed_modes != NULL) {
xf86DrvMsg(scrn->scrnIndex, X_INFO,
"Printing probed modes for output %s\n",
output->name);
}
else {
xf86DrvMsg(scrn->scrnIndex, X_INFO,
"No remaining probed modes for output %s\n",
output->name);
}
}
for (mode = output->probed_modes; mode != NULL; mode = mode->next) {
/* The code to choose the best mode per pipe later on will require
* VRefresh to be set.
*/
mode->VRefresh = xf86ModeVRefresh(mode);
xf86SetModeCrtc(mode, INTERLACE_HALVE_V);
if (debug_modes)
xf86PrintModeline(scrn->scrnIndex, mode);
}
}
}
/**
* Copy one of the output mode lists to the ScrnInfo record
*/
static DisplayModePtr
biggestMode(DisplayModePtr a, DisplayModePtr b)
{
int A, B;
if (!a)
return b;
if (!b)
return a;
A = a->HDisplay * a->VDisplay;
B = b->HDisplay * b->VDisplay;
if (A > B)
return a;
return b;
}
static xf86OutputPtr
SetCompatOutput(xf86CrtcConfigPtr config)
{
xf86OutputPtr output = NULL, test = NULL;
DisplayModePtr maxmode = NULL, testmode, mode;
int o, compat = -1, count, mincount = 0;
if (config->num_output == 0)
return NULL;
/* Look for one that's definitely connected */
for (o = 0; o < config->num_output; o++) {
test = config->output[o];
if (!test->crtc)
continue;
if (test->status != XF86OutputStatusConnected)
continue;
if (!test->probed_modes)
continue;
testmode = mode = test->probed_modes;
for (count = 0; mode; mode = mode->next, count++)
testmode = biggestMode(testmode, mode);
if (!output) {
output = test;
compat = o;
maxmode = testmode;
mincount = count;
}
else if (maxmode == biggestMode(maxmode, testmode)) {
output = test;
compat = o;
maxmode = testmode;
mincount = count;
}
else if ((maxmode->HDisplay == testmode->HDisplay) &&
(maxmode->VDisplay == testmode->VDisplay) &&
count <= mincount) {
output = test;
compat = o;
maxmode = testmode;
mincount = count;
}
}
/* If we didn't find one, take anything we can get */
if (!output) {
for (o = 0; o < config->num_output; o++) {
test = config->output[o];
if (!test->crtc)
continue;
if (!test->probed_modes)
continue;
if (!output) {
output = test;
compat = o;
}
else if (test->probed_modes->HDisplay <
output->probed_modes->HDisplay) {
output = test;
compat = o;
}
}
}
if (compat >= 0) {
config->compat_output = compat;
}
else if (config->compat_output >= 0 && config->compat_output < config->num_output) {
/* Don't change the compat output when no valid outputs found */
output = config->output[config->compat_output];
}
/* All outputs are disconnected, select one to fake */
if (!output && config->num_output) {
config->compat_output = 0;
output = config->output[config->compat_output];
}
return output;
}
void
xf86SetScrnInfoModes(ScrnInfoPtr scrn)
{
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
xf86OutputPtr output;
xf86CrtcPtr crtc;
DisplayModePtr last, mode = NULL;
output = SetCompatOutput(config);
if (!output)
return; /* punt */
crtc = output->crtc;
/* Clear any existing modes from scrn->modes */
while (scrn->modes != NULL)
xf86DeleteMode(&scrn->modes, scrn->modes);
/* Set scrn->modes to the mode list for the 'compat' output */
scrn->modes = xf86DuplicateModes(scrn, output->probed_modes);
if (crtc) {
for (mode = scrn->modes; mode; mode = mode->next)
if (xf86ModesEqual(mode, &crtc->desiredMode))
break;
}
if (!scrn->modes) {
scrn->modes = xf86ModesAdd(scrn->modes,
xf86CVTMode(scrn->display->virtualX,
scrn->display->virtualY,
60, 0, 0));
}
/* For some reason, scrn->modes is circular, unlike the other mode
* lists. How great is that?
*/
for (last = scrn->modes; last && last->next; last = last->next);
last->next = scrn->modes;
scrn->modes->prev = last;
if (mode) {
while (scrn->modes != mode)
scrn->modes = scrn->modes->next;
}
scrn->currentMode = scrn->modes;
#ifdef XFreeXDGA
if (scrn->pScreen)
_xf86_di_dga_reinit_internal(scrn->pScreen);
#endif
}
static Bool
xf86CollectEnabledOutputs(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
Bool *enabled)
{
Bool any_enabled = FALSE;
int o;
/*
* Don't bother enabling outputs on GPU screens: a client needs to attach
* it to a source provider before setting a mode that scans out a shared
* pixmap.
*/
if (scrn->is_gpu)
return FALSE;
for (o = 0; o < config->num_output; o++)
any_enabled |= enabled[o] = xf86OutputEnabled(config->output[o], TRUE);
if (!any_enabled) {
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
"No outputs definitely connected, trying again...\n");
for (o = 0; o < config->num_output; o++)
any_enabled |= enabled[o] =
xf86OutputEnabled(config->output[o], FALSE);
}
return any_enabled;
}
static Bool
nextEnabledOutput(xf86CrtcConfigPtr config, Bool *enabled, int *index)
{
int o = *index;
for (o++; o < config->num_output; o++) {
if (enabled[o]) {
*index = o;
return TRUE;
}
}
return FALSE;
}
static Bool
aspectMatch(float a, float b)
{
return fabs(1 - (a / b)) < 0.05;
}
static DisplayModePtr
nextAspectMode(xf86OutputPtr o, DisplayModePtr last, float aspect)
{
DisplayModePtr m = NULL;
if (!o)
return NULL;
if (!last)
m = o->probed_modes;
else
m = last->next;
for (; m; m = m->next)
if (aspectMatch(aspect, (float) m->HDisplay / (float) m->VDisplay))
return m;
return NULL;
}
static DisplayModePtr
bestModeForAspect(xf86CrtcConfigPtr config, Bool *enabled, float aspect)
{
int o = -1, p;
DisplayModePtr mode = NULL, test = NULL, match = NULL;
if (!nextEnabledOutput(config, enabled, &o))
return NULL;
while ((mode = nextAspectMode(config->output[o], mode, aspect))) {
test = mode;
for (p = o; nextEnabledOutput(config, enabled, &p);) {
test = xf86OutputFindClosestMode(config->output[p], mode);
if (!test)
break;
if (test->HDisplay != mode->HDisplay ||
test->VDisplay != mode->VDisplay) {
test = NULL;
break;
}
}
/* if we didn't match it on all outputs, try the next one */
if (!test)
continue;
/* if it's bigger than the last one, save it */
if (!match || (test->HDisplay > match->HDisplay))
match = test;
}
/* return the biggest one found */
return match;
}
static int
numEnabledOutputs(xf86CrtcConfigPtr config, Bool *enabled)
{
int i = 0, p;
for (i = 0, p = -1; nextEnabledOutput(config, enabled, &p); i++) ;
return i;
}
static Bool
xf86TargetRightOf(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
DisplayModePtr *modes, Bool *enabled,
int width, int height)
{
int o;
int w = 0;
Bool has_tile = FALSE;
uint32_t configured_outputs;
if (scrn->preferClone)
return FALSE;
if (numEnabledOutputs(config, enabled) < 2)
return FALSE;
for (o = -1; nextEnabledOutput(config, enabled, &o); ) {
DisplayModePtr mode =
xf86OutputHasPreferredMode(config->output[o], width, height);
if (!mode)
return FALSE;
w += mode->HDisplay;
}
if (w > width)
return FALSE;
w = 0;
configured_outputs = 0;
for (o = -1; nextEnabledOutput(config, enabled, &o); ) {
DisplayModePtr mode =
xf86OutputHasPreferredMode(config->output[o], width, height);
if (configured_outputs & (1 << o))
continue;
if (config->output[o]->tile_info.group_id) {
has_tile = TRUE;
continue;
}
config->output[o]->initial_x = w;
w += mode->HDisplay;
configured_outputs |= (1 << o);
modes[o] = mode;
}
if (has_tile) {
for (o = -1; nextEnabledOutput(config, enabled, &o); ) {
int ht, vt, ot;
int add_x, cur_x = w;
struct xf86CrtcTileInfo *tile_info = &config->output[o]->tile_info, *this_tile;
if (configured_outputs & (1 << o))
continue;
if (!tile_info->group_id)
continue;
if (tile_info->tile_h_loc != 0 && tile_info->tile_v_loc != 0)
continue;
for (ht = 0; ht < tile_info->num_h_tile; ht++) {
int cur_y = 0;
add_x = 0;
for (vt = 0; vt < tile_info->num_v_tile; vt++) {
for (ot = -1; nextEnabledOutput(config, enabled, &ot); ) {
DisplayModePtr mode =
xf86OutputHasPreferredMode(config->output[ot], width, height);
if (!config->output[ot]->tile_info.group_id)
continue;
this_tile = &config->output[ot]->tile_info;
if (this_tile->group_id != tile_info->group_id)
continue;
if (this_tile->tile_h_loc != ht ||
this_tile->tile_v_loc != vt)
continue;
config->output[ot]->initial_x = cur_x;
config->output[ot]->initial_y = cur_y;
if (vt == 0)
add_x = this_tile->tile_h_size;
cur_y += this_tile->tile_v_size;
configured_outputs |= (1 << ot);
modes[ot] = mode;
}
}
cur_x += add_x;
}
w = cur_x;
}
}
return TRUE;
}
static Bool
xf86TargetPreferred(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
DisplayModePtr * modes, Bool *enabled,
int width, int height)
{
int o, p;
int max_pref_width = 0, max_pref_height = 0;
DisplayModePtr *preferred, *preferred_match;
Bool ret = FALSE;
preferred = xnfcalloc(config->num_output, sizeof(DisplayModePtr));
preferred_match = xnfcalloc(config->num_output, sizeof(DisplayModePtr));
/* Check if the preferred mode is available on all outputs */
for (p = -1; nextEnabledOutput(config, enabled, &p);) {
Rotation r = config->output[p]->initial_rotation;
DisplayModePtr mode;
if ((preferred[p] = xf86OutputHasPreferredMode(config->output[p],
width, height))) {
int pref_width = xf86ModeWidth(preferred[p], r);
int pref_height = xf86ModeHeight(preferred[p], r);
Bool all_match = TRUE;
for (o = -1; nextEnabledOutput(config, enabled, &o);) {
Bool match = FALSE;
xf86OutputPtr output = config->output[o];
if (o == p)
continue;
/*
* First see if the preferred mode matches on the next
* output as well. This catches the common case of identical
* monitors and makes sure they all have the same timings
* and refresh. If that fails, we fall back to trying to
* match just width & height.
*/
mode = xf86OutputHasPreferredMode(output, pref_width,
pref_height);
if (mode && xf86ModesEqual(mode, preferred[p])) {
preferred[o] = mode;
match = TRUE;
}
else {
for (mode = output->probed_modes; mode; mode = mode->next) {
Rotation ir = output->initial_rotation;
if (xf86ModeWidth(mode, ir) == pref_width &&
xf86ModeHeight(mode, ir) == pref_height) {
preferred[o] = mode;
match = TRUE;
}
}
}
all_match &= match;
}
if (all_match &&
(pref_width * pref_height > max_pref_width * max_pref_height)) {
for (o = -1; nextEnabledOutput(config, enabled, &o);)
preferred_match[o] = preferred[o];
max_pref_width = pref_width;
max_pref_height = pref_height;
ret = TRUE;
}
}
}
/*
* If there's no preferred mode, but only one monitor, pick the
* biggest mode for its aspect ratio or 4:3, assuming one exists.
*/
if (!ret)
do {
float aspect = 0.0;
DisplayModePtr a = NULL, b = NULL;
if (numEnabledOutputs(config, enabled) != 1)
break;
p = -1;
nextEnabledOutput(config, enabled, &p);
if (config->output[p]->mm_height)
aspect = (float) config->output[p]->mm_width /
(float) config->output[p]->mm_height;
a = bestModeForAspect(config, enabled, 4.0/3.0);
if (aspect)
b = bestModeForAspect(config, enabled, aspect);
preferred_match[p] = biggestMode(a, b);
if (preferred_match[p])
ret = TRUE;
} while (0);
if (ret) {
/* oh good, there is a match. stash the selected modes and return. */
memcpy(modes, preferred_match,
config->num_output * sizeof(DisplayModePtr));
}
free(preferred);
free(preferred_match);
return ret;
}
static Bool
xf86TargetAspect(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
DisplayModePtr * modes, Bool *enabled, int width, int height)
{
int o;
float aspect = 0.0, *aspects;
xf86OutputPtr output;
Bool ret = FALSE;
DisplayModePtr guess = NULL, aspect_guess = NULL, base_guess = NULL;
aspects = xnfcalloc(config->num_output, sizeof(float));
/* collect the aspect ratios */
for (o = -1; nextEnabledOutput(config, enabled, &o);) {
output = config->output[o];
if (output->mm_height)
aspects[o] = (float) output->mm_width / (float) output->mm_height;
else
aspects[o] = 4.0 / 3.0;
}
/* check that they're all the same */
for (o = -1; nextEnabledOutput(config, enabled, &o);) {
output = config->output[o];
if (!aspect) {
aspect = aspects[o];
}
else if (!aspectMatch(aspect, aspects[o])) {
goto no_aspect_match;
}
}
/* if they're all 4:3, just skip ahead and save effort */
if (!aspectMatch(aspect, 4.0 / 3.0))
aspect_guess = bestModeForAspect(config, enabled, aspect);
no_aspect_match:
base_guess = bestModeForAspect(config, enabled, 4.0 / 3.0);
guess = biggestMode(base_guess, aspect_guess);
if (!guess)
goto out;
/* found a mode that works everywhere, now apply it */
for (o = -1; nextEnabledOutput(config, enabled, &o);) {
modes[o] = xf86OutputFindClosestMode(config->output[o], guess);
}
ret = TRUE;
out:
free(aspects);
return ret;
}
static Bool
xf86TargetFallback(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
DisplayModePtr * modes, Bool *enabled, int width, int height)
{
DisplayModePtr target_mode = NULL;
Rotation target_rotation = RR_Rotate_0;
DisplayModePtr default_mode;
int default_preferred, target_preferred = 0, o;
/* User preferred > preferred > other modes */
for (o = -1; nextEnabledOutput(config, enabled, &o);) {
default_mode = xf86DefaultMode(config->output[o], width, height);
if (!default_mode)
continue;
default_preferred = (((default_mode->type & M_T_PREFERRED) != 0) +
((default_mode->type & M_T_USERPREF) != 0));
if (default_preferred > target_preferred || !target_mode) {
target_mode = default_mode;
target_preferred = default_preferred;
target_rotation = config->output[o]->initial_rotation;
config->compat_output = o;
}
}
if (target_mode)
modes[config->compat_output] = target_mode;
/* Fill in other output modes */
for (o = -1; nextEnabledOutput(config, enabled, &o);) {
if (!modes[o])
modes[o] = xf86ClosestMode(config->output[o], target_mode,
target_rotation, width, height);
}
return target_mode != NULL;
}
static Bool
xf86TargetUserpref(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
DisplayModePtr * modes, Bool *enabled, int width, int height)
{
int o;
if (xf86UserConfiguredOutputs(scrn, modes))
return xf86TargetFallback(scrn, config, modes, enabled, width, height);
for (o = -1; nextEnabledOutput(config, enabled, &o);)
if (xf86OutputHasUserPreferredMode(config->output[o]))
return
xf86TargetFallback(scrn, config, modes, enabled, width, height);
return FALSE;
}
/**
* Construct default screen configuration
*
* Given auto-detected (and, eventually, configured) values,
* construct a usable configuration for the system
*
* canGrow indicates that the driver can resize the screen to larger than its
* initially configured size via the config->funcs->resize hook. If TRUE, this
* function will set virtualX and virtualY to match the initial configuration
* and leave config->max{Width,Height} alone. If FALSE, it will bloat
* virtual[XY] to include the largest modes and set config->max{Width,Height}
* accordingly.
*/
Bool
xf86InitialConfiguration(ScrnInfoPtr scrn, Bool canGrow)
{
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
int o, c;
xf86CrtcPtr *crtcs;
DisplayModePtr *modes;
Bool *enabled;
int width, height;
int i = scrn->scrnIndex;
Bool have_outputs = TRUE;
Bool ret;
Bool success = FALSE;
/* Set up the device options */
config->options = xnfalloc(sizeof(xf86DeviceOptions));
memcpy(config->options, xf86DeviceOptions, sizeof(xf86DeviceOptions));
xf86ProcessOptions(scrn->scrnIndex, scrn->options, config->options);
config->debug_modes = xf86ReturnOptValBool(config->options,
OPTION_MODEDEBUG, FALSE);
if (scrn->display->virtualX && !scrn->is_gpu)
width = scrn->display->virtualX;
else
width = config->maxWidth;
if (scrn->display->virtualY && !scrn->is_gpu)
height = scrn->display->virtualY;
else
height = config->maxHeight;
xf86ProbeOutputModes(scrn, width, height);
crtcs = xnfcalloc(config->num_output, sizeof(xf86CrtcPtr));
modes = xnfcalloc(config->num_output, sizeof(DisplayModePtr));
enabled = xnfcalloc(config->num_output, sizeof(Bool));
ret = xf86CollectEnabledOutputs(scrn, config, enabled);
if (ret == FALSE && canGrow) {
if (!scrn->is_gpu)
xf86DrvMsg(i, X_WARNING,
"Unable to find connected outputs - setting %dx%d "
"initial framebuffer\n",
NO_OUTPUT_DEFAULT_WIDTH, NO_OUTPUT_DEFAULT_HEIGHT);
have_outputs = FALSE;
}
else {
if (xf86TargetUserpref(scrn, config, modes, enabled, width, height))
xf86DrvMsg(i, X_INFO, "Using user preference for initial modes\n");
else if (xf86TargetRightOf(scrn, config, modes, enabled, width, height))
xf86DrvMsg(i, X_INFO, "Using spanning desktop for initial modes\n");
else if (xf86TargetPreferred
(scrn, config, modes, enabled, width, height))
xf86DrvMsg(i, X_INFO, "Using exact sizes for initial modes\n");
else if (xf86TargetAspect(scrn, config, modes, enabled, width, height))
xf86DrvMsg(i, X_INFO,
"Using fuzzy aspect match for initial modes\n");
else if (xf86TargetFallback
(scrn, config, modes, enabled, width, height))
xf86DrvMsg(i, X_INFO, "Using sloppy heuristic for initial modes\n");
else
xf86DrvMsg(i, X_WARNING, "Unable to find initial modes\n");
}
for (o = -1; nextEnabledOutput(config, enabled, &o);) {
if (!modes[o])
xf86DrvMsg(scrn->scrnIndex, X_ERROR,
"Output %s enabled but has no modes\n",
config->output[o]->name);
else
xf86DrvMsg (scrn->scrnIndex, X_INFO,
"Output %s using initial mode %s +%d+%d\n",
config->output[o]->name, modes[o]->name,
config->output[o]->initial_x,
config->output[o]->initial_y);
}
/*
* Set the position of each output
*/
if (!xf86InitialOutputPositions(scrn, modes))
goto bailout;
/*
* Set initial panning of each output
*/
xf86InitialPanning(scrn);
/*
* Assign CRTCs to fit output configuration
*/
if (have_outputs && !xf86PickCrtcs(scrn, crtcs, modes, 0, width, height))
goto bailout;
/* XXX override xf86 common frame computation code */
if (!scrn->is_gpu) {
scrn->display->frameX0 = 0;
scrn->display->frameY0 = 0;
}
for (c = 0; c < config->num_crtc; c++) {
xf86CrtcPtr crtc = config->crtc[c];
crtc->enabled = FALSE;
memset(&crtc->desiredMode, '\0', sizeof(crtc->desiredMode));
}
/*
* Set initial configuration
*/
for (o = 0; o < config->num_output; o++) {
xf86OutputPtr output = config->output[o];
DisplayModePtr mode = modes[o];
xf86CrtcPtr crtc = crtcs[o];
if (mode && crtc) {
xfree86: Strip dangling pointers from desiredMode Based on the original patch by Chris Wilson, which was a better fix than mine. We stash a copy of the desiredMode on the crtc so that we can restore it after a vt switch. This copy is a simple memcpy and so also stashes a references to the pointers contained within the desiredMode. Those pointers are freed the next time the outputs are probed and mode list rebuilt, resulting in us chasing those dangling pointers on the next mode switch. ==22787== Invalid read of size 1 ==22787== at 0x40293C2: __GI_strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==22787== by 0x668F875: strdup (strdup.c:42) ==22787== by 0x5DBA00: XNFstrdup (utils.c:1124) ==22787== by 0x4D72ED: xf86DuplicateMode (xf86Modes.c:209) ==22787== by 0x4CA848: xf86CrtcSetModeTransform (xf86Crtc.c:276) ==22787== by 0x4D05B4: xf86SetDesiredModes (xf86Crtc.c:2677) ==22787== by 0xA7479D0: sna_create_screen_resources (sna_driver.c:220) ==22787== by 0x4CB914: xf86CrtcCreateScreenResources (xf86Crtc.c:725) ==22787== by 0x425498: main (main.c:216) ==22787== Address 0x72c60e0 is 0 bytes inside a block of size 9 free'd ==22787== at 0x4027AAE: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==22787== by 0x4A547E: xf86DeleteMode (xf86Mode.c:1984) ==22787== by 0x4CD84F: xf86ProbeOutputModes (xf86Crtc.c:1578) ==22787== by 0x4DC405: xf86RandR12GetInfo12 (xf86RandR12.c:1537) ==22787== by 0x518119: RRGetInfo (rrinfo.c:202) ==22787== by 0x51D997: rrGetScreenResources (rrscreen.c:335) ==22787== by 0x51E0D0: ProcRRGetScreenResources (rrscreen.c:475) ==22787== by 0x513852: ProcRRDispatch (randr.c:493) ==22787== by 0x4346DB: Dispatch (dispatch.c:439) ==22787== by 0x4256E4: main (main.c:287) Signed-off-by: Maarten Lankhorst <maarten.lankhorst@canonical.com> Reported-by: Zdenek Kabelac <zdenek.kabelac@gmail.com> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=36108 Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Keith Packard <keithp@keithp.com>
2012-07-11 16:27:46 +02:00
xf86SaveModeContents(&crtc->desiredMode, mode);
crtc->desiredRotation = output->initial_rotation;
crtc->desiredX = output->initial_x;
crtc->desiredY = output->initial_y;
crtc->desiredTransformPresent = FALSE;
crtc->enabled = TRUE;
memcpy(&crtc->panningTotalArea, &output->initialTotalArea,
sizeof(BoxRec));
memcpy(&crtc->panningTrackingArea, &output->initialTrackingArea,
sizeof(BoxRec));
memcpy(crtc->panningBorder, output->initialBorder,
4 * sizeof(INT16));
output->crtc = crtc;
}
else {
output->crtc = NULL;
}
}
if (scrn->display->virtualX == 0 || scrn->is_gpu) {
/*
* Expand virtual size to cover the current config and potential mode
* switches, if the driver can't enlarge the screen later.
*/
xf86DefaultScreenLimits(scrn, &width, &height, canGrow);
if (have_outputs == FALSE) {
if (width < NO_OUTPUT_DEFAULT_WIDTH &&
height < NO_OUTPUT_DEFAULT_HEIGHT) {
width = NO_OUTPUT_DEFAULT_WIDTH;
height = NO_OUTPUT_DEFAULT_HEIGHT;
}
}
if (!scrn->is_gpu) {
scrn->display->virtualX = width;
scrn->display->virtualY = height;
}
}
if (width > scrn->virtualX)
scrn->virtualX = width;
if (height > scrn->virtualY)
scrn->virtualY = height;
/*
* Make sure the configuration isn't too small.
*/
if (width < config->minWidth || height < config->minHeight)
goto bailout;
/*
* Limit the crtc config to virtual[XY] if the driver can't grow the
* desktop.
*/
if (!canGrow) {
xf86CrtcSetSizeRange(scrn, config->minWidth, config->minHeight,
width, height);
}
xf86SetScrnInfoModes(scrn);
success = TRUE;
bailout:
free(crtcs);
free(modes);
free(enabled);
return success;
}
/*
* Check the CRTC we're going to map each output to vs. it's current
* CRTC. If they don't match, we have to disable the output and the CRTC
* since the driver will have to re-route things.
*/
static void
xf86PrepareOutputs(ScrnInfoPtr scrn)
{
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
int o;
for (o = 0; o < config->num_output; o++) {
xf86OutputPtr output = config->output[o];
#if RANDR_GET_CRTC_INTERFACE
/* Disable outputs that are unused or will be re-routed */
if (!output->funcs->get_crtc ||
output->crtc != (*output->funcs->get_crtc) (output) ||
output->crtc == NULL)
#endif
(*output->funcs->dpms) (output, DPMSModeOff);
}
}
static void
xf86PrepareCrtcs(ScrnInfoPtr scrn)
{
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
int c;
for (c = 0; c < config->num_crtc; c++) {
#if RANDR_GET_CRTC_INTERFACE
xf86CrtcPtr crtc = config->crtc[c];
xf86OutputPtr output = NULL;
uint32_t desired_outputs = 0, current_outputs = 0;
int o;
for (o = 0; o < config->num_output; o++) {
output = config->output[o];
if (output->crtc == crtc)
desired_outputs |= (1 << o);
/* If we can't tell where it's mapped, force it off */
if (!output->funcs->get_crtc) {
desired_outputs = 0;
break;
}
if ((*output->funcs->get_crtc) (output) == crtc)
current_outputs |= (1 << o);
}
/*
* If mappings are different or the CRTC is unused,
* we need to disable it
*/
if (desired_outputs != current_outputs || !desired_outputs)
(*crtc->funcs->dpms) (crtc, DPMSModeOff);
#else
(*crtc->funcs->dpms) (crtc, DPMSModeOff);
#endif
}
}
/*
* Using the desired mode information in each crtc, set
* modes (used in EnterVT functions, or at server startup)
*/
Bool
xf86SetDesiredModes(ScrnInfoPtr scrn)
{
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
xf86CrtcPtr crtc = config->crtc[0];
int enabled = 0, failed = 0;
int c;
/* A driver with this hook will take care of this */
if (!crtc->funcs->set_mode_major) {
xf86PrepareOutputs(scrn);
xf86PrepareCrtcs(scrn);
}
for (c = 0; c < config->num_crtc; c++) {
xf86OutputPtr output = NULL;
int o;
RRTransformPtr transform;
crtc = config->crtc[c];
/* Skip disabled CRTCs */
if (!crtc->enabled)
continue;
if (xf86CompatOutput(scrn) && xf86CompatCrtc(scrn) == crtc)
output = xf86CompatOutput(scrn);
else {
for (o = 0; o < config->num_output; o++)
if (config->output[o]->crtc == crtc) {
output = config->output[o];
break;
}
}
/* paranoia */
if (!output)
continue;
/* Mark that we'll need to re-set the mode for sure */
memset(&crtc->mode, 0, sizeof(crtc->mode));
if (!crtc->desiredMode.CrtcHDisplay) {
DisplayModePtr mode =
xf86OutputFindClosestMode(output, scrn->currentMode);
if (!mode)
return FALSE;
xfree86: Strip dangling pointers from desiredMode Based on the original patch by Chris Wilson, which was a better fix than mine. We stash a copy of the desiredMode on the crtc so that we can restore it after a vt switch. This copy is a simple memcpy and so also stashes a references to the pointers contained within the desiredMode. Those pointers are freed the next time the outputs are probed and mode list rebuilt, resulting in us chasing those dangling pointers on the next mode switch. ==22787== Invalid read of size 1 ==22787== at 0x40293C2: __GI_strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==22787== by 0x668F875: strdup (strdup.c:42) ==22787== by 0x5DBA00: XNFstrdup (utils.c:1124) ==22787== by 0x4D72ED: xf86DuplicateMode (xf86Modes.c:209) ==22787== by 0x4CA848: xf86CrtcSetModeTransform (xf86Crtc.c:276) ==22787== by 0x4D05B4: xf86SetDesiredModes (xf86Crtc.c:2677) ==22787== by 0xA7479D0: sna_create_screen_resources (sna_driver.c:220) ==22787== by 0x4CB914: xf86CrtcCreateScreenResources (xf86Crtc.c:725) ==22787== by 0x425498: main (main.c:216) ==22787== Address 0x72c60e0 is 0 bytes inside a block of size 9 free'd ==22787== at 0x4027AAE: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==22787== by 0x4A547E: xf86DeleteMode (xf86Mode.c:1984) ==22787== by 0x4CD84F: xf86ProbeOutputModes (xf86Crtc.c:1578) ==22787== by 0x4DC405: xf86RandR12GetInfo12 (xf86RandR12.c:1537) ==22787== by 0x518119: RRGetInfo (rrinfo.c:202) ==22787== by 0x51D997: rrGetScreenResources (rrscreen.c:335) ==22787== by 0x51E0D0: ProcRRGetScreenResources (rrscreen.c:475) ==22787== by 0x513852: ProcRRDispatch (randr.c:493) ==22787== by 0x4346DB: Dispatch (dispatch.c:439) ==22787== by 0x4256E4: main (main.c:287) Signed-off-by: Maarten Lankhorst <maarten.lankhorst@canonical.com> Reported-by: Zdenek Kabelac <zdenek.kabelac@gmail.com> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=36108 Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Keith Packard <keithp@keithp.com>
2012-07-11 16:27:46 +02:00
xf86SaveModeContents(&crtc->desiredMode, mode);
crtc->desiredRotation = RR_Rotate_0;
crtc->desiredTransformPresent = FALSE;
crtc->desiredX = 0;
crtc->desiredY = 0;
}
if (crtc->desiredTransformPresent)
transform = &crtc->desiredTransform;
else
transform = NULL;
if (xf86CrtcSetModeTransform
(crtc, &crtc->desiredMode, crtc->desiredRotation, transform,
crtc->desiredX, crtc->desiredY)) {
++enabled;
} else {
for (o = 0; o < config->num_output; o++)
if (config->output[o]->crtc == crtc)
config->output[o]->crtc = NULL;
crtc->enabled = FALSE;
++failed;
}
}
xf86DisableUnusedFunctions(scrn);
return enabled != 0 || failed == 0;
}
/**
* In the current world order, there are lists of modes per output, which may
* or may not include the mode that was asked to be set by XFree86's mode
* selection. Find the closest one, in the following preference order:
*
* - Equality
* - Closer in size to the requested mode, but no larger
* - Closer in refresh rate to the requested mode.
*/
DisplayModePtr
xf86OutputFindClosestMode(xf86OutputPtr output, DisplayModePtr desired)
{
DisplayModePtr best = NULL, scan = NULL;
for (scan = output->probed_modes; scan != NULL; scan = scan->next) {
/* If there's an exact match, we're done. */
if (xf86ModesEqual(scan, desired)) {
best = desired;
break;
}
/* Reject if it's larger than the desired mode. */
if (scan->HDisplay > desired->HDisplay ||
scan->VDisplay > desired->VDisplay) {
continue;
}
/*
* If we haven't picked a best mode yet, use the first
* one in the size range
*/
if (best == NULL) {
best = scan;
continue;
}
/* Find if it's closer to the right size than the current best
* option.
*/
if ((scan->HDisplay > best->HDisplay &&
scan->VDisplay >= best->VDisplay) ||
(scan->HDisplay >= best->HDisplay &&
scan->VDisplay > best->VDisplay)) {
best = scan;
continue;
}
/* Find if it's still closer to the right refresh than the current
* best resolution.
*/
if (scan->HDisplay == best->HDisplay &&
scan->VDisplay == best->VDisplay &&
(fabs(scan->VRefresh - desired->VRefresh) <
fabs(best->VRefresh - desired->VRefresh))) {
best = scan;
}
}
return best;
}
/**
* When setting a mode through XFree86-VidModeExtension or XFree86-DGA,
* take the specified mode and apply it to the crtc connected to the compat
* output. Then, find similar modes for the other outputs, as with the
* InitialConfiguration code above. The goal is to clone the desired
* mode across all outputs that are currently active.
*/
Bool
xf86SetSingleMode(ScrnInfoPtr pScrn, DisplayModePtr desired, Rotation rotation)
{
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
Bool ok = TRUE;
xf86OutputPtr compat_output;
DisplayModePtr compat_mode = NULL;
int c;
/*
* Let the compat output drive the final mode selection
*/
compat_output = xf86CompatOutput(pScrn);
if (compat_output)
compat_mode = xf86OutputFindClosestMode(compat_output, desired);
if (compat_mode)
desired = compat_mode;
for (c = 0; c < config->num_crtc; c++) {
xf86CrtcPtr crtc = config->crtc[c];
DisplayModePtr crtc_mode = NULL;
int o;
if (!crtc->enabled)
continue;
for (o = 0; o < config->num_output; o++) {
xf86OutputPtr output = config->output[o];
DisplayModePtr output_mode;
/* skip outputs not on this crtc */
if (output->crtc != crtc)
continue;
if (crtc_mode) {
output_mode = xf86OutputFindClosestMode(output, crtc_mode);
if (output_mode != crtc_mode)
output->crtc = NULL;
}
else
crtc_mode = xf86OutputFindClosestMode(output, desired);
}
if (!crtc_mode) {
crtc->enabled = FALSE;
continue;
}
if (!xf86CrtcSetModeTransform(crtc, crtc_mode, rotation, NULL, 0, 0))
ok = FALSE;
else {
xfree86: Strip dangling pointers from desiredMode Based on the original patch by Chris Wilson, which was a better fix than mine. We stash a copy of the desiredMode on the crtc so that we can restore it after a vt switch. This copy is a simple memcpy and so also stashes a references to the pointers contained within the desiredMode. Those pointers are freed the next time the outputs are probed and mode list rebuilt, resulting in us chasing those dangling pointers on the next mode switch. ==22787== Invalid read of size 1 ==22787== at 0x40293C2: __GI_strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==22787== by 0x668F875: strdup (strdup.c:42) ==22787== by 0x5DBA00: XNFstrdup (utils.c:1124) ==22787== by 0x4D72ED: xf86DuplicateMode (xf86Modes.c:209) ==22787== by 0x4CA848: xf86CrtcSetModeTransform (xf86Crtc.c:276) ==22787== by 0x4D05B4: xf86SetDesiredModes (xf86Crtc.c:2677) ==22787== by 0xA7479D0: sna_create_screen_resources (sna_driver.c:220) ==22787== by 0x4CB914: xf86CrtcCreateScreenResources (xf86Crtc.c:725) ==22787== by 0x425498: main (main.c:216) ==22787== Address 0x72c60e0 is 0 bytes inside a block of size 9 free'd ==22787== at 0x4027AAE: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==22787== by 0x4A547E: xf86DeleteMode (xf86Mode.c:1984) ==22787== by 0x4CD84F: xf86ProbeOutputModes (xf86Crtc.c:1578) ==22787== by 0x4DC405: xf86RandR12GetInfo12 (xf86RandR12.c:1537) ==22787== by 0x518119: RRGetInfo (rrinfo.c:202) ==22787== by 0x51D997: rrGetScreenResources (rrscreen.c:335) ==22787== by 0x51E0D0: ProcRRGetScreenResources (rrscreen.c:475) ==22787== by 0x513852: ProcRRDispatch (randr.c:493) ==22787== by 0x4346DB: Dispatch (dispatch.c:439) ==22787== by 0x4256E4: main (main.c:287) Signed-off-by: Maarten Lankhorst <maarten.lankhorst@canonical.com> Reported-by: Zdenek Kabelac <zdenek.kabelac@gmail.com> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=36108 Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Keith Packard <keithp@keithp.com>
2012-07-11 16:27:46 +02:00
xf86SaveModeContents(&crtc->desiredMode, crtc_mode);
crtc->desiredRotation = rotation;
crtc->desiredTransformPresent = FALSE;
crtc->desiredX = 0;
crtc->desiredY = 0;
}
}
xf86DisableUnusedFunctions(pScrn);
#ifdef RANDR_12_INTERFACE
xf86RandR12TellChanged(pScrn->pScreen);
#endif
return ok;
}
/**
* Set the DPMS power mode of all outputs and CRTCs.
*
* If the new mode is off, it will turn off outputs and then CRTCs.
* Otherwise, it will affect CRTCs before outputs.
*/
void
xf86DPMSSet(ScrnInfoPtr scrn, int mode, int flags)
{
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
int i;
if (!scrn->vtSema)
return;
if (mode == DPMSModeOff) {
for (i = 0; i < config->num_output; i++) {
xf86OutputPtr output = config->output[i];
if (output->crtc != NULL)
(*output->funcs->dpms) (output, mode);
}
}
for (i = 0; i < config->num_crtc; i++) {
xf86CrtcPtr crtc = config->crtc[i];
if (crtc->enabled)
(*crtc->funcs->dpms) (crtc, mode);
}
if (mode != DPMSModeOff) {
for (i = 0; i < config->num_output; i++) {
xf86OutputPtr output = config->output[i];
if (output->crtc != NULL)
(*output->funcs->dpms) (output, mode);
}
}
}
/**
* Implement the screensaver by just calling down into the driver DPMS hooks.
*
* Even for monitors with no DPMS support, by the definition of our DPMS hooks,
* the outputs will still get disabled (blanked).
*/
Bool
xf86SaveScreen(ScreenPtr pScreen, int mode)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
if (xf86IsUnblank(mode))
xf86DPMSSet(pScrn, DPMSModeOn, 0);
else
xf86DPMSSet(pScrn, DPMSModeOff, 0);
return TRUE;
}
/**
* Disable all inactive crtcs and outputs
*/
void
xf86DisableUnusedFunctions(ScrnInfoPtr pScrn)
{
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
int o, c;
for (o = 0; o < xf86_config->num_output; o++) {
xf86OutputPtr output = xf86_config->output[o];
if (!output->crtc)
(*output->funcs->dpms) (output, DPMSModeOff);
}
for (c = 0; c < xf86_config->num_crtc; c++) {
xf86CrtcPtr crtc = xf86_config->crtc[c];
if (!crtc->enabled) {
crtc->funcs->dpms(crtc, DPMSModeOff);
memset(&crtc->mode, 0, sizeof(crtc->mode));
xf86RotateDestroy(crtc);
crtc->active = FALSE;
}
}
if (pScrn->pScreen)
xf86_crtc_notify(pScrn->pScreen);
if (pScrn->ModeSet)
pScrn->ModeSet(pScrn);
if (pScrn->pScreen) {
if (pScrn->pScreen->isGPU)
xf86CursorResetCursor(pScrn->pScreen->current_master);
else
xf86CursorResetCursor(pScrn->pScreen);
}
}
#ifdef RANDR_12_INTERFACE
#define EDID_ATOM_NAME "EDID"
/**
* Set the RandR EDID property
*/
static void
xf86OutputSetEDIDProperty(xf86OutputPtr output, void *data, int data_len)
{
Atom edid_atom = MakeAtom(EDID_ATOM_NAME, sizeof(EDID_ATOM_NAME) - 1, TRUE);
/* This may get called before the RandR resources have been created */
if (output->randr_output == NULL)
return;
if (data_len != 0) {
RRChangeOutputProperty(output->randr_output, edid_atom, XA_INTEGER, 8,
PropModeReplace, data_len, data, FALSE, TRUE);
}
else {
RRDeleteOutputProperty(output->randr_output, edid_atom);
}
}
#define TILE_ATOM_NAME "TILE"
/* changing this in the future could be tricky as people may hardcode 8 */
#define TILE_PROP_NUM_ITEMS 8
static void
xf86OutputSetTileProperty(xf86OutputPtr output)
{
Atom tile_atom = MakeAtom(TILE_ATOM_NAME, sizeof(TILE_ATOM_NAME) - 1, TRUE);
/* This may get called before the RandR resources have been created */
if (output->randr_output == NULL)
return;
if (output->tile_info.group_id != 0) {
RRChangeOutputProperty(output->randr_output, tile_atom, XA_INTEGER, 32,
PropModeReplace, TILE_PROP_NUM_ITEMS, (uint32_t *)&output->tile_info, FALSE, TRUE);
}
else {
RRDeleteOutputProperty(output->randr_output, tile_atom);
}
}
#endif
/* Pull out a phyiscal size from a detailed timing if available. */
struct det_phySize_parameter {
xf86OutputPtr output;
ddc_quirk_t quirks;
Bool ret;
};
static void
handle_detailed_physical_size(struct detailed_monitor_section
*det_mon, void *data)
{
struct det_phySize_parameter *p;
p = (struct det_phySize_parameter *) data;
if (p->ret == TRUE)
return;
xf86DetTimingApplyQuirks(det_mon, p->quirks,
p->output->MonInfo->features.hsize,
p->output->MonInfo->features.vsize);
if (det_mon->type == DT &&
det_mon->section.d_timings.h_size != 0 &&
det_mon->section.d_timings.v_size != 0) {
/* some sanity checking for aspect ratio:
assume any h / v (or v / h) > 2.4 to be bogus.
This would even include cinemascope */
if (((det_mon->section.d_timings.h_size * 5) <
(det_mon->section.d_timings.v_size * 12)) &&
((det_mon->section.d_timings.v_size * 5) <
(det_mon->section.d_timings.h_size * 12))) {
p->output->mm_width = det_mon->section.d_timings.h_size;
p->output->mm_height = det_mon->section.d_timings.v_size;
p->ret = TRUE;
} else
xf86DrvMsg(p->output->scrn->scrnIndex, X_WARNING,
"Output %s: Strange aspect ratio (%i/%i), "
"consider adding a quirk\n", p->output->name,
det_mon->section.d_timings.h_size,
det_mon->section.d_timings.v_size);
}
}
Bool
xf86OutputParseKMSTile(const char *tile_data, int tile_length,
struct xf86CrtcTileInfo *tile_info)
{
int ret;
ret = sscanf(tile_data, "%d:%d:%d:%d:%d:%d:%d:%d",
&tile_info->group_id,
&tile_info->flags,
&tile_info->num_h_tile,
&tile_info->num_v_tile,
&tile_info->tile_h_loc,
&tile_info->tile_v_loc,
&tile_info->tile_h_size,
&tile_info->tile_v_size);
if (ret != 8)
return FALSE;
return TRUE;
}
void
xf86OutputSetTile(xf86OutputPtr output, struct xf86CrtcTileInfo *tile_info)
{
if (tile_info)
output->tile_info = *tile_info;
else
memset(&output->tile_info, 0, sizeof(output->tile_info));
#ifdef RANDR_12_INTERFACE
xf86OutputSetTileProperty(output);
#endif
}
/**
* Set the EDID information for the specified output
*/
void
xf86OutputSetEDID(xf86OutputPtr output, xf86MonPtr edid_mon)
{
ScrnInfoPtr scrn = output->scrn;
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
Bool debug_modes = config->debug_modes || xf86Initialising;
#ifdef RANDR_12_INTERFACE
int size;
#endif
free(output->MonInfo);
output->MonInfo = edid_mon;
output->mm_width = 0;
output->mm_height = 0;
if (debug_modes) {
xf86DrvMsg(scrn->scrnIndex, X_INFO, "EDID for output %s\n",
output->name);
xf86PrintEDID(edid_mon);
}
/* Set the DDC properties for the 'compat' output */
/* GPU screens don't have a root window */
if (output == xf86CompatOutput(scrn) && !scrn->is_gpu)
xf86SetDDCproperties(scrn, edid_mon);
#ifdef RANDR_12_INTERFACE
/* Set the RandR output properties */
size = 0;
if (edid_mon) {
if (edid_mon->ver.version == 1) {
size = 128;
if (edid_mon->flags & EDID_COMPLETE_RAWDATA)
size += edid_mon->no_sections * 128;
}
else if (edid_mon->ver.version == 2)
size = 256;
}
xf86OutputSetEDIDProperty(output, edid_mon ? edid_mon->rawData : NULL,
size);
#endif
if (edid_mon) {
struct det_phySize_parameter p;
p.output = output;
p.quirks = xf86DDCDetectQuirks(scrn->scrnIndex, edid_mon, FALSE);
p.ret = FALSE;
xf86ForEachDetailedBlock(edid_mon, handle_detailed_physical_size, &p);
/* if no mm size is available from a detailed timing, check the max size field */
if ((!output->mm_width || !output->mm_height) &&
(edid_mon->features.hsize && edid_mon->features.vsize)) {
output->mm_width = edid_mon->features.hsize * 10;
output->mm_height = edid_mon->features.vsize * 10;
}
}
}
/**
* Return the list of modes supported by the EDID information
* stored in 'output'
*/
DisplayModePtr
xf86OutputGetEDIDModes(xf86OutputPtr output)
{
ScrnInfoPtr scrn = output->scrn;
xf86MonPtr edid_mon = output->MonInfo;
if (!edid_mon)
return NULL;
return xf86DDCGetModes(scrn->scrnIndex, edid_mon);
}
2008-06-21 22:07:54 +02:00
/* maybe we should care about DDC1? meh. */
xf86MonPtr
xf86OutputGetEDID(xf86OutputPtr output, I2CBusPtr pDDCBus)
{
ScrnInfoPtr scrn = output->scrn;
xf86MonPtr mon;
api: rework the X server driver API to avoid global arrays. This is a squash merge containing all the API changes, as well as the video ABI bump. Its been squashed to make bisection easier. Full patch log below: commit b202738bbf0c5a1c1172767119c2c71f1e7f8070 Author: Aaron Plattner <aplattner@nvidia.com> Date: Mon May 14 15:16:11 2012 -0700 xfree86: Bump video ABI to 13.0 The ABI was broken by changes to convert from screen index numbers to ScreenPtr / ScrnInfoPtr in various structures and function signatures. Signed-off-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Dave Airlie <airlied@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 3d5f7d9f8d408bcad3f83277d255f25d3b0edbf3 Author: Dave Airlie <airlied@redhat.com> Date: Thu May 24 10:56:57 2012 +0100 xf86: xf86ClearEntityListForScreen should take a pScrn When adding GPU screens this make life easier. (also fix comment, as pointed out by Alan) Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net> Signed-off-by: Dave Airlie <airlied@redhat.com> commit afee8b5ab4501597ecc1ade34124d7ca227ab055 Author: Dave Airlie <airlied@redhat.com> Date: Thu May 24 07:07:32 2012 +0100 xf86i2c: add pscrn for drivers to use This just adds a pScrn pointer into the struct for the drivers to use instead of scrnIndex. Mostly scrnIndex is used for logging, but some drivers use it to lookup xf86Screens, so let them stash a pScrn instead. Removing the scrnIndex is a bit more involved and I'm not sure its worth the effort. Doing i2c in the X server is legacy code as far as I'm concerned. Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit ea5092f1f679691d187f1eee9427e6057beec56e Author: Dave Airlie <airlied@redhat.com> Date: Wed May 23 19:25:20 2012 +0100 dix/gc: consolidate GC object creation in one place The standard GC create and scratch GC create were 90% the same really, and I have a need in the future for creating GC objects without the other bits, so wanted to avoid a third copy. Reviewed-by: Keith Packard <keithp@keithp.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 3d91482ea9b4883e64e496f2768168e0ffa21ba1 Author: Dave Airlie <airlied@redhat.com> Date: Wed May 23 10:24:06 2012 +0100 xf86: add a define to denote the new non-index interfaces are being used This can be used by drivers to provide compatible APIs. Reviewed-by: Keith Packard <keithp@keithp.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 37c3ae3e6cd4f3dedc72f371096d6743f8f99df3 Author: Dave Airlie <airlied@redhat.com> Date: Wed May 23 15:09:12 2012 +0100 dix: make Create/Free scratch pixmaps take a ScreenPtr While technically an API/ABI change I doubt anyone uses it, but it helps in splitting screens up. Reviewed-by: Keith Packard <keithp@keithp.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 75f2062a3fe94f04764ecc7d2ff2fbbeccb9da60 Author: Dave Airlie <airlied@redhat.com> Date: Wed May 23 14:57:55 2012 +0100 xf86/xv: remove scrnIndexfrom xf86FindXvOptions. Move this interface to taking an ScrnInfoPtr. Reviewed-by: Keith Packard <keithp@keithp.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit f80c2374f40ea7b2ee0556e2e76cc07406f3d843 Author: Dave Airlie <airlied@redhat.com> Date: Wed May 23 14:53:59 2012 +0100 xf86: make xf86DeleteScreen take a ScrnInfoPtr (v2) stop passing indices into this function. v2: drop flags argument. Reviewed-by: Keith Packard <keithp@keithp.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 58824e414f35682435f15bfe6c4b656bd90b9235 Author: Dave Airlie <airlied@redhat.com> Date: Wed May 23 14:48:09 2012 +0100 xf86: fix xf86IsScreenPrimary interface to take a pScrn (API/ABI) Reviewed-by: Keith Packard <keithp@keithp.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 6b4fc1f9d391bcdf7ca288766e49bce60f4635cd Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 14:18:59 2012 +0100 xserver: convert block/wakeup handlers to passing ScreenPtr (ABI/API) (v2) Instead of passing an index, pass the actual ScreenPtr. This allows more moving towards not abusing xf86Screens + screenInfo. v2: drop the blockData/wakeupData args as per ajax's suggestion., fix docs. Reviewed-by: Keith Packard <keithp@keithp.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 790d003de20fb47674420a24dadd92412d78620d Author: Dave Airlie <airlied@gmail.com> Date: Wed Apr 11 09:53:14 2012 +0100 xf86/common: remove some more pScrn->pScreen uses remove some more conversions that appeared after api cleanups. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit aac85e18d1dd093f2cad6bd29375e40bd7af0b8f Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 16:34:53 2012 +0100 ddc: change API to take ScrnInfoPtr (v2) This removes all xf86Screens usage from ddc code, it modifies the API for some functions to avoid taking indices. v2: address Alan's comments about dropping DDC2Init parameter. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit fe3f57b6eaf6860a33876a54f9439f69578f03a5 Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 16:31:26 2012 +0100 vbe: don't use index for VBEInterpretPanelID (API) Remove use of xf86screens from vbe module. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit abf1965f4ed91529036d3fdb470d6a3ce6f29675 Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 16:25:11 2012 +0100 int10/vbe: don't use xf86Screens. (ABI) (v3) Pass the ScrnInfoPtr instead of the index in the int10 struct. This saves us using it to dereference xf86Screens. v2: address Alan's comment to fix struct alignment. v3: squash in all the int10 fixes, test the vm86 code builds, after comments by Keith. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 23cca612b4fb5efc33683c7624b803b457387e3d Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 15:30:18 2012 +0100 xserver: drop index argument to ScreenInit (ABI/API) (v2) This drops the index argument, its the same as pScreen->myNum, and its the last major index abuse I can find. v2: address Alan's review - update docs, fix xwin/xnest/darwin Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 40d360e2d7e832407f3ed64e3a02c27ecc89a960 Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 15:23:01 2012 +0100 xf86: migrate PointerMoved from index to ScrnInfoPtr (ABI/API) This migrates PointerMoved from an index to ScrnInfoPtr. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit aa60a2f38679d0eeb979a9c2648c9bc771409bf9 Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 15:20:46 2012 +0100 xf86: migrate PMEvent to a ScrnInfoPtr (ABI/API) This migrates the PMEvent from index to ScrnInfoPtr. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit d3f28ef44371ed4a039ffc5dd7eb6408d1269ba2 Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 15:18:30 2012 +0100 xf86: migrate SetDGAMode from index to ScrnInfoPtr (ABI/API) This migrates the SetDGAMode callback from an index to ScrnInfoPtr. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit baf5e4818a74f2b68c3dfdcc56f54322351039a0 Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 15:14:11 2012 +0100 xf86: migrate ChangeGamma from index to ScrnInfoPtr (ABI/API) (v2) This migrates the ChangeGamma interface to avoid passing a index. v2: fix xf86RandR12.c + xf86cmap.c call Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 51e5f90ada929d6b23176090badbb42fdb3fa550 Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 15:11:09 2012 +0100 xf86/exa: migrate index to screen types for EnableDisableFBAccess (ABI/API) The EXA interface migrates to ScreenPtr, and the xf86 interface migrated to ScrnInfoPtr. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 94f1f21d17e86f96d4a54292a399160950087675 Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 15:02:11 2012 +0100 xf86: migrate ValidMode callback to ScrnInfoPtr (ABI/API) This migrates the ValidMode to passing a ScrnInfoPtr instead of an index. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 3f8f18198fed4f39ec805b508a3482e91eea26b2 Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 14:59:46 2012 +0100 xf86: migrate SwitchMode to taking ScrnInfoPtr (ABI/API) (v2) This migrate the SwitchMode interface to take a ScrnInfoPtr instead of an index. v2: drop flags. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit d06a038a5c49328ab3a8d969d24f9fcd22c63202 Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 14:50:37 2012 +0100 xf86: move AdjustFrame to passing ScrnInfoPtr (ABI/API) (v2) This converts AdjustFrame code paths to passing a ScrnInfoPtr instead of an integer index. v2: drop flags args. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 53d2f8608ffd4090d08e7d5cf2e92fb954959b90 Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 14:41:27 2012 +0100 xf86: modify FreeScreen callback to take pScrn instead of index. (ABI/API) (v2) Another index->pScrn conversion. v2: drop flags arg. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 60db37c0b247052e0f5c54b1921fe58a3609c2e3 Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 14:35:41 2012 +0100 xf86: change EnterVT/LeaveVT to take a ScrnInfoPtr (ABI/API break) (v2) This modifies the EnterVT/LeaveVT interfaces to take a ScrnInfoPtr instead of an index into xf86Screens. This allows dropping more public dereferences of the xf86Screens and screenInfo. v2: drop flags args as suggested by Keith, fix docs. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> commit 06729dbbc804a20242e6499f446acb5d94023c3c Author: Dave Airlie <airlied@gmail.com> Date: Tue Apr 10 14:04:59 2012 +0100 xserver: remove index from CloseScreen (API/ABI breakage) This drops the index from the CloseScreen callback, its always been useless really, since the pScreen contains it. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Acked-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
2012-06-05 14:22:18 +02:00
mon = xf86DoEEDID(scrn, pDDCBus, TRUE);
if (mon)
2008-06-21 22:07:54 +02:00
xf86DDCApplyQuirks(scrn->scrnIndex, mon);
return mon;
}
static const char *_xf86ConnectorNames[] = {
"None", "VGA", "DVI-I", "DVI-D",
"DVI-A", "Composite", "S-Video",
"Component", "LFP", "Proprietary",
"HDMI", "DisplayPort",
};
const char *
xf86ConnectorGetName(xf86ConnectorType connector)
{
return _xf86ConnectorNames[connector];
}
static void
x86_crtc_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b)
{
dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1;
dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2;
dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1;
dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2;
if (dest->x1 >= dest->x2 || dest->y1 >= dest->y2)
dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0;
}
static void
x86_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box)
{
if (crtc->enabled) {
crtc_box->x1 = crtc->x;
crtc_box->x2 = crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation);
crtc_box->y1 = crtc->y;
crtc_box->y2 = crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation);
}
else
crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0;
}
static int
xf86_crtc_box_area(BoxPtr box)
{
return (int) (box->x2 - box->x1) * (int) (box->y2 - box->y1);
}
#ifdef XV
/*
* Return the crtc covering 'box'. If two crtcs cover a portion of
* 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc
* with greater coverage
*/
static xf86CrtcPtr
xf86_covering_crtc(ScrnInfoPtr pScrn,
BoxPtr box, xf86CrtcPtr desired, BoxPtr crtc_box_ret)
{
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
xf86CrtcPtr crtc, best_crtc;
int coverage, best_coverage;
int c;
BoxRec crtc_box, cover_box;
best_crtc = NULL;
best_coverage = 0;
crtc_box_ret->x1 = 0;
crtc_box_ret->x2 = 0;
crtc_box_ret->y1 = 0;
crtc_box_ret->y2 = 0;
for (c = 0; c < xf86_config->num_crtc; c++) {
crtc = xf86_config->crtc[c];
x86_crtc_box(crtc, &crtc_box);
x86_crtc_box_intersect(&cover_box, &crtc_box, box);
coverage = xf86_crtc_box_area(&cover_box);
if (coverage && crtc == desired) {
*crtc_box_ret = crtc_box;
return crtc;
}
else if (coverage > best_coverage) {
*crtc_box_ret = crtc_box;
best_crtc = crtc;
best_coverage = coverage;
}
}
return best_crtc;
}
/*
* For overlay video, compute the relevant CRTC and
* clip video to that.
*
* returning FALSE means there was a memory failure of some kind,
* not that the video shouldn't be displayed
*/
Bool
xf86_crtc_clip_video_helper(ScrnInfoPtr pScrn,
xf86CrtcPtr * crtc_ret,
xf86CrtcPtr desired_crtc,
BoxPtr dst,
INT32 *xa,
INT32 *xb,
INT32 *ya,
INT32 *yb, RegionPtr reg, INT32 width, INT32 height)
{
Bool ret;
RegionRec crtc_region_local;
RegionPtr crtc_region = reg;
if (crtc_ret) {
BoxRec crtc_box;
xf86CrtcPtr crtc = xf86_covering_crtc(pScrn, dst,
desired_crtc,
&crtc_box);
if (crtc) {
RegionInit(&crtc_region_local, &crtc_box, 1);
crtc_region = &crtc_region_local;
RegionIntersect(crtc_region, crtc_region, reg);
}
*crtc_ret = crtc;
}
ret = xf86XVClipVideoHelper(dst, xa, xb, ya, yb,
crtc_region, width, height);
if (crtc_region != reg)
RegionUninit(&crtc_region_local);
return ret;
}
#endif
xf86_crtc_notify_proc_ptr
xf86_wrap_crtc_notify(ScreenPtr screen, xf86_crtc_notify_proc_ptr new)
{
if (xf86CrtcConfigPrivateIndex != -1) {
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
xf86_crtc_notify_proc_ptr old;
old = config->xf86_crtc_notify;
config->xf86_crtc_notify = new;
return old;
}
return NULL;
}
void
xf86_unwrap_crtc_notify(ScreenPtr screen, xf86_crtc_notify_proc_ptr old)
{
if (xf86CrtcConfigPrivateIndex != -1) {
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
config->xf86_crtc_notify = old;
}
}
void
xf86_crtc_notify(ScreenPtr screen)
{
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
if (config->xf86_crtc_notify)
config->xf86_crtc_notify(screen);
}
Bool
xf86_crtc_supports_gamma(ScrnInfoPtr pScrn)
{
if (xf86CrtcConfigPrivateIndex != -1) {
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
xf86CrtcPtr crtc;
/* for multiple drivers loaded we need this */
if (!xf86_config)
return FALSE;
if (xf86_config->num_crtc == 0)
return FALSE;
crtc = xf86_config->crtc[0];
return crtc->funcs->gamma_set != NULL;
}
return FALSE;
}
void
xf86ProviderSetup(ScrnInfoPtr scrn,
const xf86ProviderFuncsRec *funcs, const char *name)
{
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
assert(!xf86_config->name);
assert(name);
xf86_config->name = strdup(name);
xf86_config->provider_funcs = funcs;
#ifdef RANDR_12_INTERFACE
xf86_config->randr_provider = NULL;
#endif
}
void
xf86DetachAllCrtc(ScrnInfoPtr scrn)
{
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
int i;
for (i = 0; i < xf86_config->num_crtc; i++) {
xf86CrtcPtr crtc = xf86_config->crtc[i];
if (crtc->randr_crtc)
RRCrtcDetachScanoutPixmap(crtc->randr_crtc);
/* dpms off */
(*crtc->funcs->dpms) (crtc, DPMSModeOff);
/* force a reset the next time its used */
crtc->randr_crtc->mode = NULL;
crtc->mode.HDisplay = 0;
crtc->x = crtc->y = 0;
}
}