📄 radeon_mergedfb.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 voidRADEONChooseCursorCRTC(ScrnInfoPtr pScrn1, int x, int y);/* mergedfb functions *//* Helper function for CRT2 monitor vrefresh/hsync options * (Taken from mga, sis drivers) */intRADEONStrToRanges(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 DisplayModePtrRADEONCopyModeNLink(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 DisplayModePtrRADEONGetModeFromName(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 DisplayModePtrRADEONFindWidestTallestMode(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 voidRADEONFindWidestTallestCommonMode(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 DisplayModePtrRADEONGenerateModeListFromLargestModes(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) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -