xenocara/driver/xf86-video-ati/src/radeon_mergedfb.c
2006-11-26 20:00:15 +00:00

2095 lines
65 KiB
C

/* $XFree86$ */
/*
* Copyright 2003 Alex Deucher.
*
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation on the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT. IN NO EVENT SHALL ALEX DEUCHER, OR ANY OTHER
* CONTRIBUTORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/*
* Authors:
* Alex Deucher <agd5f@yahoo.com>
* Based, in large part, on the sis driver by Thomas Winischhofer.
*/
#include <string.h>
#include <stdio.h>
#include "xf86.h"
#include "xf86Priv.h"
#include "xf86Resources.h"
#include "xf86_OSproc.h"
#include "extnsionst.h" /* required */
#include <X11/extensions/panoramiXproto.h> /* required */
#include "dixstruct.h"
#include "vbe.h"
#include "radeon.h"
#include "radeon_reg.h"
#include "radeon_macros.h"
#include "radeon_mergedfb.h"
/* psuedo xinerama support */
static unsigned char RADEONXineramaReqCode = 0;
int RADEONXineramaPixWidth = 0;
int RADEONXineramaPixHeight = 0;
int RADEONXineramaNumScreens = 0;
RADEONXineramaData *RADEONXineramadataPtr = NULL;
static int RADEONXineramaGeneration;
Bool RADEONnoPanoramiXExtension = TRUE;
int RADEONProcXineramaQueryVersion(ClientPtr client);
int RADEONProcXineramaGetState(ClientPtr client);
int RADEONProcXineramaGetScreenCount(ClientPtr client);
int RADEONProcXineramaGetScreenSize(ClientPtr client);
int RADEONProcXineramaIsActive(ClientPtr client);
int RADEONProcXineramaQueryScreens(ClientPtr client);
int RADEONSProcXineramaDispatch(ClientPtr client);
static void
RADEONChooseCursorCRTC(ScrnInfoPtr pScrn1, int x, int y);
/* mergedfb functions */
/* Helper function for CRT2 monitor vrefresh/hsync options
* (Taken from mga, sis drivers)
*/
int
RADEONStrToRanges(range *r, char *s, int max)
{
float num = 0.0;
int rangenum = 0;
Bool gotdash = FALSE;
Bool nextdash = FALSE;
char* strnum = NULL;
do {
switch(*s) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '.':
if(strnum == NULL) {
strnum = s;
gotdash = nextdash;
nextdash = FALSE;
}
break;
case '-':
case ' ':
case 0:
if(strnum == NULL) break;
sscanf(strnum, "%f", &num);
strnum = NULL;
if(gotdash)
r[rangenum - 1].hi = num;
else {
r[rangenum].lo = num;
r[rangenum].hi = num;
rangenum++;
}
if(*s == '-') nextdash = (rangenum != 0);
else if(rangenum >= max) return rangenum;
break;
default :
return 0;
}
} while(*(s++) != 0);
return rangenum;
}
/* Copy and link two modes (i, j) for merged-fb mode
* (Taken from mga, sis drivers)
* Copys mode i, merges j to copy of i, links the result to dest, and returns it.
* Links i and j in Private record.
* If dest is NULL, return value is copy of i linked to itself.
* For mergedfb auto-config, we only check the dimension
* against virtualX/Y, if they were user-provided.
*/
static DisplayModePtr
RADEONCopyModeNLink(ScrnInfoPtr pScrn, DisplayModePtr dest,
DisplayModePtr i, DisplayModePtr j,
RADEONScrn2Rel srel)
{
DisplayModePtr mode;
int dx = 0,dy = 0;
RADEONInfoPtr info = RADEONPTR(pScrn);
if(!((mode = xalloc(sizeof(DisplayModeRec))))) return dest;
memcpy(mode, i, sizeof(DisplayModeRec));
if(!((mode->Private = xalloc(sizeof(RADEONMergedDisplayModeRec))))) {
xfree(mode);
return dest;
}
((RADEONMergedDisplayModePtr)mode->Private)->CRT1 = i;
((RADEONMergedDisplayModePtr)mode->Private)->CRT2 = j;
((RADEONMergedDisplayModePtr)mode->Private)->CRT2Position = srel;
mode->PrivSize = 0;
switch(srel) {
case radeonLeftOf:
case radeonRightOf:
if(!(pScrn->display->virtualX)) {
dx = i->HDisplay + j->HDisplay;
} else {
dx = min(pScrn->virtualX, i->HDisplay + j->HDisplay);
}
dx -= mode->HDisplay;
if(!(pScrn->display->virtualY)) {
dy = max(i->VDisplay, j->VDisplay);
} else {
dy = min(pScrn->virtualY, max(i->VDisplay, j->VDisplay));
}
dy -= mode->VDisplay;
break;
case radeonAbove:
case radeonBelow:
if(!(pScrn->display->virtualY)) {
dy = i->VDisplay + j->VDisplay;
} else {
dy = min(pScrn->virtualY, i->VDisplay + j->VDisplay);
}
dy -= mode->VDisplay;
if(!(pScrn->display->virtualX)) {
dx = max(i->HDisplay, j->HDisplay);
} else {
dx = min(pScrn->virtualX, max(i->HDisplay, j->HDisplay));
}
dx -= mode->HDisplay;
break;
case radeonClone:
if(!(pScrn->display->virtualX)) {
dx = max(i->HDisplay, j->HDisplay);
} else {
dx = min(pScrn->virtualX, max(i->HDisplay, j->HDisplay));
}
dx -= mode->HDisplay;
if(!(pScrn->display->virtualY)) {
dy = max(i->VDisplay, j->VDisplay);
} else {
dy = min(pScrn->virtualY, max(i->VDisplay, j->VDisplay));
}
dy -= mode->VDisplay;
break;
}
mode->HDisplay += dx;
mode->HSyncStart += dx;
mode->HSyncEnd += dx;
mode->HTotal += dx;
mode->VDisplay += dy;
mode->VSyncStart += dy;
mode->VSyncEnd += dy;
mode->VTotal += dy;
/* This is needed for not generating negative refesh rates in xrandr with the
faked DotClock below
*/
if (!(mode->VRefresh))
mode->VRefresh = mode->Clock * 1000.0 / mode->HTotal / mode->VTotal;
/* Provide a sophisticated fake DotClock in order to trick the vidmode
* extension to allow selecting among a number of modes whose merged result
* looks identical but consists of different modes for CRT1 and CRT2
*/
mode->Clock = (((i->Clock >> 3) + i->HTotal) << 16) | ((j->Clock >> 2) + j->HTotal);
mode->Clock ^= ((i->VTotal << 19) | (j->VTotal << 3));
if( ((mode->HDisplay * ((pScrn->bitsPerPixel + 7) / 8) * mode->VDisplay) >
(pScrn->videoRam * 1024)) ||
(mode->HDisplay > 8191) ||
(mode->VDisplay > 8191) ) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Skipped \"%s\" (%dx%d), not enough video RAM or beyond hardware specs\n",
mode->name, mode->HDisplay, mode->VDisplay);
xfree(mode->Private);
xfree(mode);
return dest;
}
if(srel != radeonClone) {
info->AtLeastOneNonClone = TRUE;
}
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Merged \"%s\" (%dx%d) and \"%s\" (%dx%d) to %dx%d%s\n",
i->name, i->HDisplay, i->VDisplay, j->name, j->HDisplay, j->VDisplay,
mode->HDisplay, mode->VDisplay, (srel == radeonClone) ? " (Clone)" : "");
mode->next = mode;
mode->prev = mode;
if(dest) {
mode->next = dest->next; /* Insert node after "dest" */
dest->next->prev = mode;
mode->prev = dest;
dest->next = mode;
}
return mode;
}
/* Helper function to find a mode from a given name
* (Taken from mga, sis drivers)
*/
static DisplayModePtr
RADEONGetModeFromName(char* str, DisplayModePtr i)
{
DisplayModePtr c = i;
if(!i) return NULL;
do {
if(strcmp(str, c->name) == 0) return c;
c = c->next;
} while(c != i);
return NULL;
}
static DisplayModePtr
RADEONFindWidestTallestMode(DisplayModePtr i, Bool tallest)
{
DisplayModePtr c = i, d = NULL;
int max = 0;
if(!i) return NULL;
do {
if(tallest) {
if(c->VDisplay > max) {
max = c->VDisplay;
d = c;
}
} else {
if(c->HDisplay > max) {
max = c->HDisplay;
d = c;
}
}
c = c->next;
} while(c != i);
return d;
}
static void
RADEONFindWidestTallestCommonMode(DisplayModePtr i, DisplayModePtr j, Bool tallest,
DisplayModePtr *a, DisplayModePtr *b)
{
DisplayModePtr c = i, d;
int max = 0;
Bool foundone;
(*a) = (*b) = NULL;
if(!i || !j) return;
do {
d = j;
foundone = FALSE;
do {
if( (c->HDisplay == d->HDisplay) &&
(c->VDisplay == d->VDisplay) ) {
foundone = TRUE;
break;
}
d = d->next;
} while(d != j);
if(foundone) {
if(tallest) {
if(c->VDisplay > max) {
max = c->VDisplay;
(*a) = c;
(*b) = d;
}
} else {
if(c->HDisplay > max) {
max = c->HDisplay;
(*a) = c;
(*b) = d;
}
}
}
c = c->next;
} while(c != i);
}
static DisplayModePtr
RADEONGenerateModeListFromLargestModes(ScrnInfoPtr pScrn,
DisplayModePtr i, DisplayModePtr j,
RADEONScrn2Rel srel)
{
RADEONInfoPtr info = RADEONPTR(pScrn);
DisplayModePtr mode1 = NULL;
DisplayModePtr mode2 = NULL;
DisplayModePtr mode3 = NULL;
DisplayModePtr mode4 = NULL;
DisplayModePtr result = NULL;
info->AtLeastOneNonClone = FALSE;
/* Now build a default list of MetaModes.
* - Non-clone: If the user enabled NonRectangular, we use the
* largest mode for each CRT1 and CRT2. If not, we use the largest
* common mode for CRT1 and CRT2 (if available). Additionally, and
* regardless if the above, we produce a clone mode consisting of
* the largest common mode (if available) in order to use DGA.
* - Clone: If the (global) CRT2Position is Clone, we use the
* largest common mode if available, otherwise the first two modes
* in each list.
*/
switch(srel) {
case radeonLeftOf:
case radeonRightOf:
mode1 = RADEONFindWidestTallestMode(i, FALSE);
mode2 = RADEONFindWidestTallestMode(j, FALSE);
RADEONFindWidestTallestCommonMode(i, j, FALSE, &mode3, &mode4);
break;
case radeonAbove:
case radeonBelow:
mode1 = RADEONFindWidestTallestMode(i, TRUE);
mode2 = RADEONFindWidestTallestMode(j, TRUE);
RADEONFindWidestTallestCommonMode(i, j, TRUE, &mode3, &mode4);
break;
case radeonClone:
RADEONFindWidestTallestCommonMode(i, j, FALSE, &mode3, &mode4);
if(mode3 && mode4) {
mode1 = mode3;
mode2 = mode4;
} else {
mode1 = i;
mode2 = j;
}
}
if(srel != radeonClone) {
if(mode3 && mode4 && !info->NonRect) {
mode1 = mode3;
mode2 = mode2;
}
}
if(mode1 && mode2) {
result = RADEONCopyModeNLink(pScrn, result, mode1, mode2, srel);
}
if(srel != radeonClone) {
if(mode3 && mode4) {
result = RADEONCopyModeNLink(pScrn, result, mode3, mode4, radeonClone);
}
}
return result;
}
/* Generate the merged-fb mode modelist
* (Taken from mga, sis drivers)
*/
static DisplayModePtr
RADEONGenerateModeListFromMetaModes(ScrnInfoPtr pScrn, char* str,
DisplayModePtr i, DisplayModePtr j,
RADEONScrn2Rel srel)
{
char* strmode = str;
char modename[256];
Bool gotdash = FALSE;
char gotsep = 0;
RADEONScrn2Rel sr;
DisplayModePtr mode1 = NULL;
DisplayModePtr mode2 = NULL;
DisplayModePtr result = NULL;
int myslen;
RADEONInfoPtr info = RADEONPTR(pScrn);
info->AtLeastOneNonClone = FALSE;
do {
switch(*str) {
case 0:
case '-':
case '+':
case ' ':
case ',':
case ';':
if(strmode != str) {
myslen = str - strmode;
if(myslen > 255) myslen = 255;
strncpy(modename, strmode, myslen);
modename[myslen] = 0;
if(gotdash) {
if(mode1 == NULL) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Error parsing MetaModes parameter\n");
return NULL;
}
mode2 = RADEONGetModeFromName(modename, j);
if(!mode2) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"Mode \"%s\" is not a supported mode for CRT2\n", modename);
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"\t(Skipping metamode \"%s%c%s\")\n", mode1->name, gotsep, modename);
mode1 = NULL;
gotsep = 0;
}
} else {
mode1 = RADEONGetModeFromName(modename, i);
if(!mode1) {
char* tmps = str;
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"Mode \"%s\" is not a supported mode for CRT1\n", modename);
while(*tmps == ' ' || *tmps == ';') tmps++;
/* skip the next mode */
if(*tmps == '-' || *tmps == '+' || *tmps == ',') {
tmps++;
/* skip spaces */
while(*tmps == ' ' || *tmps == ';') tmps++;
/* skip modename */
while(*tmps && *tmps != ' ' && *tmps != ';' && *tmps != '-' && *tmps != '+' && *tmps != ',') tmps++;
myslen = tmps - strmode;
if(myslen > 255) myslen = 255;
strncpy(modename,strmode,myslen);
modename[myslen] = 0;
str = tmps-1;
}
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"\t(Skipping metamode \"%s\")\n", modename);
mode1 = NULL;
gotsep = 0;
}
}
gotdash = FALSE;
}
strmode = str + 1;
gotdash |= (*str == '-' || *str == '+' || *str == ',');
if (*str == '-' || *str == '+' || *str == ',')
gotsep = *str;
if(*str != 0) break;
/* Fall through otherwise */
default:
if(!gotdash && mode1) {
sr = srel;
if(gotsep == '+') sr = radeonClone;
if(!mode2) {
mode2 = RADEONGetModeFromName(mode1->name, j);
sr = radeonClone;
}
if(!mode2) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"Mode \"%s\" is not a supported mode for CRT2\n", mode1->name);
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"\t(Skipping metamode \"%s\")\n", modename);
mode1 = NULL;
} else {
result = RADEONCopyModeNLink(pScrn, result, mode1, mode2, sr);
mode1 = NULL;
mode2 = NULL;
}
gotsep = 0;
}
break;
}
} while(*(str++) != 0);
return result;
}
DisplayModePtr
RADEONGenerateModeList(ScrnInfoPtr pScrn, char* str,
DisplayModePtr i, DisplayModePtr j,
RADEONScrn2Rel srel)
{
RADEONInfoPtr info = RADEONPTR(pScrn);
if(str != NULL) {
return(RADEONGenerateModeListFromMetaModes(pScrn, str, i, j, srel));
} else {
if (srel == radeonClone ) {
DisplayModePtr p, q, result = NULL;
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Clone mode, list all common modes\n");
for (p = i; p->next != i; p = p->next)
for (q = j; q->next != j; q = q->next)
if ((p->HDisplay == q->HDisplay) &&
(p->VDisplay == q->VDisplay))
result = RADEONCopyModeNLink(pScrn, result, p, q, srel);
return result;
} else {
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"No MetaModes given, linking %s modes by default\n",
(info->NonRect ?
(((srel == radeonLeftOf) || (srel == radeonRightOf)) ? "widest" : "tallest")
:
(((srel == radeonLeftOf) || (srel == radeonRightOf)) ? "widest common" : "tallest common")) );
return(RADEONGenerateModeListFromLargestModes(pScrn, i, j, srel));
}
}
}
void
RADEONRecalcDefaultVirtualSize(ScrnInfoPtr pScrn)
{
RADEONInfoPtr info = RADEONPTR(pScrn);
DisplayModePtr mode, bmode;
int maxh, maxv;
static const char *str = "MergedFB: Virtual %s %d\n";
static const char *errstr = "Virtual %s to small for given CRT2Position offset\n";
mode = bmode = pScrn->modes;
maxh = maxv = 0;
do {
if(mode->HDisplay > maxh) maxh = mode->HDisplay;
if(mode->VDisplay > maxv) maxv = mode->VDisplay;
mode = mode->next;
} while(mode != bmode);
maxh += info->CRT1XOffs + info->CRT2XOffs;
maxv += info->CRT1YOffs + info->CRT2YOffs;
if(!(pScrn->display->virtualX)) {
if(maxh > 8191) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Virtual width with CRT2Position offset beyond hardware specs\n");
info->CRT1XOffs = info->CRT2XOffs = 0;
maxh -= (info->CRT1XOffs + info->CRT2XOffs);
}
pScrn->virtualX = maxh;
pScrn->displayWidth = maxh;
xf86DrvMsg(pScrn->scrnIndex, X_PROBED, str, "width", maxh);
} else {
if(maxh < pScrn->display->virtualX) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, errstr, "width");
info->CRT1XOffs = info->CRT2XOffs = 0;
}
}
if(!(pScrn->display->virtualY)) {
pScrn->virtualY = maxv;
xf86DrvMsg(pScrn->scrnIndex, X_PROBED, str, "height", maxv);
} else {
if(maxv < pScrn->display->virtualY) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, errstr, "height");
info->CRT1YOffs = info->CRT2YOffs = 0;
}
}
}
/* Pseudo-Xinerama extension for MergedFB mode */
void
RADEONUpdateXineramaScreenInfo(ScrnInfoPtr pScrn1)
{
RADEONInfoPtr info = RADEONPTR(pScrn1);
ScrnInfoPtr pScrn2 = NULL;
int crt1scrnnum = 0, crt2scrnnum = 1;
int x1=0, x2=0, y1=0, y2=0, h1=0, h2=0, w1=0, w2=0;
int realvirtX, realvirtY;
DisplayModePtr currentMode, firstMode;
Bool infochanged = FALSE;
Bool usenonrect = info->NonRect;
const char *rectxine = "\t... setting up rectangular Xinerama layout\n";
info->MBXNR1XMAX = info->MBXNR1YMAX = info->MBXNR2XMAX = info->MBXNR2YMAX = 65536;
info->HaveNonRect = info->HaveOffsRegions = FALSE;
if(!info->MergedFB) return;
if(RADEONnoPanoramiXExtension) return;
if(!RADEONXineramadataPtr) return;
if(info->CRT2IsScrn0) {
crt1scrnnum = 1;
crt2scrnnum = 0;
}
pScrn2 = info->CRT2pScrn;
/* Attention: Usage of RandR may lead into virtual X and Y values
* actually smaller than our MetaModes! To avoid this, we calculate
* the maxCRT fields here (and not somewhere else, like in CopyNLink)
*/
/* "Real" virtual: Virtual without the Offset */
realvirtX = pScrn1->virtualX - info->CRT1XOffs - info->CRT2XOffs;
realvirtY = pScrn1->virtualY - info->CRT1YOffs - info->CRT2YOffs;
if((info->RADEONXineramaVX != pScrn1->virtualX) || (info->RADEONXineramaVY != pScrn1->virtualY)) {
if(!(pScrn1->modes)) {
xf86DrvMsg(pScrn1->scrnIndex, X_ERROR,
"Internal error: RADEONUpdateXineramaScreenInfo(): pScrn->modes is NULL\n");
return;
}
info->maxCRT1_X1 = info->maxCRT1_X2 = 0;
info->maxCRT1_Y1 = info->maxCRT1_Y2 = 0;
info->maxCRT2_X1 = info->maxCRT2_X2 = 0;
info->maxCRT2_Y1 = info->maxCRT2_Y2 = 0;
info->maxClone_X1 = info->maxClone_X2 = 0;
info->maxClone_Y1 = info->maxClone_Y2 = 0;
currentMode = firstMode = pScrn1->modes;
do {
DisplayModePtr p = currentMode->next;
DisplayModePtr i = ((RADEONMergedDisplayModePtr)currentMode->Private)->CRT1;
DisplayModePtr j = ((RADEONMergedDisplayModePtr)currentMode->Private)->CRT2;
RADEONScrn2Rel srel = ((RADEONMergedDisplayModePtr)currentMode->Private)->CRT2Position;
if((currentMode->HDisplay <= realvirtX) && (currentMode->VDisplay <= realvirtY) &&
(i->HDisplay <= realvirtX) && (j->HDisplay <= realvirtX) &&
(i->VDisplay <= realvirtY) && (j->VDisplay <= realvirtY)) {
if(srel != radeonClone) {
if(info->maxCRT1_X1 == i->HDisplay) {
if(info->maxCRT1_X2 < j->HDisplay) {
info->maxCRT1_X2 = j->HDisplay; /* Widest CRT2 mode displayed with widest CRT1 mode */
}
} else if(info->maxCRT1_X1 < i->HDisplay) {
info->maxCRT1_X1 = i->HDisplay; /* Widest CRT1 mode */
info->maxCRT1_X2 = j->HDisplay;
}
if(info->maxCRT2_X2 == j->HDisplay) {
if(info->maxCRT2_X1 < i->HDisplay) {
info->maxCRT2_X1 = i->HDisplay; /* Widest CRT1 mode displayed with widest CRT2 mode */
}
} else if(info->maxCRT2_X2 < j->HDisplay) {
info->maxCRT2_X2 = j->HDisplay; /* Widest CRT2 mode */
info->maxCRT2_X1 = i->HDisplay;
}
if(info->maxCRT1_Y1 == i->VDisplay) { /* Same as above, but tallest instead of widest */
if(info->maxCRT1_Y2 < j->VDisplay) {
info->maxCRT1_Y2 = j->VDisplay;
}
} else if(info->maxCRT1_Y1 < i->VDisplay) {
info->maxCRT1_Y1 = i->VDisplay;
info->maxCRT1_Y2 = j->VDisplay;
}
if(info->maxCRT2_Y2 == j->VDisplay) {
if(info->maxCRT2_Y1 < i->VDisplay) {
info->maxCRT2_Y1 = i->VDisplay;
}
} else if(info->maxCRT2_Y2 < j->VDisplay) {
info->maxCRT2_Y2 = j->VDisplay;
info->maxCRT2_Y1 = i->VDisplay;
}
} else {
if(info->maxClone_X1 < i->HDisplay) {
info->maxClone_X1 = i->HDisplay;
}
if(info->maxClone_X2 < j->HDisplay) {
info->maxClone_X2 = j->HDisplay;
}
if(info->maxClone_Y1 < i->VDisplay) {
info->maxClone_Y1 = i->VDisplay;
}
if(info->maxClone_Y2 < j->VDisplay) {
info->maxClone_Y2 = j->VDisplay;
}
}
}
currentMode = p;
} while((currentMode) && (currentMode != firstMode));
info->RADEONXineramaVX = pScrn1->virtualX;
info->RADEONXineramaVY = pScrn1->virtualY;
infochanged = TRUE;
}
if((usenonrect) && (info->CRT2Position != radeonClone) && info->maxCRT1_X1) {
switch(info->CRT2Position) {
case radeonLeftOf:
case radeonRightOf:
if((info->maxCRT1_Y1 != realvirtY) && (info->maxCRT2_Y2 != realvirtY)) {
usenonrect = FALSE;
}
break;
case radeonAbove:
case radeonBelow:
if((info->maxCRT1_X1 != realvirtX) && (info->maxCRT2_X2 != realvirtX)) {
usenonrect = FALSE;
}
break;
case radeonClone:
break;
}
if(infochanged && !usenonrect) {
xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
"Virtual screen size does not match maximum display modes...\n");
xf86DrvMsg(pScrn1->scrnIndex, X_INFO, rectxine);
}
} else if(infochanged && usenonrect) {
usenonrect = FALSE;
xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
"Only clone modes available for this virtual screen size...\n");
xf86DrvMsg(pScrn1->scrnIndex, X_INFO, rectxine);
}
if(info->maxCRT1_X1) { /* Means we have at least one non-clone mode */
switch(info->CRT2Position) {
case radeonLeftOf:
x1 = min(info->maxCRT1_X2, pScrn1->virtualX - info->maxCRT1_X1);
if(x1 < 0) x1 = 0;
y1 = info->CRT1YOffs;
w1 = pScrn1->virtualX - x1;
h1 = realvirtY;
if((usenonrect) && (info->maxCRT1_Y1 != realvirtY)) {
h1 = info->MBXNR1YMAX = info->maxCRT1_Y1;
info->NonRectDead.x0 = x1;
info->NonRectDead.x1 = x1 + w1 - 1;
info->NonRectDead.y0 = y1 + h1;
info->NonRectDead.y1 = pScrn1->virtualY - 1;
info->HaveNonRect = TRUE;
}
x2 = 0;
y2 = info->CRT2YOffs;
w2 = max(info->maxCRT2_X2, pScrn1->virtualX - info->maxCRT2_X1);
if(w2 > pScrn1->virtualX) w2 = pScrn1->virtualX;
h2 = realvirtY;
if((usenonrect) && (info->maxCRT2_Y2 != realvirtY)) {
h2 = info->MBXNR2YMAX = info->maxCRT2_Y2;
info->NonRectDead.x0 = x2;
info->NonRectDead.x1 = x2 + w2 - 1;
info->NonRectDead.y0 = y2 + h2;
info->NonRectDead.y1 = pScrn1->virtualY - 1;
info->HaveNonRect = TRUE;
}
break;
case radeonRightOf:
x1 = 0;
y1 = info->CRT1YOffs;
w1 = max(info->maxCRT1_X1, pScrn1->virtualX - info->maxCRT1_X2);
if(w1 > pScrn1->virtualX) w1 = pScrn1->virtualX;
h1 = realvirtY;
if((usenonrect) && (info->maxCRT1_Y1 != realvirtY)) {
h1 = info->MBXNR1YMAX = info->maxCRT1_Y1;
info->NonRectDead.x0 = x1;
info->NonRectDead.x1 = x1 + w1 - 1;
info->NonRectDead.y0 = y1 + h1;
info->NonRectDead.y1 = pScrn1->virtualY - 1;
info->HaveNonRect = TRUE;
}
x2 = min(info->maxCRT2_X1, pScrn1->virtualX - info->maxCRT2_X2);
if(x2 < 0) x2 = 0;
y2 = info->CRT2YOffs;
w2 = pScrn1->virtualX - x2;
h2 = realvirtY;
if((usenonrect) && (info->maxCRT2_Y2 != realvirtY)) {
h2 = info->MBXNR2YMAX = info->maxCRT2_Y2;
info->NonRectDead.x0 = x2;
info->NonRectDead.x1 = x2 + w2 - 1;
info->NonRectDead.y0 = y2 + h2;
info->NonRectDead.y1 = pScrn1->virtualY - 1;
info->HaveNonRect = TRUE;
}
break;
case radeonAbove:
x1 = info->CRT1XOffs;
y1 = min(info->maxCRT1_Y2, pScrn1->virtualY - info->maxCRT1_Y1);
if(y1 < 0) y1 = 0;
w1 = realvirtX;
h1 = pScrn1->virtualY - y1;
if((usenonrect) && (info->maxCRT1_X1 != realvirtX)) {
w1 = info->MBXNR1XMAX = info->maxCRT1_X1;
info->NonRectDead.x0 = x1 + w1;
info->NonRectDead.x1 = pScrn1->virtualX - 1;
info->NonRectDead.y0 = y1;
info->NonRectDead.y1 = y1 + h1 - 1;
info->HaveNonRect = TRUE;
}
x2 = info->CRT2XOffs;
y2 = 0;
w2 = realvirtX;
h2 = max(info->maxCRT2_Y2, pScrn1->virtualY - info->maxCRT2_Y1);
if(h2 > pScrn1->virtualY) h2 = pScrn1->virtualY;
if((usenonrect) && (info->maxCRT2_X2 != realvirtX)) {
w2 = info->MBXNR2XMAX = info->maxCRT2_X2;
info->NonRectDead.x0 = x2 + w2;
info->NonRectDead.x1 = pScrn1->virtualX - 1;
info->NonRectDead.y0 = y2;
info->NonRectDead.y1 = y2 + h2 - 1;
info->HaveNonRect = TRUE;
}
break;
case radeonBelow:
x1 = info->CRT1XOffs;
y1 = 0;
w1 = realvirtX;
h1 = max(info->maxCRT1_Y1, pScrn1->virtualY - info->maxCRT1_Y2);
if(h1 > pScrn1->virtualY) h1 = pScrn1->virtualY;
if((usenonrect) && (info->maxCRT1_X1 != realvirtX)) {
w1 = info->MBXNR1XMAX = info->maxCRT1_X1;
info->NonRectDead.x0 = x1 + w1;
info->NonRectDead.x1 = pScrn1->virtualX - 1;
info->NonRectDead.y0 = y1;
info->NonRectDead.y1 = y1 + h1 - 1;
info->HaveNonRect = TRUE;
}
x2 = info->CRT2XOffs;
y2 = min(info->maxCRT2_Y1, pScrn1->virtualY - info->maxCRT2_Y2);
if(y2 < 0) y2 = 0;
w2 = realvirtX;
h2 = pScrn1->virtualY - y2;
if((usenonrect) && (info->maxCRT2_X2 != realvirtX)) {
w2 = info->MBXNR2XMAX = info->maxCRT2_X2;
info->NonRectDead.x0 = x2 + w2;
info->NonRectDead.x1 = pScrn1->virtualX - 1;
info->NonRectDead.y0 = y2;
info->NonRectDead.y1 = y2 + h2 - 1;
info->HaveNonRect = TRUE;
}
default:
break;
}
switch(info->CRT2Position) {
case radeonLeftOf:
case radeonRightOf:
if(info->CRT1YOffs) {
info->OffDead1.x0 = x1;
info->OffDead1.x1 = x1 + w1 - 1;
info->OffDead1.y0 = 0;
info->OffDead1.y1 = y1 - 1;
info->OffDead2.x0 = x2;
info->OffDead2.x1 = x2 + w2 - 1;
info->OffDead2.y0 = y2 + h2;
info->OffDead2.y1 = pScrn1->virtualY - 1;
info->HaveOffsRegions = TRUE;
} else if(info->CRT2YOffs) {
info->OffDead1.x0 = x2;
info->OffDead1.x1 = x2 + w2 - 1;
info->OffDead1.y0 = 0;
info->OffDead1.y1 = y2 - 1;
info->OffDead2.x0 = x1;
info->OffDead2.x1 = x1 + w1 - 1;
info->OffDead2.y0 = y1 + h1;
info->OffDead2.y1 = pScrn1->virtualY - 1;
info->HaveOffsRegions = TRUE;
}
break;
case radeonAbove:
case radeonBelow:
if(info->CRT1XOffs) {
info->OffDead1.x0 = x2 + w2;
info->OffDead1.x1 = pScrn1->virtualX - 1;
info->OffDead1.y0 = y2;
info->OffDead1.y1 = y2 + h2 - 1;
info->OffDead2.x0 = 0;
info->OffDead2.x1 = x1 - 1;
info->OffDead2.y0 = y1;
info->OffDead2.y1 = y1 + h1 - 1;
info->HaveOffsRegions = TRUE;
} else if(info->CRT2XOffs) {
info->OffDead1.x0 = x1 + w1;
info->OffDead1.x1 = pScrn1->virtualX - 1;
info->OffDead1.y0 = y1;
info->OffDead1.y1 = y1 + h1 - 1;
info->OffDead2.x0 = 0;
info->OffDead2.x1 = x2 - 1;
info->OffDead2.y0 = y2;
info->OffDead2.y1 = y2 + h2 - 1;
info->HaveOffsRegions = TRUE;
}
default:
break;
}
} else { /* Only clone-modes left */
x1 = x2 = 0;
y1 = y2 = 0;
w1 = w2 = max(info->maxClone_X1, info->maxClone_X2);
h1 = h2 = max(info->maxClone_Y1, info->maxClone_Y2);
}
RADEONXineramadataPtr[crt1scrnnum].x = x1;
RADEONXineramadataPtr[crt1scrnnum].y = y1;
RADEONXineramadataPtr[crt1scrnnum].width = w1;
RADEONXineramadataPtr[crt1scrnnum].height = h1;
RADEONXineramadataPtr[crt2scrnnum].x = x2;
RADEONXineramadataPtr[crt2scrnnum].y = y2;
RADEONXineramadataPtr[crt2scrnnum].width = w2;
RADEONXineramadataPtr[crt2scrnnum].height = h2;
if(infochanged) {
xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
"Pseudo-Xinerama: CRT1 (Screen %d) (%d,%d)-(%d,%d)\n",
crt1scrnnum, x1, y1, w1+x1-1, h1+y1-1);
xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
"Pseudo-Xinerama: CRT2 (Screen %d) (%d,%d)-(%d,%d)\n",
crt2scrnnum, x2, y2, w2+x2-1, h2+y2-1);
if(info->HaveNonRect) {
xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
"Pseudo-Xinerama: Inaccessible area (%d,%d)-(%d,%d)\n",
info->NonRectDead.x0, info->NonRectDead.y0,
info->NonRectDead.x1, info->NonRectDead.y1);
}
if(info->HaveOffsRegions) {
xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
"Pseudo-Xinerama: Inaccessible offset area (%d,%d)-(%d,%d)\n",
info->OffDead1.x0, info->OffDead1.y0,
info->OffDead1.x1, info->OffDead1.y1);
xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
"Pseudo-Xinerama: Inaccessible offset area (%d,%d)-(%d,%d)\n",
info->OffDead2.x0, info->OffDead2.y0,
info->OffDead2.x1, info->OffDead2.y1);
}
if(info->HaveNonRect || info->HaveOffsRegions) {
xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
"Mouse restriction for inaccessible areas is %s\n",
info->MouseRestrictions ? "enabled" : "disabled");
}
}
}
/* Proc */
int
RADEONProcXineramaQueryVersion(ClientPtr client)
{
xPanoramiXQueryVersionReply rep;
register int n;
REQUEST_SIZE_MATCH(xPanoramiXQueryVersionReq);
rep.type = X_Reply;
rep.length = 0;
rep.sequenceNumber = client->sequence;
rep.majorVersion = RADEON_XINERAMA_MAJOR_VERSION;
rep.minorVersion = RADEON_XINERAMA_MINOR_VERSION;
if(client->swapped) {
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
swaps(&rep.majorVersion, n);
swaps(&rep.minorVersion, n);
}
WriteToClient(client, sizeof(xPanoramiXQueryVersionReply), (char *)&rep);
return (client->noClientException);
}
int
RADEONProcXineramaGetState(ClientPtr client)
{
REQUEST(xPanoramiXGetStateReq);
WindowPtr pWin;
xPanoramiXGetStateReply rep;
register int n;
REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
pWin = LookupWindow(stuff->window, client);
if(!pWin) return BadWindow;
rep.type = X_Reply;
rep.length = 0;
rep.sequenceNumber = client->sequence;
rep.state = !RADEONnoPanoramiXExtension;
if(client->swapped) {
swaps (&rep.sequenceNumber, n);
swapl (&rep.length, n);
swaps (&rep.state, n);
}
WriteToClient(client, sizeof(xPanoramiXGetStateReply), (char *)&rep);
return client->noClientException;
}
int
RADEONProcXineramaGetScreenCount(ClientPtr client)
{
REQUEST(xPanoramiXGetScreenCountReq);
WindowPtr pWin;
xPanoramiXGetScreenCountReply rep;
register int n;
REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
pWin = LookupWindow(stuff->window, client);
if(!pWin) return BadWindow;
rep.type = X_Reply;
rep.length = 0;
rep.sequenceNumber = client->sequence;
rep.ScreenCount = RADEONXineramaNumScreens;
if(client->swapped) {
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
swaps(&rep.ScreenCount, n);
}
WriteToClient(client, sizeof(xPanoramiXGetScreenCountReply), (char *)&rep);
return client->noClientException;
}
int
RADEONProcXineramaGetScreenSize(ClientPtr client)
{
REQUEST(xPanoramiXGetScreenSizeReq);
WindowPtr pWin;
xPanoramiXGetScreenSizeReply rep;
register int n;
REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
pWin = LookupWindow (stuff->window, client);
if(!pWin) return BadWindow;
rep.type = X_Reply;
rep.length = 0;
rep.sequenceNumber = client->sequence;
rep.width = RADEONXineramadataPtr[stuff->screen].width;
rep.height = RADEONXineramadataPtr[stuff->screen].height;
if(client->swapped) {
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
swaps(&rep.width, n);
swaps(&rep.height, n);
}
WriteToClient(client, sizeof(xPanoramiXGetScreenSizeReply), (char *)&rep);
return client->noClientException;
}
int
RADEONProcXineramaIsActive(ClientPtr client)
{
xXineramaIsActiveReply rep;
REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
rep.type = X_Reply;
rep.length = 0;
rep.sequenceNumber = client->sequence;
rep.state = !RADEONnoPanoramiXExtension;
if(client->swapped) {
register int n;
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
swapl(&rep.state, n);
}
WriteToClient(client, sizeof(xXineramaIsActiveReply), (char *) &rep);
return client->noClientException;
}
int
RADEONProcXineramaQueryScreens(ClientPtr client)
{
xXineramaQueryScreensReply rep;
REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
rep.type = X_Reply;
rep.sequenceNumber = client->sequence;
rep.number = (RADEONnoPanoramiXExtension) ? 0 : RADEONXineramaNumScreens;
rep.length = rep.number * sz_XineramaScreenInfo >> 2;
if(client->swapped) {
register int n;
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
swapl(&rep.number, n);
}
WriteToClient(client, sizeof(xXineramaQueryScreensReply), (char *)&rep);
if(!RADEONnoPanoramiXExtension) {
xXineramaScreenInfo scratch;
int i;
for(i = 0; i < RADEONXineramaNumScreens; i++) {
scratch.x_org = RADEONXineramadataPtr[i].x;
scratch.y_org = RADEONXineramadataPtr[i].y;
scratch.width = RADEONXineramadataPtr[i].width;
scratch.height = RADEONXineramadataPtr[i].height;
if(client->swapped) {
register int n;
swaps(&scratch.x_org, n);
swaps(&scratch.y_org, n);
swaps(&scratch.width, n);
swaps(&scratch.height, n);
}
WriteToClient(client, sz_XineramaScreenInfo, (char *)&scratch);
}
}
return client->noClientException;
}
static int
RADEONProcXineramaDispatch(ClientPtr client)
{
REQUEST(xReq);
switch (stuff->data)
{
case X_PanoramiXQueryVersion:
return RADEONProcXineramaQueryVersion(client);
case X_PanoramiXGetState:
return RADEONProcXineramaGetState(client);
case X_PanoramiXGetScreenCount:
return RADEONProcXineramaGetScreenCount(client);
case X_PanoramiXGetScreenSize:
return RADEONProcXineramaGetScreenSize(client);
case X_XineramaIsActive:
return RADEONProcXineramaIsActive(client);
case X_XineramaQueryScreens:
return RADEONProcXineramaQueryScreens(client);
}
return BadRequest;
}
/* SProc */
static int
RADEONSProcXineramaQueryVersion (ClientPtr client)
{
REQUEST(xPanoramiXQueryVersionReq);
register int n;
swaps(&stuff->length,n);
REQUEST_SIZE_MATCH (xPanoramiXQueryVersionReq);
return RADEONProcXineramaQueryVersion(client);
}
static int
RADEONSProcXineramaGetState(ClientPtr client)
{
REQUEST(xPanoramiXGetStateReq);
register int n;
swaps (&stuff->length, n);
REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
return RADEONProcXineramaGetState(client);
}
static int
RADEONSProcXineramaGetScreenCount(ClientPtr client)
{
REQUEST(xPanoramiXGetScreenCountReq);
register int n;
swaps (&stuff->length, n);
REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
return RADEONProcXineramaGetScreenCount(client);
}
static int
RADEONSProcXineramaGetScreenSize(ClientPtr client)
{
REQUEST(xPanoramiXGetScreenSizeReq);
register int n;
swaps (&stuff->length, n);
REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
return RADEONProcXineramaGetScreenSize(client);
}
static int
RADEONSProcXineramaIsActive(ClientPtr client)
{
REQUEST(xXineramaIsActiveReq);
register int n;
swaps (&stuff->length, n);
REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
return RADEONProcXineramaIsActive(client);
}
static int
RADEONSProcXineramaQueryScreens(ClientPtr client)
{
REQUEST(xXineramaQueryScreensReq);
register int n;
swaps (&stuff->length, n);
REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
return RADEONProcXineramaQueryScreens(client);
}
int
RADEONSProcXineramaDispatch(ClientPtr client)
{
REQUEST(xReq);
switch (stuff->data) {
case X_PanoramiXQueryVersion:
return RADEONSProcXineramaQueryVersion(client);
case X_PanoramiXGetState:
return RADEONSProcXineramaGetState(client);
case X_PanoramiXGetScreenCount:
return RADEONSProcXineramaGetScreenCount(client);
case X_PanoramiXGetScreenSize:
return RADEONSProcXineramaGetScreenSize(client);
case X_XineramaIsActive:
return RADEONSProcXineramaIsActive(client);
case X_XineramaQueryScreens:
return RADEONSProcXineramaQueryScreens(client);
}
return BadRequest;
}
static void
RADEONXineramaResetProc(ExtensionEntry* extEntry)
{
if(RADEONXineramadataPtr) {
Xfree(RADEONXineramadataPtr);
RADEONXineramadataPtr = NULL;
}
}
void
RADEONXineramaExtensionInit(ScrnInfoPtr pScrn)
{
RADEONInfoPtr info = RADEONPTR(pScrn);
Bool success = FALSE;
if(!(RADEONXineramadataPtr)) {
if(!info->MergedFB) {
RADEONnoPanoramiXExtension = TRUE;
info->MouseRestrictions = FALSE;
return;
}
#ifdef PANORAMIX
if(!noPanoramiXExtension) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Xinerama active, not initializing Radeon Pseudo-Xinerama\n");
RADEONnoPanoramiXExtension = TRUE;
info->MouseRestrictions = FALSE;
return;
}
#endif
if(RADEONnoPanoramiXExtension) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Radeon Pseudo-Xinerama disabled\n");
info->MouseRestrictions = FALSE;
return;
}
if(info->CRT2Position == radeonClone) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Running MergedFB in Clone mode, Radeon Pseudo-Xinerama disabled\n");
RADEONnoPanoramiXExtension = TRUE;
info->MouseRestrictions = FALSE;
return;
}
if(!(info->AtLeastOneNonClone)) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Only Clone modes defined, Radeon Pseudo-Xinerama disabled\n");
RADEONnoPanoramiXExtension = TRUE;
info->MouseRestrictions = FALSE;
return;
}
RADEONXineramaNumScreens = 2;
while(RADEONXineramaGeneration != serverGeneration) {
info->XineramaExtEntry = AddExtension(PANORAMIX_PROTOCOL_NAME, 0,0,
RADEONProcXineramaDispatch,
RADEONSProcXineramaDispatch,
RADEONXineramaResetProc,
StandardMinorOpcode);
if(!info->XineramaExtEntry) break;
RADEONXineramaReqCode = (unsigned char)info->XineramaExtEntry->base;
if(!(RADEONXineramadataPtr = (RADEONXineramaData *)
xcalloc(RADEONXineramaNumScreens, sizeof(RADEONXineramaData)))) break;
RADEONXineramaGeneration = serverGeneration;
success = TRUE;
}
if(!success) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Failed to initialize Radeon Pseudo-Xinerama extension\n");
RADEONnoPanoramiXExtension = TRUE;
info->MouseRestrictions = FALSE;
return;
}
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Initialized Radeon Pseudo-Xinerama extension\n");
info->RADEONXineramaVX = 0;
info->RADEONXineramaVY = 0;
}
RADEONUpdateXineramaScreenInfo(pScrn);
}
/* End of PseudoXinerama */
static Bool
InRegion(int x, int y, region r)
{
return (r.x0 <= x) && (x <= r.x1) && (r.y0 <= y) && (y <= r.y1);
}
void
RADEONMergePointerMoved(int scrnIndex, int x, int y)
{
ScrnInfoPtr pScrn1 = xf86Screens[scrnIndex];
RADEONInfoPtr info = RADEONPTR(pScrn1);
ScrnInfoPtr pScrn2 = info->CRT2pScrn;
region out, in1, in2, f2, f1;
int deltax, deltay;
int temp1, temp2;
int old1x0, old1y0, old2x0, old2y0;
int CRT1XOffs = 0, CRT1YOffs = 0, CRT2XOffs = 0, CRT2YOffs = 0;
int HVirt = pScrn1->virtualX;
int VVirt = pScrn1->virtualY;
int sigstate;
Bool doit = FALSE, HaveNonRect = FALSE, HaveOffsRegions = FALSE;
RADEONScrn2Rel srel = ((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2Position;
if(info->DGAactive) {
return;
/* DGA: There is no cursor and no panning while DGA is active. */
/* If it were, we would need to do: */
/* HVirt = info->CurrentLayout.displayWidth;
VVirt = info->CurrentLayout.displayHeight;
BOUND(x, info->CurrentLayout.DGAViewportX, HVirt);
BOUND(y, info->CurrentLayout.DGAViewportY, VVirt); */
} else {
CRT1XOffs = info->CRT1XOffs;
CRT1YOffs = info->CRT1YOffs;
CRT2XOffs = info->CRT2XOffs;
CRT2YOffs = info->CRT2YOffs;
HaveNonRect = info->HaveNonRect;
HaveOffsRegions = info->HaveOffsRegions;
}
/* Check if the pointer is inside our dead areas */
if((info->MouseRestrictions) && (srel != radeonClone) && !RADEONnoPanoramiXExtension) {
if(HaveNonRect) {
if(InRegion(x, y, info->NonRectDead)) {
switch(srel) {
case radeonLeftOf:
case radeonRightOf: y = info->NonRectDead.y0 - 1;
doit = TRUE;
break;
case radeonAbove:
case radeonBelow: x = info->NonRectDead.x0 - 1;
doit = TRUE;
default: break;
}
}
}
if(HaveOffsRegions) {
if(InRegion(x, y, info->OffDead1)) {
switch(srel) {
case radeonLeftOf:
case radeonRightOf: y = info->OffDead1.y1;
doit = TRUE;
break;
case radeonAbove:
case radeonBelow: x = info->OffDead1.x1;
doit = TRUE;
default: break;
}
} else if(InRegion(x, y, info->OffDead2)) {
switch(srel) {
case radeonLeftOf:
case radeonRightOf: y = info->OffDead2.y0 - 1;
doit = TRUE;
break;
case radeonAbove:
case radeonBelow: x = info->OffDead2.x0 - 1;
doit = TRUE;
default: break;
}
}
}
if(doit) {
UpdateCurrentTime();
sigstate = xf86BlockSIGIO();
miPointerAbsoluteCursor(x, y, currentTime.milliseconds);
xf86UnblockSIGIO(sigstate);
return;
}
}
f1.x0 = old1x0 = info->CRT1frameX0;
f1.x1 = info->CRT1frameX1;
f1.y0 = old1y0 = info->CRT1frameY0;
f1.y1 = info->CRT1frameY1;
f2.x0 = old2x0 = pScrn2->frameX0;
f2.x1 = pScrn2->frameX1;
f2.y0 = old2y0 = pScrn2->frameY0;
f2.y1 = pScrn2->frameY1;
/* Define the outer region. Crossing this causes all frames to move */
out.x0 = pScrn1->frameX0;
out.x1 = pScrn1->frameX1;
out.y0 = pScrn1->frameY0;
out.y1 = pScrn1->frameY1;
/*
* Define the inner sliding window. Being outsize both frames but
* inside the outer clipping window will slide corresponding frame
*/
in1 = out;
in2 = out;
switch(srel) {
case radeonLeftOf:
in1.x0 = f1.x0;
in2.x1 = f2.x1;
break;
case radeonRightOf:
in1.x1 = f1.x1;
in2.x0 = f2.x0;
break;
case radeonBelow:
in1.y1 = f1.y1;
in2.y0 = f2.y0;
break;
case radeonAbove:
in1.y0 = f1.y0;
in2.y1 = f2.y1;
break;
case radeonClone:
break;
}
deltay = 0;
deltax = 0;
if(InRegion(x, y, out)) { /* inside outer region */
/* xf86DrvMsg(0, X_INFO, "1: %d %d | %d %d %d %d | %d %d %d %d\n",
x, y, in1.x0, in1.x1, in1.y0, in1.y1, f1.x0, f1.x1, f1.y0, f1.y1); */
if(InRegion(x, y, in1) && !InRegion(x, y, f1)) {
REBOUND(f1.x0, f1.x1, x);
REBOUND(f1.y0, f1.y1, y);
deltax = 1;
/* xf86DrvMsg(0, X_INFO, "2: %d %d | %d %d %d %d | %d %d %d %d\n",
x, y, in1.x0, in1.x1, in1.y0, in1.y1, f1.x0, f1.x1, f1.y0, f1.y1); */
}
if(InRegion(x, y, in2) && !InRegion(x, y, f2)) {
REBOUND(f2.x0, f2.x1, x);
REBOUND(f2.y0, f2.y1, y);
deltax = 1;
}
} else { /* outside outer region */
/* xf86DrvMsg(0, X_INFO, "3: %d %d | %d %d %d %d | %d %d %d %d\n",
x, y, in1.x0, in1.x1, in1.y0, in1.y1, f1.x0, f1.x1, f1.y0, f1.y1);
xf86DrvMsg(0, X_INFO, "3-out: %d %d %d %d\n",
out.x0, out.x1, out.y0, out.y1); */
if(out.x0 > x) {
deltax = x - out.x0;
}
if(out.x1 < x) {
deltax = x - out.x1;
}
if(deltax) {
pScrn1->frameX0 += deltax;
pScrn1->frameX1 += deltax;
f1.x0 += deltax;
f1.x1 += deltax;
f2.x0 += deltax;
f2.x1 += deltax;
}
if(out.y0 > y) {
deltay = y - out.y0;
}
if(out.y1 < y) {
deltay = y - out.y1;
}
if(deltay) {
pScrn1->frameY0 += deltay;
pScrn1->frameY1 += deltay;
f1.y0 += deltay;
f1.y1 += deltay;
f2.y0 += deltay;
f2.y1 += deltay;
}
switch(srel) {
case radeonLeftOf:
if(x >= f1.x0) { REBOUND(f1.y0, f1.y1, y); }
if(x <= f2.x1) { REBOUND(f2.y0, f2.y1, y); }
break;
case radeonRightOf:
if(x <= f1.x1) { REBOUND(f1.y0, f1.y1, y); }
if(x >= f2.x0) { REBOUND(f2.y0, f2.y1, y); }
break;
case radeonBelow:
if(y <= f1.y1) { REBOUND(f1.x0, f1.x1, x); }
if(y >= f2.y0) { REBOUND(f2.x0, f2.x1, x); }
break;
case radeonAbove:
if(y >= f1.y0) { REBOUND(f1.x0, f1.x1, x); }
if(y <= f2.y1) { REBOUND(f2.x0, f2.x1, x); }
break;
case radeonClone:
break;
}
}
if(deltax || deltay) {
info->CRT1frameX0 = f1.x0;
info->CRT1frameY0 = f1.y0;
pScrn2->frameX0 = f2.x0;
pScrn2->frameY0 = f2.y0;
switch(((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2Position) {
case radeonLeftOf:
case radeonRightOf:
if(info->CRT1YOffs || info->CRT2YOffs || HaveNonRect) {
if(info->CRT1frameY0 != old1y0) {
if(info->CRT1frameY0 < info->CRT1YOffs)
info->CRT1frameY0 = info->CRT1YOffs;
temp1 = info->CRT1frameY0 + CDMPTR->CRT1->VDisplay;
/*temp2 = pScrn1->virtualY - info->CRT2YOffs;*/
temp2 = min((VVirt - CRT2YOffs), (CRT1YOffs + info->MBXNR1YMAX));
if(temp1 > temp2)
info->CRT1frameY0 -= (temp1 - temp2);
}
if(pScrn2->frameY0 != old2y0) {
if(pScrn2->frameY0 < info->CRT2YOffs)
pScrn2->frameY0 = info->CRT2YOffs;
temp1 = pScrn2->frameY0 + CDMPTR->CRT2->VDisplay;
/*temp2 = pScrn1->virtualY - info->CRT1YOffs;*/
temp2 = min((VVirt - CRT1YOffs), (CRT2YOffs + info->MBXNR2YMAX));
if(temp1 > temp2)
pScrn2->frameY0 -= (temp1 - temp2);
}
}
break;
case radeonBelow:
case radeonAbove:
if(info->CRT1XOffs || info->CRT2XOffs || HaveNonRect) {
if(info->CRT1frameX0 != old1x0) {
if(info->CRT1frameX0 < info->CRT1XOffs)
info->CRT1frameX0 = info->CRT1XOffs;
temp1 = info->CRT1frameX0 + CDMPTR->CRT1->HDisplay;
/*temp2 = pScrn1->virtualX - info->CRT2XOffs;*/
temp2 = min((HVirt - CRT2XOffs), (CRT1XOffs + info->MBXNR1XMAX));
if(temp1 > temp2)
info->CRT1frameX0 -= (temp1 - temp2);
}
if(pScrn2->frameX0 != old2x0) {
if(pScrn2->frameX0 < info->CRT2XOffs)
pScrn2->frameX0 = info->CRT2XOffs;
temp1 = pScrn2->frameX0 + CDMPTR->CRT2->HDisplay;
/*temp2 = pScrn1->virtualX - info->CRT1XOffs;*/
temp2 = min((HVirt - CRT1XOffs), (CRT2XOffs + info->MBXNR2XMAX));
if(temp1 > temp2)
pScrn2->frameX0 -= (temp1 - temp2);
}
}
break;
case radeonClone:
break;
}
info->CRT1frameX1 = info->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1;
info->CRT1frameY1 = info->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1;
pScrn2->frameX1 = pScrn2->frameX0 + CDMPTR->CRT2->HDisplay - 1;
pScrn2->frameY1 = pScrn2->frameY0 + CDMPTR->CRT2->VDisplay - 1;
#if 0
pScrn1->frameX1 = pScrn1->frameX0 + info->CurrentLayout.mode->HDisplay - 1;
pScrn1->frameY1 = pScrn1->frameY0 + info->CurrentLayout.mode->VDisplay - 1;
#endif
RADEONDoAdjustFrame(pScrn1, info->CRT1frameX0, info->CRT1frameY0, FALSE);
RADEONDoAdjustFrame(pScrn1, pScrn2->frameX0, pScrn2->frameY0, TRUE);
}
}
static void
RADEONAdjustFrameMergedHelper(int scrnIndex, int x, int y, int flags)
{
ScrnInfoPtr pScrn1 = xf86Screens[scrnIndex];
RADEONInfoPtr info = RADEONPTR(pScrn1);
ScrnInfoPtr pScrn2 = info->CRT2pScrn;
int VTotal = info->CurrentLayout.mode->VDisplay;
int HTotal = info->CurrentLayout.mode->HDisplay;
int VMax = VTotal;
int HMax = HTotal;
int HVirt = pScrn1->virtualX;
int VVirt = pScrn1->virtualY;
int x1 = x, x2 = x;
int y1 = y, y2 = y;
int CRT1XOffs = 0, CRT1YOffs = 0, CRT2XOffs = 0, CRT2YOffs = 0;
int MBXNR1XMAX = 65536, MBXNR1YMAX = 65536, MBXNR2XMAX = 65536, MBXNR2YMAX = 65536;
if(info->DGAactive) {
HVirt = info->CurrentLayout.displayWidth;
VVirt = info->CurrentLayout.displayHeight;
} else {
CRT1XOffs = info->CRT1XOffs;
CRT1YOffs = info->CRT1YOffs;
CRT2XOffs = info->CRT2XOffs;
CRT2YOffs = info->CRT2YOffs;
MBXNR1XMAX = info->MBXNR1XMAX;
MBXNR1YMAX = info->MBXNR1YMAX;
MBXNR2XMAX = info->MBXNR2XMAX;
MBXNR2YMAX = info->MBXNR2YMAX;
}
BOUND(x, 0, pScrn1->virtualX - HTotal);
BOUND(y, 0, pScrn1->virtualY - VTotal);
if(SDMPTR(pScrn1)->CRT2Position != radeonClone) {
#if 0
BOUND(x1, info->CRT1XOffs, pScrn1->virtualX - HTotal - info->CRT2XOffs);
BOUND(y1, info->CRT1YOffs, pScrn1->virtualY - VTotal - info->CRT2YOffs);
BOUND(x2, info->CRT2XOffs, pScrn1->virtualX - HTotal - info->CRT1XOffs);
BOUND(y2, info->CRT2YOffs, pScrn1->virtualY - VTotal - info->CRT1YOffs);
#endif
BOUND(x1, CRT1XOffs, min(HVirt, MBXNR1XMAX + CRT1XOffs) - min(HTotal, MBXNR1XMAX) - CRT2XOffs);
BOUND(y1, CRT1YOffs, min(VVirt, MBXNR1YMAX + CRT1YOffs) - min(VTotal, MBXNR1YMAX) - CRT2YOffs);
BOUND(x2, CRT2XOffs, min(HVirt, MBXNR2XMAX + CRT2XOffs) - min(HTotal, MBXNR2XMAX) - CRT1XOffs);
BOUND(y2, CRT2YOffs, min(VVirt, MBXNR2YMAX + CRT2YOffs) - min(VTotal, MBXNR2YMAX) - CRT1YOffs);
}
switch(SDMPTR(pScrn1)->CRT2Position) {
case radeonLeftOf:
pScrn2->frameX0 = x2;
/*BOUND(pScrn2->frameY0, y2, y2 + VMax - CDMPTR->CRT2->VDisplay);*/
BOUND(pScrn2->frameY0, y2, y2 + min(VMax, MBXNR2YMAX) - CDMPTR->CRT2->VDisplay);
info->CRT1frameX0 = x1 + CDMPTR->CRT2->HDisplay;
/*BOUND(info->CRT1frameY0, y1, y1 + VMax - CDMPTR->CRT1->VDisplay);*/
BOUND(info->CRT1frameY0, y1, y1 + min(VMax, MBXNR1YMAX) - CDMPTR->CRT1->VDisplay);
break;
case radeonRightOf:
info->CRT1frameX0 = x1;
/*BOUND(info->CRT1frameY0, y1, y1 + VMax - CDMPTR->CRT1->VDisplay);*/
BOUND(info->CRT1frameY0, y1, y1 + min(VMax, MBXNR1YMAX) - CDMPTR->CRT1->VDisplay);
pScrn2->frameX0 = x2 + CDMPTR->CRT1->HDisplay;
/*BOUND(pScrn2->frameY0, y2, y2 + VMax - CDMPTR->CRT2->VDisplay);*/
BOUND(pScrn2->frameY0, y2, y2 + min(VMax, MBXNR2YMAX) - CDMPTR->CRT2->VDisplay);
break;
case radeonAbove:
/*BOUND(pScrn2->frameX0, x2, x2 + HMax - CDMPTR->CRT2->HDisplay);*/
BOUND(pScrn2->frameX0, x2, x2 + min(HMax, MBXNR2XMAX) - CDMPTR->CRT2->HDisplay);
pScrn2->frameY0 = y2;
/*BOUND(info->CRT1frameX0, x1, x1 + HMax - CDMPTR->CRT1->HDisplay);*/
BOUND(info->CRT1frameX0, x1, x1 + min(HMax, MBXNR1XMAX) - CDMPTR->CRT1->HDisplay);
info->CRT1frameY0 = y1 + CDMPTR->CRT2->VDisplay;
break;
case radeonBelow:
/*BOUND(info->CRT1frameX0, x1, x1 + HMax - CDMPTR->CRT1->HDisplay);*/
BOUND(info->CRT1frameX0, x1, x1 + min(HMax, MBXNR1XMAX) - CDMPTR->CRT1->HDisplay);
info->CRT1frameY0 = y1;
/*BOUND(pScrn2->frameX0, x2, x2 + HMax - CDMPTR->CRT2->HDisplay);*/
BOUND(pScrn2->frameX0, x2, x2 + min(HMax, MBXNR2XMAX) - CDMPTR->CRT2->HDisplay);
pScrn2->frameY0 = y2 + CDMPTR->CRT1->VDisplay;
break;
case radeonClone:
BOUND(info->CRT1frameX0, x, x + HMax - CDMPTR->CRT1->HDisplay);
BOUND(info->CRT1frameY0, y, y + VMax - CDMPTR->CRT1->VDisplay);
BOUND(pScrn2->frameX0, x, x + HMax - CDMPTR->CRT2->HDisplay);
BOUND(pScrn2->frameY0, y, y + VMax - CDMPTR->CRT2->VDisplay);
break;
}
BOUND(info->CRT1frameX0, 0, pScrn1->virtualX - CDMPTR->CRT1->HDisplay);
BOUND(info->CRT1frameY0, 0, pScrn1->virtualY - CDMPTR->CRT1->VDisplay);
BOUND(pScrn2->frameX0, 0, pScrn1->virtualX - CDMPTR->CRT2->HDisplay);
BOUND(pScrn2->frameY0, 0, pScrn1->virtualY - CDMPTR->CRT2->VDisplay);
pScrn1->frameX0 = x;
pScrn1->frameY0 = y;
info->CRT1frameX1 = info->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1;
info->CRT1frameY1 = info->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1;
pScrn2->frameX1 = pScrn2->frameX0 + CDMPTR->CRT2->HDisplay - 1;
pScrn2->frameY1 = pScrn2->frameY0 + CDMPTR->CRT2->VDisplay - 1;
pScrn1->frameX1 = pScrn1->frameX0 + info->CurrentLayout.mode->HDisplay - 1;
pScrn1->frameY1 = pScrn1->frameY0 + info->CurrentLayout.mode->VDisplay - 1;
if(SDMPTR(pScrn1)->CRT2Position != radeonClone) {
pScrn1->frameX1 += CRT1XOffs + CRT2XOffs;
pScrn1->frameY1 += CRT1YOffs + CRT2YOffs;
}
/*
RADEONDoAdjustFrame(pScrn1, info->CRT1frameX0, info->CRT1frameY0, FALSE);
RADEONDoAdjustFrame(pScrn1, pScrn2->frameX0, pScrn2->frameY0, TRUE);
*/
}
void
RADEONAdjustFrameMerged(int scrnIndex, int x, int y, int flags)
{
ScrnInfoPtr pScrn1 = xf86Screens[scrnIndex];
RADEONInfoPtr info = RADEONPTR(pScrn1);
ScrnInfoPtr pScrn2 = info->CRT2pScrn;
RADEONAdjustFrameMergedHelper(scrnIndex, x, y, flags);
RADEONDoAdjustFrame(pScrn1, info->CRT1frameX0, info->CRT1frameY0, FALSE);
RADEONDoAdjustFrame(pScrn1, pScrn2->frameX0, pScrn2->frameY0, TRUE);
}
static void
RADEONMergedFBCalcDPI(ScrnInfoPtr pScrn1, ScrnInfoPtr pScrn2, RADEONScrn2Rel srel, Bool quiet)
{
RADEONInfoPtr info = RADEONPTR(pScrn1);
MessageType from = X_DEFAULT;
xf86MonPtr DDC1 = (xf86MonPtr)(pScrn1->monitor->DDC);
xf86MonPtr DDC2 = (xf86MonPtr)(pScrn2->monitor->DDC);
int ddcWidthmm = 0, ddcHeightmm = 0;
const char *dsstr = "MergedFB: Display dimensions: %dx%d mm\n";
/* This sets the DPI for MergedFB mode. The problem is that
* this can never be exact, because the output devices may
* have different dimensions. This function tries to compromise
* through a few assumptions, and it just calculates an average
* DPI value for both monitors.
*/
/* Copy user-given DisplaySize (which should regard BOTH monitors!) */
pScrn1->widthmm = pScrn1->monitor->widthmm;
pScrn1->heightmm = pScrn1->monitor->heightmm;
if(monitorResolution > 0) {
/* Set command line given values (overrules given options) */
pScrn1->xDpi = monitorResolution;
pScrn1->yDpi = monitorResolution;
from = X_CMDLINE;
} else if(info->MergedFBXDPI) {
/* Set option-wise given values (overrules DisplaySize config option) */
pScrn1->xDpi = info->MergedFBXDPI;
pScrn1->yDpi = info->MergedFBYDPI;
from = X_CONFIG;
} else if(pScrn1->widthmm > 0 || pScrn1->heightmm > 0) {
/* Set values calculated from given DisplaySize */
from = X_CONFIG;
if(pScrn1->widthmm > 0) {
pScrn1->xDpi = (int)((double)pScrn1->virtualX * 25.4 / pScrn1->widthmm);
}
if(pScrn1->heightmm > 0) {
pScrn1->yDpi = (int)((double)pScrn1->virtualY * 25.4 / pScrn1->heightmm);
}
if(!quiet) {
xf86DrvMsg(pScrn1->scrnIndex, from, dsstr, pScrn1->widthmm, pScrn1->heightmm);
}
} else if(ddcWidthmm && ddcHeightmm) {
/* Set values from DDC-provided display size */
/* Get DDC display size; if only either CRT1 or CRT2 provided these,
* assume equal dimensions for both, otherwise add dimensions
*/
if( (DDC1 && (DDC1->features.hsize > 0 && DDC1->features.vsize > 0)) &&
(DDC2 && (DDC2->features.hsize > 0 && DDC2->features.vsize > 0)) ) {
ddcWidthmm = max(DDC1->features.hsize, DDC2->features.hsize) * 10;
ddcHeightmm = max(DDC1->features.vsize, DDC2->features.vsize) * 10;
switch(srel) {
case radeonLeftOf:
case radeonRightOf:
ddcWidthmm = (DDC1->features.hsize + DDC2->features.hsize) * 10;
break;
case radeonAbove:
case radeonBelow:
ddcHeightmm = (DDC1->features.vsize + DDC2->features.vsize) * 10;
default:
break;
}
} else if(DDC1 && (DDC1->features.hsize > 0 && DDC1->features.vsize > 0)) {
ddcWidthmm = DDC1->features.hsize * 10;
ddcHeightmm = DDC1->features.vsize * 10;
switch(srel) {
case radeonLeftOf:
case radeonRightOf:
ddcWidthmm *= 2;
break;
case radeonAbove:
case radeonBelow:
ddcHeightmm *= 2;
default:
break;
}
} else if(DDC2 && (DDC2->features.hsize > 0 && DDC2->features.vsize > 0) ) {
ddcWidthmm = DDC2->features.hsize * 10;
ddcHeightmm = DDC2->features.vsize * 10;
switch(srel) {
case radeonLeftOf:
case radeonRightOf:
ddcWidthmm *= 2;
break;
case radeonAbove:
case radeonBelow:
ddcHeightmm *= 2;
default:
break;
}
}
from = X_PROBED;
if(!quiet) {
xf86DrvMsg(pScrn1->scrnIndex, from, dsstr, ddcWidthmm, ddcHeightmm);
}
pScrn1->widthmm = ddcWidthmm;
pScrn1->heightmm = ddcHeightmm;
if(pScrn1->widthmm > 0) {
pScrn1->xDpi = (int)((double)pScrn1->virtualX * 25.4 / pScrn1->widthmm);
}
if(pScrn1->heightmm > 0) {
pScrn1->yDpi = (int)((double)pScrn1->virtualY * 25.4 / pScrn1->heightmm);
}
} else {
pScrn1->xDpi = pScrn1->yDpi = DEFAULT_DPI;
}
/* Sanity check */
if(pScrn1->xDpi > 0 && pScrn1->yDpi <= 0)
pScrn1->yDpi = pScrn1->xDpi;
if(pScrn1->yDpi > 0 && pScrn1->xDpi <= 0)
pScrn1->xDpi = pScrn1->yDpi;
pScrn2->xDpi = pScrn1->xDpi;
pScrn2->yDpi = pScrn1->yDpi;
if(!quiet) {
xf86DrvMsg(pScrn1->scrnIndex, from, "MergedFB: DPI set to (%d, %d)\n",
pScrn1->xDpi, pScrn1->yDpi);
}
}
void
RADEONMergedFBSetDpi(ScrnInfoPtr pScrn1, ScrnInfoPtr pScrn2, RADEONScrn2Rel srel)
{
RADEONInfoPtr info = RADEONPTR(pScrn1);
RADEONMergedFBCalcDPI(pScrn1, pScrn2, srel, FALSE);
info->MergedDPISRel = srel;
info->RADEONMergedDPIVX = pScrn1->virtualX;
info->RADEONMergedDPIVY = pScrn1->virtualY;
}
void
RADEONMergedFBResetDpi(ScrnInfoPtr pScrn, Bool force)
{
RADEONInfoPtr info = RADEONPTR(pScrn);
ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
RADEONScrn2Rel srel = ((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2Position;
/* This does the same calculation for the DPI as
* the initial run. This means that an eventually
* given -dpi command line switch will lead to
* constant dpi values, regardless of the virtual
* screen size.
* I consider this consequent. If this is undesired,
* one should use the DisplaySize parameter in the
* config file instead of the command line switch.
* The DPI will be calculated then.
*/
if(force ||
(info->MergedDPISRel != srel) ||
(info->RADEONMergedDPIVX != pScrn->virtualX) ||
(info->RADEONMergedDPIVY != pScrn->virtualY)
) {
RADEONMergedFBCalcDPI(pScrn, info->CRT2pScrn, srel, TRUE);
pScreen->mmWidth = (pScrn->virtualX * 254 + pScrn->xDpi * 5) / (pScrn->xDpi * 10);
pScreen->mmHeight = (pScrn->virtualY * 254 + pScrn->yDpi * 5) / (pScrn->yDpi * 10);
info->MergedDPISRel = srel;
info->RADEONMergedDPIVX = pScrn->virtualX;
info->RADEONMergedDPIVY = pScrn->virtualY;
}
}
/* radeon cursor helpers */
static void
RADEONChooseCursorCRTC(ScrnInfoPtr pScrn1, int x, int y)
{
RADEONInfoPtr info = RADEONPTR(pScrn1);
unsigned char *RADEONMMIO = info->MMIO;
RADEONScrn2Rel srel =
((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2Position;
ScrnInfoPtr pScrn2 = info->CRT2pScrn;
if (srel == radeonClone) {
/* show cursor 2 */
OUTREGP(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_CUR_EN,
~RADEON_CRTC2_CUR_EN);
/* show cursor 1 */
OUTREGP(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_CUR_EN,
~RADEON_CRTC_CUR_EN);
}
else {
if (((x >= pScrn1->frameX0) && (x <= pScrn1->frameX1)) &&
((y >= pScrn1->frameY0) && (y <= pScrn1->frameY1))) {
/* hide cursor 2 */
OUTREGP(RADEON_CRTC2_GEN_CNTL, 0, ~RADEON_CRTC2_CUR_EN);
/* show cursor 1 */
OUTREGP(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_CUR_EN,
~RADEON_CRTC_CUR_EN);
}
if (((x >= pScrn2->frameX0) && (x <= pScrn2->frameX1)) &&
((y >= pScrn2->frameY0) && (y <= pScrn2->frameY1))) {
/* hide cursor 1 */
OUTREGP(RADEON_CRTC_GEN_CNTL, 0, ~RADEON_CRTC_CUR_EN);
/* show cursor 2 */
OUTREGP(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_CUR_EN,
~RADEON_CRTC2_CUR_EN);
}
}
}
void
RADEONSetCursorPositionMerged(ScrnInfoPtr pScrn, int x, int y)
{
RADEONInfoPtr info = RADEONPTR(pScrn);
unsigned char *RADEONMMIO = info->MMIO;
xf86CursorInfoPtr cursor = info->cursor;
int xorigin = 0;
int yorigin = 0;
int stride = 256;
ScrnInfoPtr pScrn2 = info->CRT2pScrn;
DisplayModePtr mode1 = CDMPTR->CRT1;
DisplayModePtr mode2 = CDMPTR->CRT2;
int x1, y1, x2, y2;
int total_y1 = pScrn->frameY1 - pScrn->frameY0;
int total_y2 = pScrn2->frameY1 - pScrn2->frameY0;
if (x < 0) xorigin = -x+1;
if (y < 0) yorigin = -y+1;
/* if (y > total_y) y = total_y; */
if (xorigin >= cursor->MaxWidth) xorigin = cursor->MaxWidth - 1;
if (yorigin >= cursor->MaxHeight) yorigin = cursor->MaxHeight - 1;
x += pScrn->frameX0;
y += pScrn->frameY0;
x1 = x - info->CRT1frameX0;
y1 = y - info->CRT1frameY0;
x2 = x - pScrn2->frameX0;
y2 = y - pScrn2->frameY0;
if (y1 > total_y1)
y1 = total_y1;
if (y2 > total_y2)
y2 = total_y2;
if(mode1->Flags & V_INTERLACE)
y1 /= 2;
else if(mode1->Flags & V_DBLSCAN)
y1 *= 2;
if(mode2->Flags & V_INTERLACE)
y2 /= 2;
else if(mode2->Flags & V_DBLSCAN)
y2 *= 2;
if (x < 0)
x = 0;
if (y < 0)
y = 0;
RADEONChooseCursorCRTC(pScrn, x, y);
/* cursor1 */
OUTREG(RADEON_CUR_HORZ_VERT_OFF, (RADEON_CUR_LOCK
| (xorigin << 16)
| yorigin));
OUTREG(RADEON_CUR_HORZ_VERT_POSN, (RADEON_CUR_LOCK
| ((xorigin ? 0 : x1) << 16)
| (yorigin ? 0 : y1)));
OUTREG(RADEON_CUR_OFFSET, info->cursor_offset + yorigin * stride);
/* cursor2 */
OUTREG(RADEON_CUR2_HORZ_VERT_OFF, (RADEON_CUR2_LOCK
| (xorigin << 16)
| yorigin));
OUTREG(RADEON_CUR2_HORZ_VERT_POSN, (RADEON_CUR2_LOCK
| ((xorigin ? 0 : x2) << 16)
| (yorigin ? 0 : y2)));
OUTREG(RADEON_CUR2_OFFSET, info->cursor_offset + yorigin * stride);
}
/* radeon Xv helpers */
/* choose the crtc for the overlay for mergedfb based on the location
of the output window and the orientation of the crtcs */
void
RADEONChooseOverlayCRTC(
ScrnInfoPtr pScrn,
BoxPtr dstBox
) {
RADEONInfoPtr info = RADEONPTR(pScrn);
RADEONScrn2Rel srel =
((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2Position;
if (srel == radeonLeftOf) {
if (dstBox->x1 >= info->CRT2pScrn->frameX1)
info->OverlayOnCRTC2 = FALSE;
else
info->OverlayOnCRTC2 = TRUE;
}
if (srel == radeonRightOf) {
if (dstBox->x2 <= info->CRT2pScrn->frameX0)
info->OverlayOnCRTC2 = FALSE;
else
info->OverlayOnCRTC2 = TRUE;
}
if (srel == radeonAbove) {
if (dstBox->y1 >= info->CRT2pScrn->frameY1)
info->OverlayOnCRTC2 = FALSE;
else
info->OverlayOnCRTC2 = TRUE;
}
if (srel == radeonBelow) {
if (dstBox->y2 <= info->CRT2pScrn->frameY0)
info->OverlayOnCRTC2 = FALSE;
else
info->OverlayOnCRTC2 = TRUE;
}
}