GFX now handles non-default adapters

The GFX (DirectX) pipeline did not respect the choice of adapter and
always went for the default one.  Normally this isn't an issue unless
you wish to target a particular adapter and display device combination.
This has been corrected.

The GFX initialize functions now attempt to find the best adapter that
matches a given display device (i.e. monitor) if one has been passed in.
To aid with choosing a display device some new monitor enumeration
methods have been added to the platform window manager.  These methods
have been exposed to the Canvas.
This commit is contained in:
DavidWyand-GG 2013-04-09 12:50:17 -04:00
parent 1ed1a41256
commit 0d77cdc270
18 changed files with 282 additions and 45 deletions

View file

@ -30,9 +30,9 @@
#endif
GFXD3D9CardProfiler::GFXD3D9CardProfiler() : GFXCardProfiler()
GFXD3D9CardProfiler::GFXD3D9CardProfiler(U32 adapterIndex) : GFXCardProfiler()
{
mAdapterOrdinal = adapterIndex;
}
GFXD3D9CardProfiler::~GFXD3D9CardProfiler()
@ -133,7 +133,7 @@ bool GFXD3D9CardProfiler::_queryFormat( const GFXFormat fmt, const GFXTexturePro
if(texFormat == (_D3DFORMAT)GFX_UNSUPPORTED_VAL)
return false;
HRESULT hr = pD3D->CheckDeviceFormat( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
HRESULT hr = pD3D->CheckDeviceFormat( mAdapterOrdinal, D3DDEVTYPE_HAL,
adapterFormat, usage, rType, texFormat );
bool retVal = SUCCEEDED( hr );
@ -145,7 +145,7 @@ bool GFXD3D9CardProfiler::_queryFormat( const GFXFormat fmt, const GFXTexturePro
{
usage ^= D3DUSAGE_AUTOGENMIPMAP;
hr = pD3D->CheckDeviceFormat( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
hr = pD3D->CheckDeviceFormat( mAdapterOrdinal, D3DDEVTYPE_HAL,
adapterFormat, usage, D3DRTYPE_TEXTURE, GFXD3D9TextureFormat[fmt] );
retVal = SUCCEEDED( hr );

View file

@ -36,7 +36,7 @@ private:
UINT mAdapterOrdinal;
public:
GFXD3D9CardProfiler();
GFXD3D9CardProfiler(U32 adapterIndex);
~GFXD3D9CardProfiler();
void init();

View file

@ -265,6 +265,8 @@ public:
GFXAdapterType getAdapterType(){ return Direct3D9; }
U32 getAdaterIndex() const { return mAdapterIndex; }
virtual GFXCubemap *createCubemap();
virtual F32 getPixelShaderVersion() const { return mPixVersion; }

View file

@ -114,7 +114,7 @@ GFXD3D9OcclusionQuery::OcclusionQueryStatus GFXD3D9OcclusionQuery::getStatus( bo
return Unset;
#ifdef TORQUE_GATHER_METRICS
AssertFatal( mBeginFrame < GuiTSCtrl::getFrameCount(), "GFXD3D9OcclusionQuery::getStatus - called on the same frame as begin!" );
//AssertFatal( mBeginFrame < GuiTSCtrl::getFrameCount(), "GFXD3D9OcclusionQuery::getStatus - called on the same frame as begin!" );
//U32 mTimeSinceEnd = mTimer->getElapsedMs();
//AssertFatal( mTimeSinceEnd >= 5, "GFXD3DOcculsionQuery::getStatus - less than TickMs since called ::end!" );

View file

@ -43,9 +43,10 @@ U32 GFXD3D9TextureObject::mTexCount = 0;
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
GFXD3D9TextureManager::GFXD3D9TextureManager( LPDIRECT3DDEVICE9 d3ddevice )
GFXD3D9TextureManager::GFXD3D9TextureManager( LPDIRECT3DDEVICE9 d3ddevice, U32 adapterIndex )
{
mD3DDevice = d3ddevice;
mAdapterIndex = adapterIndex;
dMemset( mCurTexSet, 0, sizeof( mCurTexSet ) );
mD3DDevice->GetDeviceCaps(&mDeviceCaps);
}
@ -183,7 +184,7 @@ void GFXD3D9TextureManager::_innerCreateTexture( GFXD3D9TextureObject *retTex,
mslevel = antialiasLevel;
#ifdef TORQUE_DEBUG
DWORD MaxSampleQualities;
d3d->getD3D()->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3dTextureFormat, FALSE, D3DMULTISAMPLE_NONMASKABLE, &MaxSampleQualities);
d3d->getD3D()->CheckDeviceMultiSampleType(mAdapterIndex, D3DDEVTYPE_HAL, d3dTextureFormat, FALSE, D3DMULTISAMPLE_NONMASKABLE, &MaxSampleQualities);
AssertFatal(mslevel < MaxSampleQualities, "Invalid AA level!");
#endif
}

View file

@ -36,8 +36,10 @@ class GFXD3D9TextureManager : public GFXTextureManager
{
friend class GFXD3D9TextureObject;
U32 mAdapterIndex;
public:
GFXD3D9TextureManager( LPDIRECT3DDEVICE9 d3ddevice );
GFXD3D9TextureManager( LPDIRECT3DDEVICE9 d3ddevice, U32 adapterIndex );
virtual ~GFXD3D9TextureManager();
protected:

View file

@ -120,7 +120,7 @@ GFXFormat GFXPCD3D9Device::selectSupportedFormat(GFXTextureProfile *profile,
usage |= D3DUSAGE_QUERY_FILTER;
D3DDISPLAYMODE mode;
D3D9Assert(mD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &mode), "Unable to get adapter mode.");
D3D9Assert(mD3D->GetAdapterDisplayMode(mAdapterIndex, &mode), "Unable to get adapter mode.");
D3DRESOURCETYPE type;
if(texture)
@ -130,7 +130,7 @@ GFXFormat GFXPCD3D9Device::selectSupportedFormat(GFXTextureProfile *profile,
for(U32 i=0; i<formats.size(); i++)
{
if(mD3D->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mode.Format,
if(mD3D->CheckDeviceFormat(mAdapterIndex, D3DDEVTYPE_HAL, mode.Format,
usage, type, GFXD3D9TextureFormat[formats[i]]) == D3D_OK)
return formats[i];
}
@ -259,9 +259,12 @@ void GFXPCD3D9Device::enumerateAdapters( Vector<GFXAdapter*> &adapterList )
D3DADAPTER_IDENTIFIER9 temp;
d3d9->GetAdapterIdentifier( adapterIndex, NULL, &temp ); // The NULL is the flags which deal with WHQL
dStrcpy( toAdd->mName, temp.Description );
dStrncpy(toAdd->mName, temp.Description, GFXAdapter::MaxAdapterNameLen);
dStrncat(toAdd->mName, " (D3D9)", GFXAdapter::MaxAdapterNameLen);
// And the output display device name
dStrncpy(toAdd->mOutputName, temp.DeviceName, GFXAdapter::MaxAdapterNameLen);
// Video mode enumeration.
Vector<D3DFORMAT> formats( __FILE__, __LINE__ );
formats.push_back( D3DFMT_R5G6B5 ); // D3DFMT_R5G6B5 - 16bit format
@ -303,10 +306,10 @@ void GFXPCD3D9Device::enumerateVideoModes()
for( S32 i = 0; i < formats.size(); i++ )
{
for( U32 j = 0; j < mD3D->GetAdapterModeCount( D3DADAPTER_DEFAULT, formats[i] ); j++ )
for( U32 j = 0; j < mD3D->GetAdapterModeCount( mAdapterIndex, formats[i] ); j++ )
{
D3DDISPLAYMODE mode;
mD3D->EnumAdapterModes( D3DADAPTER_DEFAULT, formats[i], j, &mode );
mD3D->EnumAdapterModes( mAdapterIndex, formats[i], j, &mode );
GFXVideoMode toAdd;
@ -392,7 +395,7 @@ void GFXPCD3D9Device::init( const GFXVideoMode &mode, PlatformWindow *window /*
deviceFlags |= D3DCREATE_PUREDEVICE;
#endif
hres = createDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, winHwnd, deviceFlags, &d3dpp);
hres = createDevice( mAdapterIndex, D3DDEVTYPE_HAL, winHwnd, deviceFlags, &d3dpp);
if (FAILED(hres) && hres != D3DERR_OUTOFVIDEOMEMORY)
{
@ -403,7 +406,7 @@ void GFXPCD3D9Device::init( const GFXVideoMode &mode, PlatformWindow *window /*
// try mixed mode
deviceFlags &= (~D3DCREATE_HARDWARE_VERTEXPROCESSING);
deviceFlags |= D3DCREATE_MIXED_VERTEXPROCESSING;
hres = createDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
hres = createDevice( mAdapterIndex, D3DDEVTYPE_HAL,
winHwnd, deviceFlags,
&d3dpp);
@ -413,7 +416,7 @@ void GFXPCD3D9Device::init( const GFXVideoMode &mode, PlatformWindow *window /*
Con::errorf(" Failed to create mixed mode device, trying software device");
deviceFlags &= (~D3DCREATE_MIXED_VERTEXPROCESSING);
deviceFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
hres = createDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
hres = createDevice( mAdapterIndex, D3DDEVTYPE_HAL,
winHwnd, deviceFlags,
&d3dpp);
@ -446,7 +449,7 @@ void GFXPCD3D9Device::init( const GFXVideoMode &mode, PlatformWindow *window /*
Con::printf(" Cur. D3DDevice ref count=%d", mD3DDevice->AddRef() - 1);
mD3DDevice->Release();
mTextureManager = new GFXD3D9TextureManager( mD3DDevice );
mTextureManager = new GFXD3D9TextureManager( mD3DDevice, mAdapterIndex );
// Now reacquire all the resources we trashed earlier
reacquireDefaultPoolResources();
@ -510,7 +513,7 @@ void GFXPCD3D9Device::init( const GFXVideoMode &mode, PlatformWindow *window /*
Con::printf( " Using Direct3D9Ex: %s", isD3D9Ex() ? "Yes" : "No" );
mCardProfiler = new GFXD3D9CardProfiler();
mCardProfiler = new GFXD3D9CardProfiler(mAdapterIndex);
mCardProfiler->init();
gScreenShot = new ScreenShotD3D;
@ -956,7 +959,7 @@ void GFXPCD3D9Device::_validateMultisampleParams(D3DFORMAT format, D3DMULTISAMPL
if (aatype != D3DMULTISAMPLE_NONE)
{
DWORD MaxSampleQualities;
mD3D->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, format, FALSE, D3DMULTISAMPLE_NONMASKABLE, &MaxSampleQualities);
mD3D->CheckDeviceMultiSampleType(mAdapterIndex, D3DDEVTYPE_HAL, format, FALSE, D3DMULTISAMPLE_NONMASKABLE, &MaxSampleQualities);
aatype = D3DMULTISAMPLE_NONMASKABLE;
aalevel = getMin((U32)aalevel, (U32)MaxSampleQualities-1);
}

View file

@ -248,7 +248,7 @@ void GFXPCD3D9TextureTarget::activate()
"GFXPCD3D9TextureTarget::activate() - Failed to get surface description!");
D3DFORMAT depthFormat = desc.Format;
HRESULT hr = mDevice->getD3D()->CheckDepthStencilMatch( D3DADAPTER_DEFAULT,
HRESULT hr = mDevice->getD3D()->CheckDepthStencilMatch( mDevice->getAdaterIndex(),
D3DDEVTYPE_HAL,
mDevice->mDisplayMode.Format,
renderFormat,
@ -542,7 +542,7 @@ void GFXPCD3D9WindowTarget::activate()
"GFXPCD3D9TextureTarget::activate() - Failed to get surface description!");
D3DFORMAT depthFormat = desc.Format;
HRESULT hr = mDevice->getD3D()->CheckDepthStencilMatch( D3DADAPTER_DEFAULT,
HRESULT hr = mDevice->getD3D()->CheckDepthStencilMatch( mDevice->getAdaterIndex(),
D3DDEVTYPE_HAL,
mDevice->mDisplayMode.Format,
renderFormat,

View file

@ -47,6 +47,10 @@ public:
char mName[MaxAdapterNameLen];
/// The name of the display output device for the adapter, if any.
/// For example under Windows, this could be: \\.\DISPLAY1
char mOutputName[MaxAdapterNameLen];
/// List of available full-screen modes. Windows can be any size,
/// so we do not enumerate them here.
Vector<GFXVideoMode> mAvailableModes;
@ -55,6 +59,7 @@ public:
F32 mShaderModel;
const char * getName() const { return mName; }
const char * getOutputName() const { return mOutputName; }
GFXAdapterType mType;
U32 mIndex;
CreateDeviceInstanceDelegate mCreateDeviceInstanceDelegate;
@ -64,6 +69,7 @@ public:
VECTOR_SET_ASSOCIATION( mAvailableModes );
mName[0] = 0;
mOutputName[0] = 0;
mShaderModel = 0.f;
mIndex = 0;
}

View file

@ -156,35 +156,63 @@ void GFXInit::cleanup()
SAFE_DELETE( smRegisterDeviceSignal );
}
GFXAdapter* GFXInit::getAdapterOfType( GFXAdapterType type )
bool GFXInit::compareAdapterOutputDevice(const GFXAdapter* adapter, const char* outputDevice)
{
GFXAdapter* adapter = NULL;
// If the adapter doesn't have an output display device, then it supports all of them
if(!adapter->mOutputName[0])
return true;
// Try and match the first part of the output device display name. For example,
// an adapter->mOutputName of "\\.\DISPLAY1" might correspond to a display name
// of "\\.\DISPLAY1\Monitor0". If two monitors are set up in duplicate mode then
// they will have the same 'display' part in their display name.
return (dStrstr(outputDevice, adapter->mOutputName) == outputDevice);
}
GFXAdapter* GFXInit::getAdapterOfType( GFXAdapterType type, const char* outputDevice )
{
bool testOutputDevice = false;
if(outputDevice && outputDevice[0])
testOutputDevice = true;
for( U32 i = 0; i < smAdapters.size(); i++ )
{
if( smAdapters[i]->mType == type )
{
adapter = smAdapters[i];
break;
if(testOutputDevice)
{
// Check if the output display device also matches
if(compareAdapterOutputDevice(smAdapters[i], outputDevice))
{
return smAdapters[i];
}
}
else
{
// No need to also test the output display device, so return
return smAdapters[i];
}
}
}
return adapter;
return NULL;
}
GFXAdapter* GFXInit::chooseAdapter( GFXAdapterType type)
GFXAdapter* GFXInit::chooseAdapter( GFXAdapterType type, const char* outputDevice)
{
GFXAdapter* adapter = GFXInit::getAdapterOfType(type);
GFXAdapter* adapter = GFXInit::getAdapterOfType(type, outputDevice);
if(!adapter && type != OpenGL)
{
Con::errorf("The requested renderer, %s, doesn't seem to be available."
" Trying the default, OpenGL.", getAdapterNameFromType(type));
adapter = GFXInit::getAdapterOfType(OpenGL);
adapter = GFXInit::getAdapterOfType(OpenGL, outputDevice);
}
if(!adapter)
{
Con::errorf("The OpenGL renderer doesn't seem to be available. Trying the GFXNulDevice.");
adapter = GFXInit::getAdapterOfType(NullDevice);
adapter = GFXInit::getAdapterOfType(NullDevice, "");
}
AssertFatal( adapter, "There is no rendering device available whatsoever.");
@ -226,8 +254,9 @@ GFXAdapter *GFXInit::getBestAdapterChoice()
{
// Get the user's preference for device...
const String renderer = Con::getVariable("$pref::Video::displayDevice");
GFXAdapterType adapterType = getAdapterTypeFromName(renderer);
GFXAdapter *adapter = chooseAdapter(adapterType);
const String outputDevice = Con::getVariable("$pref::Video::displayOutputDevice");
GFXAdapterType adapterType = getAdapterTypeFromName(renderer.c_str());
GFXAdapter *adapter = chooseAdapter(adapterType, outputDevice.c_str());
// Did they have one? Return it.
if(adapter)
@ -341,7 +370,7 @@ void GFXInit::enumerateAdapters()
GFXDevice *GFXInit::createDevice( GFXAdapter *adapter )
{
Con::printf("Attempting to create GFX device: %s", adapter->getName());
Con::printf("Attempting to create GFX device: %s [%s]", adapter->getName(), adapter->getOutputName());
GFXDevice* temp = adapter->mCreateDeviceInstanceDelegate(adapter->mIndex);
if (temp)
@ -387,6 +416,20 @@ DefineEngineStaticMethod( GFXInit, getAdapterName, String, ( S32 index ),,
return String::EmptyString;
}
DefineEngineStaticMethod( GFXInit, getAdapterOutputName, String, ( S32 index ),,
"Returns the name of the graphics adapter's output display device.\n"
"@param index The index of the adapter." )
{
Vector<GFXAdapter*> adapters( __FILE__, __LINE__ );
GFXInit::getAdapters(&adapters);
if(index >= 0 && index < adapters.size())
return adapters[index]->mOutputName;
Con::errorf( "GFXInit::getAdapterOutputName - Out of range adapter index." );
return String::EmptyString;
}
DefineEngineStaticMethod( GFXInit, getAdapterType, GFXAdapterType, ( S32 index ),,
"Returns the type (D3D9, D3D8, GL, Null) of a graphics adapter.\n"
"@param index The index of the adapter." )
@ -486,7 +529,7 @@ DefineEngineStaticMethod( GFXInit, createNullDevice, void, (),,
GFXInit::enumerateAdapters();
// Create a device.
GFXAdapter *a = GFXInit::chooseAdapter(NullDevice);
GFXAdapter *a = GFXInit::chooseAdapter(NullDevice, "");
GFXDevice *newDevice = GFX;

View file

@ -65,15 +65,19 @@ public:
/// Get the number of available adapters.
static S32 getAdapterCount();
/// Compares the adapter's output display device with the given output display device
static bool compareAdapterOutputDevice(const GFXAdapter* adapter, const char* outputDevice);
/// Chooses a suitable GFXAdapter, based on type, preferences, and fallbacks.
/// If the requested type is omitted, we use the prefs value.
/// If the requested type isn't found, we use fallbacks: OpenGL, NullDevice
/// This method never returns NULL.
static GFXAdapter *chooseAdapter( GFXAdapterType type);
static GFXAdapter *chooseAdapter( GFXAdapterType type, const char* outputDevice);
/// Gets the first adapter of the requested type from the list of enumerated
/// adapters. Should only call this after a call to enumerateAdapters.
static GFXAdapter *getAdapterOfType( GFXAdapterType type );
/// Gets the first adapter of the requested type (and on the requested output device)
/// from the list of enumerated adapters. Should only call this after a call to
/// enumerateAdapters.
static GFXAdapter *getAdapterOfType( GFXAdapterType type, const char* outputDevice );
/// Converts a GFXAdapterType to a string name. Useful for writing out prefs
static const char *getAdapterNameFromType( GFXAdapterType type );