Browse Source

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.
DavidWyand-GG 12 years ago
parent
commit
0d77cdc270

+ 4 - 4
Engine/source/gfx/D3D9/gfxD3D9CardProfiler.cpp

@@ -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 );

+ 1 - 1
Engine/source/gfx/D3D9/gfxD3D9CardProfiler.h

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

+ 2 - 0
Engine/source/gfx/D3D9/gfxD3D9Device.h

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

+ 1 - 1
Engine/source/gfx/D3D9/gfxD3D9OcclusionQuery.cpp

@@ -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!" );

+ 3 - 2
Engine/source/gfx/D3D9/gfxD3D9TextureManager.cpp

@@ -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
             }

+ 3 - 1
Engine/source/gfx/D3D9/gfxD3D9TextureManager.h

@@ -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:

+ 14 - 11
Engine/source/gfx/D3D9/pc/gfxPCD3D9Device.cpp

@@ -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);
    }

+ 2 - 2
Engine/source/gfx/D3D9/pc/gfxPCD3D9Target.cpp

@@ -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,

+ 6 - 0
Engine/source/gfx/gfxAdapter.h

@@ -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;
    }

+ 56 - 13
Engine/source/gfx/gfxInit.cpp

@@ -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;
  

+ 8 - 4
Engine/source/gfx/gfxInit.h

@@ -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 );

+ 34 - 0
Engine/source/gui/core/guiCanvas.cpp

@@ -2314,6 +2314,40 @@ DefineEngineMethod( GuiCanvas, setWindowTitle, void, ( const char* newTitle),,
 }
 
 
+DefineEngineMethod( GuiCanvas, findFirstMatchingMonitor, S32, (const char* name),,
+				   "@brief Find the first monitor index that matches the given name.\n\n"
+               "The actual match algorithm depends on the implementation.\n"
+               "@param name The name to search for.\n\n"
+				   "@return The number of monitors attached to the system, including the default monoitor.")
+{
+   return PlatformWindowManager::get()->findFirstMatchingMonitor(name);
+}
+
+DefineEngineMethod( GuiCanvas, getMonitorCount, S32, (),,
+				   "@brief Gets the number of monitors attached to the system.\n\n"
+
+				   "@return The number of monitors attached to the system, including the default monoitor.")
+{
+   return PlatformWindowManager::get()->getMonitorCount();
+}
+
+DefineEngineMethod( GuiCanvas, getMonitorName, const char*, (S32 index),,
+				   "@brief Gets the name of the requested monitor.\n\n"
+               "@param index The monitor index.\n\n"
+				   "@return The name of the requested monitor.")
+{
+   return PlatformWindowManager::get()->getMonitorName(index);
+}
+
+DefineEngineMethod( GuiCanvas, getMonitorRect, RectI, (S32 index),,
+				   "@brief Gets the region of the requested monitor.\n\n"
+               "@param index The monitor index.\n\n"
+				   "@return The rectangular region of the requested monitor.")
+{
+   return PlatformWindowManager::get()->getMonitorRect(index);
+}
+
+
 DefineEngineMethod( GuiCanvas, getVideoMode, const char*, (),,
 				   "@brief Gets the current screen mode as a string.\n\n"
 

+ 5 - 4
Engine/source/platform/platformVideoInfo.cpp

@@ -51,11 +51,10 @@ bool PlatformVideoInfo::profileAdapters()
    // Query the number of adapters
    String tempString;
 
-   mAdapters.increment( 1 );
-   //if( !_queryProperty( PVI_NumAdapters, 0, &tempString ) )
-   //   return false;
+   if( !_queryProperty( PVI_NumAdapters, 0, &tempString ) )
+      return false;
 
-   //mAdapters.increment( dAtoi( tempString ) );
+   mAdapters.increment( dAtoi( tempString ) );
 
    U32 adapterNum = 0;
    for( Vector<PVIAdapter>::iterator itr = mAdapters.begin(); itr != mAdapters.end(); itr++ )
@@ -85,6 +84,8 @@ bool PlatformVideoInfo::profileAdapters()
 #undef _QUERY_MASK_HELPER
 
       // Test flags here for success
+
+      ++adapterNum;
    }
 
    return true;

+ 23 - 1
Engine/source/platformWin32/videoInfo/wmiVideoInfo.cpp

