You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
793 lines
22 KiB
793 lines
22 KiB
/*==LICENSE==* |
|
|
|
CyanWorlds.com Engine - MMOG client, server and tools |
|
Copyright (C) 2011 Cyan Worlds, Inc. |
|
|
|
This program is free software: you can redistribute it and/or modify |
|
it under the terms of the GNU General Public License as published by |
|
the Free Software Foundation, either version 3 of the License, or |
|
(at your option) any later version. |
|
|
|
This program is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
GNU General Public License for more details. |
|
|
|
You should have received a copy of the GNU General Public License |
|
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
|
|
Additional permissions under GNU GPL version 3 section 7 |
|
|
|
If you modify this Program, or any covered work, by linking or |
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, |
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent |
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK |
|
(or a modified version of those libraries), |
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, |
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG |
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the |
|
licensors of this Program grant you additional |
|
permission to convey the resulting work. Corresponding Source for a |
|
non-source form of such a combination shall include the source code for |
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered |
|
work. |
|
|
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com |
|
or by snail mail at: |
|
Cyan Worlds, Inc. |
|
14617 N Newport Hwy |
|
Mead, WA 99021 |
|
|
|
*==LICENSE==*/ |
|
|
|
//#define DYNAHEADER_CREATE_STORAGE |
|
|
|
#include "hsTypes.h" |
|
|
|
#include <time.h> |
|
|
|
#include "hsWindows.h" |
|
|
|
#include "hsG3DDeviceSelector.h" |
|
#include "hsStream.h" |
|
#include "hsUtils.h" |
|
#include "plPipeline.h" |
|
|
|
/////////////////////////////////////////////////// |
|
/////////////////////////////////////////////////// |
|
/////////////////////////////////////////////////// |
|
hsG3DDeviceMode::hsG3DDeviceMode() |
|
: fWidth(0), fHeight(0), |
|
fDepth(0), |
|
fFlags(kNone) |
|
{ |
|
} |
|
|
|
hsG3DDeviceMode::~hsG3DDeviceMode() |
|
{ |
|
Clear(); |
|
} |
|
|
|
hsBool hsG3DDeviceMode::operator< (const hsG3DDeviceMode &mode) const |
|
{ |
|
// Color depth overrides everything else |
|
if (fDepth < mode.GetColorDepth()) |
|
return true; |
|
// Only compare width and height if the color depth is the same |
|
else if (fDepth == mode.GetColorDepth() ) |
|
{ |
|
if( fWidth < mode.GetWidth() ) |
|
return true; |
|
else if( fWidth == mode.GetWidth() && fHeight < mode.GetHeight() ) |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
void hsG3DDeviceMode::Clear() |
|
{ |
|
fFlags = kNone; |
|
fWidth = 0; |
|
fHeight = 0; |
|
fDepth = 0; |
|
fZStencilDepths.Reset(); |
|
fFSAATypes.Reset(); |
|
} |
|
|
|
/////////////////////////////////////////////////// |
|
/////////////////////////////////////////////////// |
|
/////////////////////////////////////////////////// |
|
|
|
hsG3DDeviceRecord::hsG3DDeviceRecord() |
|
: fFlags(kNone), |
|
fG3DDeviceType(hsG3DDeviceSelector::kDevTypeUnknown), |
|
fG3DDriverDesc(nil), fG3DDriverName(nil), fG3DDriverVersion(nil), fG3DDeviceDesc(nil), |
|
fLayersAtOnce(0), fMemoryBytes(0), |
|
fG3DHALorHEL(hsG3DDeviceSelector::kHHTypeUnknown), |
|
fZBiasRating( 0 ), fLODBiasRating( 0 ), |
|
fFogExpApproxStart( 0.0 ), fFogExp2ApproxStart( 0.0 ), fFogEndBias( 0.0 ), fMaxAnisotropicSamples( 1 ) |
|
{ |
|
SetFogKneeParams( kFogExp, 0, 0 ); |
|
SetFogKneeParams( kFogExp2, 0, 0 ); |
|
} |
|
|
|
hsG3DDeviceRecord::~hsG3DDeviceRecord() |
|
{ |
|
Clear(); |
|
} |
|
|
|
hsG3DDeviceRecord::hsG3DDeviceRecord(const hsG3DDeviceRecord& src) |
|
: fFlags(kNone), |
|
fG3DDeviceType(hsG3DDeviceSelector::kDevTypeUnknown), |
|
fG3DDriverDesc(nil), fG3DDriverName(nil), fG3DDriverVersion(nil), fG3DDeviceDesc(nil), |
|
fG3DHALorHEL(hsG3DDeviceSelector::kHHTypeUnknown), |
|
fZBiasRating( src.fZBiasRating ), fLODBiasRating( 0 ), |
|
fFogExpApproxStart( src.fFogExpApproxStart ), fFogExp2ApproxStart( src.fFogExp2ApproxStart ), |
|
fFogEndBias( src.fFogEndBias ), fMaxAnisotropicSamples( src.fMaxAnisotropicSamples ) |
|
{ |
|
*this = src; |
|
} |
|
|
|
hsG3DDeviceRecord& hsG3DDeviceRecord::operator=(const hsG3DDeviceRecord& src) |
|
{ |
|
fFlags = src.fFlags; |
|
|
|
SetG3DDeviceType(src.GetG3DDeviceType()); |
|
SetG3DHALorHEL(src.GetG3DHALorHEL()); |
|
|
|
SetDriverDesc(src.GetDriverDesc()); |
|
SetDriverName(src.GetDriverName()); |
|
SetDriverVersion(src.GetDriverVersion()); |
|
SetDeviceDesc(src.GetDeviceDesc()); |
|
|
|
fCaps = src.fCaps; |
|
fLayersAtOnce = src.fLayersAtOnce; |
|
fMemoryBytes = src.fMemoryBytes; |
|
fZBiasRating = src.fZBiasRating; |
|
fLODBiasRating = src.fLODBiasRating; |
|
fFogExpApproxStart = src.fFogExpApproxStart; |
|
fFogExp2ApproxStart = src.fFogExp2ApproxStart; |
|
fFogEndBias = src.fFogEndBias; |
|
|
|
fModes.SetCount(src.fModes.GetCount()); |
|
int i; |
|
for( i = 0; i < fModes.GetCount(); i++ ) |
|
fModes[i] = src.fModes[i]; |
|
|
|
fFogKnees[ 0 ] = src.fFogKnees[ 0 ]; |
|
fFogKnees[ 1 ] = src.fFogKnees[ 1 ]; |
|
fFogKneeVals[ 0 ] = src.fFogKneeVals[ 0 ]; |
|
fFogKneeVals[ 1 ] = src.fFogKneeVals[ 1 ]; |
|
|
|
fAASetting = src.fAASetting; |
|
|
|
fMaxAnisotropicSamples = src.fMaxAnisotropicSamples; |
|
|
|
return *this; |
|
} |
|
|
|
void hsG3DDeviceRecord::SetDriverDesc( const char *s ) |
|
{ |
|
delete [] fG3DDriverDesc; |
|
fG3DDriverDesc = s ? hsStrcpy(s) : nil; |
|
} |
|
|
|
void hsG3DDeviceRecord::SetDriverName( const char *s ) |
|
{ |
|
delete [] fG3DDriverName; |
|
fG3DDriverName = s ? hsStrcpy(s) : nil; |
|
} |
|
|
|
void hsG3DDeviceRecord::SetDriverVersion( const char *s ) |
|
{ |
|
delete [] fG3DDriverVersion; |
|
fG3DDriverVersion = s ? hsStrcpy(s) : nil; |
|
} |
|
|
|
void hsG3DDeviceRecord::SetDeviceDesc( const char *s ) |
|
{ |
|
delete [] fG3DDeviceDesc; |
|
fG3DDeviceDesc = s ? hsStrcpy(s) : nil; |
|
} |
|
|
|
const char* hsG3DDeviceRecord::GetG3DDeviceTypeName() const |
|
{ |
|
static char* deviceNames[hsG3DDeviceSelector::kNumDevTypes] = { |
|
"Unknown", |
|
"Direct3D", |
|
"OpenGL" |
|
}; |
|
|
|
UInt32 devType = GetG3DDeviceType(); |
|
if( devType > hsG3DDeviceSelector::kNumDevTypes ) |
|
devType = hsG3DDeviceSelector::kDevTypeUnknown; |
|
|
|
return deviceNames[devType]; |
|
} |
|
|
|
void hsG3DDeviceRecord::RemoveDiscarded() |
|
{ |
|
int i; |
|
for( i = 0; i < fModes.GetCount(); ) |
|
{ |
|
if( fModes[i].GetDiscarded() ) |
|
{ |
|
fModes[i].Clear(); |
|
fModes.Remove(i); |
|
} |
|
else |
|
i++; |
|
} |
|
if( !fModes.GetCount() ) |
|
SetDiscarded(true); |
|
} |
|
|
|
void hsG3DDeviceRecord::ClearModes() |
|
{ |
|
int i; |
|
for( i = 0; i < fModes.GetCount(); i++ ) |
|
fModes[i].Clear(); |
|
fModes.Reset(); |
|
} |
|
|
|
void hsG3DDeviceRecord::Clear() |
|
{ |
|
fFlags = kNone; |
|
|
|
delete [] fG3DDriverDesc; |
|
fG3DDriverDesc = nil; |
|
|
|
delete [] fG3DDriverName; |
|
fG3DDriverName = nil; |
|
|
|
delete [] fG3DDriverVersion; |
|
fG3DDriverVersion = nil; |
|
|
|
delete [] fG3DDeviceDesc; |
|
fG3DDeviceDesc = nil; |
|
|
|
fCaps.Clear(); |
|
fLayersAtOnce = 0; |
|
|
|
int i; |
|
for( i = 0; i < fModes.GetCount(); i++ ) |
|
fModes[i].Clear(); |
|
fModes.Reset(); |
|
|
|
fZBiasRating = 0; |
|
fLODBiasRating = 0; |
|
fFogExpApproxStart = 0; |
|
fFogExp2ApproxStart = 0; |
|
fFogEndBias = 0; |
|
|
|
SetFogKneeParams( kFogExp, 0, 0 ); |
|
SetFogKneeParams( kFogExp2, 0, 0 ); |
|
|
|
fAASetting = 0; |
|
fMaxAnisotropicSamples = 1; |
|
} |
|
|
|
hsG3DDeviceModeRecord::hsG3DDeviceModeRecord(const hsG3DDeviceRecord& devRec, const hsG3DDeviceMode& devMode) |
|
: fDevice(devRec), fMode(devMode) |
|
{ |
|
} |
|
|
|
hsG3DDeviceModeRecord::hsG3DDeviceModeRecord() |
|
{ |
|
} |
|
|
|
hsG3DDeviceModeRecord::~hsG3DDeviceModeRecord() |
|
{ |
|
} |
|
|
|
hsG3DDeviceModeRecord::hsG3DDeviceModeRecord(const hsG3DDeviceModeRecord& src) |
|
{ |
|
*this = src; |
|
} |
|
|
|
hsG3DDeviceModeRecord& hsG3DDeviceModeRecord::operator=(const hsG3DDeviceModeRecord& src) |
|
{ |
|
fDevice = src.fDevice; |
|
fMode = src.fMode; |
|
return *this; |
|
} |
|
/////////////////////////////////////////////////// |
|
/////////////////////////////////////////////////// |
|
/////////////////////////////////////////////////// |
|
|
|
hsG3DDeviceSelector::hsG3DDeviceSelector() |
|
{ |
|
} |
|
|
|
hsG3DDeviceSelector::~hsG3DDeviceSelector() |
|
{ |
|
IClear(); |
|
} |
|
|
|
void hsG3DDeviceSelector::IRemoveDiscarded() |
|
{ |
|
int i; |
|
for( i = 0; i < fRecords.GetCount(); ) |
|
{ |
|
fRecords[i].RemoveDiscarded(); |
|
|
|
if( fRecords[i].GetDiscarded() ) |
|
{ |
|
fRecords[i].Clear(); |
|
fRecords.Remove(i); |
|
} |
|
else |
|
i++; |
|
} |
|
} |
|
|
|
void hsG3DDeviceSelector::IClear() |
|
{ |
|
int i; |
|
for( i = 0; i < fRecords.GetCount(); i++ ) |
|
fRecords[i].Clear(); |
|
fRecords.Reset(); |
|
} |
|
|
|
void hsG3DDeviceSelector::RemoveUnusableDevModes(hsBool bTough) |
|
{ |
|
for (int i = 0; i < fRecords.GetCount(); i++) |
|
{ |
|
// |
|
// Remove modes |
|
// |
|
hsTArray<hsG3DDeviceMode>& modes = fRecords[i].GetModes(); |
|
for (int j = 0; j < modes.GetCount(); j++) |
|
{ |
|
// Remove windowed modes |
|
if ((modes[j].GetWidth() == 0) && |
|
(modes[j].GetHeight() == 0) && |
|
(modes[j].GetColorDepth() == 0)) |
|
{ |
|
modes[j].SetDiscarded(true); |
|
} |
|
// If tough, remove modes less than 640x480 |
|
else if (bTough && ((modes[j].GetWidth() < 640) || (modes[j].GetHeight() < 480))) |
|
{ |
|
modes[j].SetDiscarded(true); |
|
} |
|
} |
|
|
|
// |
|
// Remove devices |
|
// |
|
if (fRecords[i].GetG3DDeviceType() == hsG3DDeviceSelector::kDevTypeUnknown) |
|
{ |
|
fRecords[i].SetDiscarded(true); |
|
} |
|
else if( fRecords[i].GetG3DDeviceType() == hsG3DDeviceSelector::kDevTypeDirect3D ) |
|
{ |
|
UInt32 totalMem; |
|
|
|
// Remove software Direct3D devices |
|
if ((fRecords[i].GetG3DHALorHEL() != hsG3DDeviceSelector::kHHD3DHALDev) && |
|
(fRecords[i].GetG3DHALorHEL() != hsG3DDeviceSelector::kHHD3DTnLHalDev)) |
|
{ |
|
fRecords[i].SetDiscarded(true); |
|
} |
|
// Remove Direct3D devices with less than 11 megs of RAM |
|
else if (bTough && ( totalMem = IAdjustDirectXMemory( fRecords[i].GetMemoryBytes() ) ) < 11*1024*1024 ) |
|
{ |
|
fRecords[i].SetDiscarded(true); |
|
} |
|
} |
|
} |
|
|
|
IRemoveDiscarded(); |
|
} |
|
|
|
//// IAdjustDirectXMemory ///////////////////////////////////////////////////// |
|
// Adjusts the number coming off of the DirectX caps for "total video memory" |
|
// to be more reflective of what is really on the board. According to |
|
// Microsoft, the best way to do this is to add in the memory necessary for |
|
// the entire desktop. Okay, whatever... |
|
|
|
UInt32 hsG3DDeviceSelector::IAdjustDirectXMemory( UInt32 cardMem ) |
|
{ |
|
#if HS_BUILD_FOR_WIN32 |
|
HDC deskDC; |
|
int width, height, bpp, total; |
|
|
|
deskDC = GetDC( nil ); |
|
width = GetDeviceCaps( deskDC, HORZRES ); |
|
height = GetDeviceCaps( deskDC, VERTRES ); |
|
bpp = GetDeviceCaps( deskDC, BITSPIXEL ); |
|
|
|
total = width * height; |
|
if( bpp > 8 ) |
|
total *= ( bpp >> 3 ); |
|
|
|
return cardMem + total; |
|
#else |
|
return cardMem; |
|
#endif |
|
} |
|
|
|
void hsG3DDeviceSelector::Enumerate(hsWinRef winRef) |
|
{ |
|
IClear(); |
|
|
|
#ifdef HS_BUILD_FOR_WIN32 |
|
/// 9.6.2000 - Create the class to use as our temporary window class |
|
WNDCLASS tempClass; |
|
|
|
strcpy( fTempWinClass, "DSTestClass" ); |
|
memset( &tempClass, 0, sizeof( tempClass ) ); |
|
tempClass.lpfnWndProc = DefWindowProc; |
|
tempClass.hInstance = GetModuleHandle( nil ); |
|
tempClass.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH ); |
|
tempClass.lpszClassName = fTempWinClass; |
|
UInt16 ret = RegisterClass(&tempClass); |
|
hsAssert(ret, "Cannot create temporary window class to test for device modes" ); |
|
#endif |
|
|
|
ITryDirect3DTnL(winRef); |
|
|
|
#ifdef HS_BUILD_FOR_WIN32 |
|
/// Get rid of the class |
|
UnregisterClass( fTempWinClass, GetModuleHandle( nil ) ); |
|
#endif |
|
} |
|
|
|
hsBool hsG3DDeviceSelector::GetDefault (hsG3DDeviceModeRecord *dmr) |
|
{ |
|
Int32 iTnL, iD3D, iOpenGL, device, mode, i; |
|
device = iTnL = iD3D = iOpenGL = mode = -1; |
|
|
|
if (device == -1) |
|
{ |
|
// Get an index for any 3D devices |
|
for (i = 0; i < fRecords.GetCount(); i++) |
|
{ |
|
switch (fRecords[i].GetG3DDeviceType()) |
|
{ |
|
case kDevTypeDirect3D: |
|
if (fRecords[i].GetG3DHALorHEL() == kHHD3DTnLHalDev) |
|
{ |
|
if (iTnL == -1 |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
|| plPipeline::fInitialPipeParams.ForceSecondMonitor |
|
#endif // PLASMA_EXTERNAL_RELEASE |
|
) |
|
{ |
|
iTnL = i; |
|
} |
|
} |
|
else if (fRecords[i].GetG3DHALorHEL() == kHHD3DHALDev ) |
|
{ |
|
if (iD3D == -1 |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
|| plPipeline::fInitialPipeParams.ForceSecondMonitor |
|
#endif // PLASMA_EXTERNAL_RELEASE |
|
) |
|
{ |
|
iD3D = i; |
|
} |
|
} |
|
break; |
|
|
|
case kDevTypeOpenGL: |
|
if (iOpenGL == -1 |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
|| plPipeline::fInitialPipeParams.ForceSecondMonitor |
|
#endif // PLASMA_EXTERNAL_RELEASE |
|
) |
|
{ |
|
iOpenGL = i; |
|
} |
|
break; |
|
} |
|
} |
|
|
|
// Pick a default device (Priority D3D T&L, D3D HAL, OpenGL) |
|
if (iTnL != -1) |
|
device = iTnL; |
|
else if (iD3D != -1) |
|
device = iD3D; |
|
else if (iOpenGL != -1) |
|
device = iOpenGL; |
|
else |
|
return false; |
|
} |
|
|
|
// |
|
// Try and find the default mode |
|
// |
|
hsTArray<hsG3DDeviceMode>& modes = fRecords[device].GetModes(); |
|
|
|
// If there are no modes (for some insane reason), fail |
|
if (modes.GetCount() == 0) |
|
return false; |
|
|
|
for (i = 0; i < modes.GetCount(); i++) |
|
{ |
|
if ((modes[i].GetWidth() == kDefaultWidth) && |
|
(modes[i].GetHeight() == kDefaultHeight) && |
|
(modes[i].GetNumZStencilDepths() > 0)) |
|
{ |
|
// Don't be too picky about the depth, use what's available if the |
|
// default isn't found. |
|
if (mode == -1 || modes[mode].GetColorDepth() != kDefaultDepth) |
|
mode = i; |
|
} |
|
} |
|
// Default mode not found, what kind of card is this?! |
|
// Regardless, just use the first mode since this isn't a fatal error. |
|
if (mode == -1) |
|
mode = 0; |
|
|
|
*dmr = hsG3DDeviceModeRecord(fRecords[device], modes[mode]); |
|
|
|
return true; |
|
} |
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
//// Fudging Routines ///////////////////////////////////////////////////////// |
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
|
namespace |
|
{ |
|
/// Here's our CFT--Chipset Fudgefactor Table |
|
/// The table consists of entries for each of our supported chipsets in the table, |
|
/// plus, flags to be forced set and flags to be forced cleared. Also included |
|
/// is a Z-buffer suckiness rating, which represents how badly we need to bias |
|
/// the z and w values to avoid z-buffer artifacts, stored as an hsScalar (i.e |
|
/// a float). A rating of 0 means very good/default (read: Nvidia), while, say, |
|
/// a 9.0 (i.e. shift the scale 9 times above normal) means s****y, like, say, |
|
/// a Savage4. Also also included is a forced value for max # of layers (0 means |
|
/// to use default). Also also also included is an LOD rating indicating how much |
|
/// (and in which direction) to alter the base LOD bias value for this device. General |
|
/// interpretation of this value is to add (-lodRating) to the LOD bias value. |
|
/// This is because the LOD bias starts out negative and typically goes in 0.25 |
|
/// increments. |
|
/// Also also ALSO included are three new values for fog tweaking. The first two-- |
|
/// fFogExp/Exp2ApproxStart, are the start of the linear approximation of exponential |
|
/// fog. Tweak these to adjust the linear approximation on any cards that don't support |
|
/// exponential and exponential-squared fog natively. The third value is the fFogEndBias-- |
|
/// this is a value (stored as a percentage of the max possible fog value) to add on to |
|
/// to the linear fog-end parameter AFTER ALL CALCULATIONS. This is so we can, for |
|
/// example, tweak the end of the fog on the ATI Rage cards to not fog out as quickly. |
|
/// 9.14.2000 - fog end bias now has a new meaning. What it *really* represents is the |
|
/// quantization of fog on a particular card, where the end bias = ( 2^bitdepth - 2 ) / ( 2^bitdepth - 1 ) |
|
/// So, for 8 bit fog, we end up with 254 / 255, etc. So far, everything is set to 8 |
|
/// bit fog, but we have it here just in case we need to change it in the future. |
|
|
|
enum { |
|
kDefaultChipset = 0x00, |
|
kIntelI810Chipset, |
|
kSavage2000Chipset, |
|
kS3GenericChipset, |
|
kATIRadeonChipset, |
|
kATIR8X00Chipset, |
|
kMatroxParhelia, |
|
kNVidiaGeForceFXChipset |
|
}; |
|
|
|
typedef struct |
|
{ |
|
hsScalar fFogExpApproxStart; |
|
hsScalar fFogExp2ApproxStart; |
|
hsScalar fFogEndBias; |
|
hsScalar fFogExpKnee; // Fog knees |
|
hsScalar fFogExpKneeVal; |
|
hsScalar fFogExp2Knee; |
|
hsScalar fFogExp2KneeVal; |
|
} FogTweakTable; |
|
|
|
FogTweakTable dsDefaultFogVals = { 0, 0, 254.0 / 255.0, 0.5f, 0.15f, 0.5f, 0.15f }; |
|
FogTweakTable dsi810FogVals = { 0, 0, 254.0 / 255.0, 0.6f, 0.15f, 0.4f, 0.15f }; |
|
FogTweakTable dsRadeonFogVals = { 0, 0, 254.0 / 255.0, 0.7f, 0.15f, 0.5f, 0.2f }; |
|
|
|
|
|
typedef struct { |
|
UInt8 fType; // Our chipset ID |
|
UInt32 *fFlagsToSet; |
|
UInt32 *fFlagsToClear; |
|
hsScalar fZSuckiness; // See above |
|
UInt32 fForceMaxLayers; // The max # of layers we REALLY want (0 to not force) |
|
hsScalar fLODRating; |
|
FogTweakTable *fFogTweaks; |
|
} CFTable; |
|
|
|
UInt32 dsGeForceFXCapsSet[] = { |
|
1, // First integer is always the length |
|
hsG3DDeviceSelector::kCapsNoAA }; |
|
|
|
UInt32 dsS3GenerCapsClr[] = { |
|
4, // First integer is always the length |
|
hsG3DDeviceSelector::kCapsCompressTextures, |
|
hsG3DDeviceSelector::kCapsFogExp, |
|
hsG3DDeviceSelector::kCapsFogExp2, |
|
hsG3DDeviceSelector::kCapsDoesSmallTextures }; |
|
|
|
UInt32 dsATIR8X00CapsSet[] = { |
|
2, // First integer is always the length |
|
hsG3DDeviceSelector::kCapsBadManaged, |
|
hsG3DDeviceSelector::kCapsShareDepth |
|
}; |
|
|
|
UInt32 dsATIR8X00CapsClr[] = { |
|
1, // First integer is always the lengt |
|
hsG3DDeviceSelector::kCapsDoesSmallTextures }; |
|
|
|
UInt32 dsDefaultCapsClr[] = { |
|
1, // First integer is always the length |
|
hsG3DDeviceSelector::kCapsDoesSmallTextures }; |
|
|
|
CFTable dsCFTable[] = |
|
{ |
|
// Chipset ID // F2Set // F2Clear // ZSuck // MaxLayers // LODBias // Fog Value Tables |
|
{ kDefaultChipset, nil, dsDefaultCapsClr, 0, 0, 0, &dsDefaultFogVals }, |
|
{ kNVidiaGeForceFXChipset,nil, nil, 0, 0, 0, &dsDefaultFogVals }, |
|
{ kIntelI810Chipset, nil, dsDefaultCapsClr, 4.5f, 1, -0.5f, &dsi810FogVals }, |
|
{ kATIR8X00Chipset, dsATIR8X00CapsSet, dsATIR8X00CapsClr, 0, 0, 0, &dsRadeonFogVals }, |
|
}; |
|
|
|
}; |
|
|
|
//// IFudgeDirectXDevice ////////////////////////////////////////////////////// |
|
// Checks this DirectX device against all our known types and fudges our caps |
|
// flags and bias values, etc, accordingly |
|
|
|
#ifdef HS_SELECT_DIRECT3D |
|
void hsG3DDeviceSelector::IFudgeDirectXDevice( hsG3DDeviceRecord &record, |
|
D3DEnum_DriverInfo *driverInfo, |
|
D3DEnum_DeviceInfo *deviceInfo ) |
|
{ |
|
char desc[ 512 ]; // Can't rely on D3D constant, since that's in another file now |
|
DWORD vendorID, deviceID; |
|
char *szDriver, *szDesc; |
|
|
|
|
|
/// Send it off to each D3D device, respectively |
|
if( record.GetG3DDeviceType() == kDevTypeDirect3D ) |
|
{ |
|
if( !IGetD3DCardInfo( record, driverInfo, deviceInfo, &vendorID, &deviceID, &szDriver, &szDesc ) ) |
|
{ |
|
// {} to make VC6 happy in release build |
|
hsAssert( false, "Trying to fudge D3D device but D3D support isn't in this EXE!" ); |
|
} |
|
} |
|
else |
|
{ |
|
hsAssert( false, "IFudgeDirectXDevice got a device type that support wasn't compiled for!" ); |
|
} |
|
|
|
/// So capitalization won't matter in our tests |
|
hsAssert( strlen( szDesc ) < sizeof( desc ), "D3D device description longer than expected!" ); |
|
hsStrcpy( desc, szDesc ); |
|
hsStrLower( desc ); |
|
|
|
/// Detect ATI Radeon chipset |
|
// We will probably need to differentiate between different Radeons at some point in |
|
// the future, but not now. |
|
if(stricmp( szDriver, "ati2dvag.dll" ) == 0 || strstr( desc, "radeon" ) != nil) |
|
{ |
|
int series = 0; |
|
const char* str = strstr(desc, "radeon"); |
|
if( str ) |
|
str += strlen("radeon"); |
|
if( str ) |
|
{ |
|
if( 1 == sscanf(str, "%d", &series) ) |
|
{ |
|
if( (series >= 8000) && (series < 9000) ) |
|
{ |
|
hsStatusMessage( "== Using fudge factors for ATI Radeon 8X00 chipset ==\n" ); |
|
ISetFudgeFactors( kATIR8X00Chipset, record ); |
|
} |
|
else if (( series >= 9000)) |
|
{ |
|
hsStatusMessage( "== Using fudge factors for ATI Radeon 9X00 chipset ==\n" ); |
|
ISetFudgeFactors( kATIR8X00Chipset, record ); |
|
} |
|
else |
|
{ |
|
series = 0; |
|
} |
|
} |
|
else |
|
{ |
|
series = 0; |
|
} |
|
} |
|
if(series == 0) |
|
{ |
|
hsStatusMessage( "== Using fudge factors for ATI/AMD Radeon X/HD/R chipset ==\n" ); |
|
ISetFudgeFactors( kDefaultChipset, record ); |
|
} |
|
} |
|
|
|
//// Other Cards ////////////////////////////////////////////////////////// |
|
/// Detect Intel i810 chipset |
|
else if( deviceID == 0x00007125 && |
|
( stricmp( szDriver, "i81xdd.dll" ) == 0 |
|
|| ( strstr( desc, "intel" ) != nil && strstr( desc, "810" ) != nil ) ) ) |
|
{ |
|
hsStatusMessage( "== Using fudge factors for an Intel i810 chipset ==\n" ); |
|
ISetFudgeFactors( kIntelI810Chipset, record ); |
|
} |
|
/// Detect for a GeForc FX card. We only need to nerf the really low end one. |
|
else if( strstr( desc, "nvidia" ) != nil && strstr( desc, "geforce fx 5200" ) != nil ) |
|
{ |
|
hsStatusMessage( "== Using fudge factors for an NVidia GeForceFX-based chipset ==\n" ); |
|
ISetFudgeFactors( kNVidiaGeForceFXChipset, record ); |
|
} |
|
|
|
/// Default fudge values |
|
else |
|
{ |
|
hsStatusMessage( "== Using default fudge factors ==\n" ); |
|
ISetFudgeFactors( kDefaultChipset, record ); |
|
} |
|
} |
|
#endif |
|
|
|
//// ISetFudgeFactors ///////////////////////////////////////////////////////// |
|
// Given a chipset ID, looks the values up in the CFT and sets the appropriate |
|
// values. |
|
|
|
void hsG3DDeviceSelector::ISetFudgeFactors( UInt8 chipsetID, hsG3DDeviceRecord &record ) |
|
{ |
|
int i, maxIDs, j; |
|
|
|
|
|
maxIDs = sizeof( dsCFTable ) / sizeof( dsCFTable[ 0 ] ); |
|
|
|
/// Search for our chipset |
|
for( i = 0; i < maxIDs; i++ ) |
|
{ |
|
if( dsCFTable[ i ].fType == chipsetID ) |
|
{ |
|
/// Found it! |
|
|
|
// Flags to force set |
|
if( dsCFTable[ i ].fFlagsToSet != nil ) |
|
{ |
|
for( j = 0; j < dsCFTable[ i ].fFlagsToSet[ 0 ]; j++ ) |
|
record.SetCap( dsCFTable[ i ].fFlagsToSet[ j + 1 ] ); |
|
} |
|
|
|
// Flags to force clear |
|
if( dsCFTable[ i ].fFlagsToClear != nil ) |
|
{ |
|
for( j = 0; j < dsCFTable[ i ].fFlagsToClear[ 0 ]; j++ ) |
|
record.SetCap( dsCFTable[ i ].fFlagsToClear[ j + 1 ], false ); |
|
} |
|
|
|
// Suckiness |
|
record.SetZBiasRating( dsCFTable[ i ].fZSuckiness ); |
|
|
|
// Max # of layers |
|
if( dsCFTable[ i ].fForceMaxLayers > 0 ) |
|
record.SetLayersAtOnce( dsCFTable[ i ].fForceMaxLayers ); |
|
|
|
// LOD bias rating |
|
record.SetLODBiasRating( dsCFTable[ i ].fLODRating ); |
|
|
|
// Fog tweaks |
|
FogTweakTable *fogTweaks = dsCFTable[ i ].fFogTweaks; |
|
|
|
record.SetFogApproxStarts( fogTweaks->fFogExpApproxStart, fogTweaks->fFogExp2ApproxStart ); |
|
record.SetFogEndBias( fogTweaks->fFogEndBias ); |
|
record.SetFogKneeParams( hsG3DDeviceRecord::kFogExp, fogTweaks->fFogExpKnee, fogTweaks->fFogExpKneeVal ); |
|
record.SetFogKneeParams( hsG3DDeviceRecord::kFogExp2, fogTweaks->fFogExp2Knee, fogTweaks->fFogExp2KneeVal ); |
|
|
|
if( record.GetCap(kCapsNoAA) ) |
|
{ |
|
int j; |
|
for( j = 0; j < record.GetModes().GetCount(); j++ ) |
|
record.GetModes()[j].ClearFSAATypes(); |
|
} |
|
|
|
return; |
|
} |
|
} |
|
} |
|
|
|
|