@@ -119,7 +119,7 @@ struct DXDIAG_INIT_PARAMS
 
 struct IDxDiagContainer : public IUnknown
 {
-   virtual HRESULT   STDMETHODCALLTYPE GetNumberOfChildContaiiners( DWORD* pdwCount ) = 0;
+   virtual HRESULT   STDMETHODCALLTYPE GetNumberOfChildContainers( DWORD* pdwCount ) = 0;
    virtual HRESULT   STDMETHODCALLTYPE EnumChildContainerNames( DWORD dwIndex, LPWSTR pwszContainer, DWORD cchContainer ) = 0;
    virtual HRESULT   STDMETHODCALLTYPE GetChildContainer( LPCWSTR pwszContainer, IDxDiagContainer** ppInstance ) = 0;
    virtual HRESULT   STDMETHODCALLTYPE GetNumberOfProps( DWORD* pdwCount ) = 0;
@@ -361,6 +361,28 @@ bool WMIVideoInfo::_queryPropertyDxDiag( const PVIQueryType queryType, const U32
       IDxDiagContainer* displayDevicesContainer = 0;
       IDxDiagContainer* deviceContainer = 0;
 
+      // Special case to deal with PVI_NumAdapters
+      if(queryType == PVI_NumAdapters)
+      {
+         DWORD count = 0;
+         String value;
+
+         if( mDxDiagProvider->GetRootContainer( &rootContainer ) == S_OK
+            && rootContainer->GetChildContainer( L"DxDiag_DisplayDevices", &displayDevicesContainer ) == S_OK
+            && displayDevicesContainer->GetNumberOfChildContainers( &count ) == S_OK )
+         {
+            value = String::ToString("%d", count);
+         }
+
+         if( rootContainer )
+            SAFE_RELEASE( rootContainer );
+         if( displayDevicesContainer )
+            SAFE_RELEASE( displayDevicesContainer );
+
+         *outValue = value;
+         return true;
+      }
+
       WCHAR adapterIdString[ 2 ];
       adapterIdString[ 0 ] = L'0' + adapterId;
       adapterIdString[ 1 ] = L'\0';

+ 19 - 0
Engine/source/windowManager/platformWindowMgr.h

@@ -71,6 +71,25 @@ public:
    /// @return The current desktop bit depth, or Point2I(-1,-1) if an error occurred
    virtual Point2I getDesktopResolution() = 0;
 
+   // Build out the monitor list.
+   virtual void buildMonitorsList() {}
+
+   // Find the first monitor index that matches the given name.  The actual match
+   // algorithm depends on the implementation.  Provides a default value of -1 to
+   // indicate no match.
+   virtual S32 findFirstMatchingMonitor(const char* name) { return -1; }
+
+   // Retrieve the number of monitors.  Provides a default count of 0 for systems that
+   // don't provide information on connected monitors.
+   virtual U32 getMonitorCount() { return 0; }
+
+   // Get the name of the requested monitor.  Provides a default of "" for platorms
+   // that do not provide information on connected monitors.
+   virtual const char* getMonitorName(U32 index) { return ""; }
+
+   // Get the requested monitor's rectangular region.
+   virtual RectI getMonitorRect(U32 index) { return RectI(0, 0, 0, 0); }
+
    /// Populate a vector with all monitors and their extents in window space.
    virtual void getMonitorRegions(Vector<RectI> &regions) = 0;
 

+ 3 - 0
Engine/source/windowManager/win32/win32Window.cpp

@@ -667,6 +667,9 @@ LRESULT PASCAL Win32Window::WindowProc( HWND hWnd, UINT message, WPARAM wParam,
 	{
 
 	case WM_DISPLAYCHANGE:
+      // Update the monitor list
+      PlatformWindowManager::get()->buildMonitorsList();
+
 		if(window && window->isVisible() && !window->mSuppressReset && window->getVideoMode().bitDepth != wParam)
 		{
 			Con::warnf("Win32Window::WindowProc - resetting device due to display mode BPP change.");

+ 71 - 1
Engine/source/windowManager/win32/win32WindowMgr.cpp

@@ -52,6 +52,8 @@ Win32WindowManager::Win32WindowManager()
    mCurtainWindow = NULL;
 
    mOffscreenRender = false;
+
+   buildMonitorsList();
 }
 
 Win32WindowManager::~Win32WindowManager()
@@ -106,6 +108,74 @@ S32 Win32WindowManager::getDesktopBitDepth()
 }
 
 BOOL Win32WindowManager::MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData )
+{
+   Vector<MonitorInfo> * monitors = (Vector<MonitorInfo>*)dwData;
+
+   // Fill out the new monitor structure
+   monitors->increment();
+   MonitorInfo& monitor = monitors->last();
+   monitor.monitorHandle = hMonitor;
+   monitor.region.point.x = lprcMonitor->left;
+   monitor.region.point.y = lprcMonitor->top;
+   monitor.region.extent.x = lprcMonitor->right - lprcMonitor->left;
+   monitor.region.extent.y = lprcMonitor->bottom - lprcMonitor->top;
+
+   MONITORINFOEX info;
+   info.cbSize = sizeof(MONITORINFOEX);
+   if(GetMonitorInfo(hMonitor, &info))
+   {
+      monitor.name = info.szDevice;
+   }
+
+   return true;
+}
+
+void Win32WindowManager::buildMonitorsList()
+{
+   // Clear the list
+   mMonitors.clear();
+
+   // Enumerate all monitors
+   EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (U32)(void*)&mMonitors);
+}
+
+S32 Win32WindowManager::findFirstMatchingMonitor(const char* name)
+{
+   // Try and match the first part of the output device display name.  For example,
+   // a Monitor name 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.
+   for(U32 i=0; i<mMonitors.size(); ++i)
+   {
+      if(dStrstr(name, mMonitors[i].name) == name)
+         return i;
+   }
+
+   return -1;
+}
+
+U32 Win32WindowManager::getMonitorCount()
+{
+   return mMonitors.size();
+}
+
+const char* Win32WindowManager::getMonitorName(U32 index)
+{
+   if(index >= mMonitors.size())
+      return "";
+
+   return mMonitors[index].name.c_str();
+}
+
+RectI Win32WindowManager::getMonitorRect(U32 index)
+{
+   if(index >= mMonitors.size())
+      return RectI(0, 0, 0, 0);
+
+   return mMonitors[index].region;
+}
+
+BOOL Win32WindowManager::MonitorRegionEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData )
 {
    Vector<RectI> * regions = (Vector<RectI>*)dwData;
 
@@ -120,7 +190,7 @@ BOOL Win32WindowManager::MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRE
 
 void Win32WindowManager::getMonitorRegions(Vector<RectI> &regions)
 {
-   EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (U32)(void*)&regions);
+   EnumDisplayMonitors(NULL, NULL, MonitorRegionEnumProc, (U32)(void*)&regions);
 }
 
 void Win32WindowManager::getWindows(VectorPtr<PlatformWindow*> &windows)

+ 27 - 0
Engine/source/windowManager/win32/win32WindowMgr.h

@@ -56,6 +56,16 @@ class Win32WindowManager : public PlatformWindowManager
    // is intended for offscreen rendering
    bool mOffscreenRender;
 
+   /// Internal structure used when enumerating monitors
+   struct MonitorInfo {
+      HMONITOR monitorHandle;
+      RectI    region;
+      String   name;
+   };
+
+   /// Array of enumerated monitors
+   Vector<MonitorInfo> mMonitors;
+
    /// Callback to receive information about available monitors.
    static BOOL CALLBACK MonitorEnumProc(
       HMONITOR hMonitor,  // handle to display monitor
@@ -64,6 +74,14 @@ class Win32WindowManager : public PlatformWindowManager
       LPARAM dwData       // data
       );
 
+   /// Callback to receive information about available monitor regions
+   static BOOL CALLBACK MonitorRegionEnumProc(
+      HMONITOR hMonitor,  // handle to display monitor
+      HDC hdcMonitor,     // handle to monitor DC
+      LPRECT lprcMonitor, // monitor intersection rectangle
+      LPARAM dwData       // data
+      );
+
    /// If a curtain window is present, then its HWND will be stored here.
    HWND mCurtainWindow;
 
@@ -75,6 +93,15 @@ public:
    virtual S32       getDesktopBitDepth();
    virtual Point2I   getDesktopResolution();
 
+   /// Build out the monitors list.  Also used to rebuild the list after
+   /// a WM_DISPLAYCHANGE message.
+   virtual void buildMonitorsList();
+
+   virtual S32 findFirstMatchingMonitor(const char* name);
+   virtual U32 getMonitorCount();
+   virtual const char* getMonitorName(U32 index);
+   virtual RectI getMonitorRect(U32 index);
+
    virtual void getMonitorRegions(Vector<RectI> &regions);
    virtual PlatformWindow *createWindow(GFXDevice *device, const GFXVideoMode &mode);
    virtual void getWindows(VectorPtr<PlatformWindow*> &windows);