diff --git a/Engine/source/gfx/D3D9/gfxD3D9CardProfiler.cpp b/Engine/source/gfx/D3D9/gfxD3D9CardProfiler.cpp index f198b8007..a2fd892fe 100644 --- a/Engine/source/gfx/D3D9/gfxD3D9CardProfiler.cpp +++ b/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 ); diff --git a/Engine/source/gfx/D3D9/gfxD3D9CardProfiler.h b/Engine/source/gfx/D3D9/gfxD3D9CardProfiler.h index f97f5d228..f4bee1fee 100644 --- a/Engine/source/gfx/D3D9/gfxD3D9CardProfiler.h +++ b/Engine/source/gfx/D3D9/gfxD3D9CardProfiler.h @@ -36,7 +36,7 @@ private: UINT mAdapterOrdinal; public: - GFXD3D9CardProfiler(); + GFXD3D9CardProfiler(U32 adapterIndex); ~GFXD3D9CardProfiler(); void init(); diff --git a/Engine/source/gfx/D3D9/gfxD3D9Device.h b/Engine/source/gfx/D3D9/gfxD3D9Device.h index 12405add2..519afd607 100644 --- a/Engine/source/gfx/D3D9/gfxD3D9Device.h +++ b/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; } diff --git a/Engine/source/gfx/D3D9/gfxD3D9OcclusionQuery.cpp b/Engine/source/gfx/D3D9/gfxD3D9OcclusionQuery.cpp index af61bf997..142896f68 100644 --- a/Engine/source/gfx/D3D9/gfxD3D9OcclusionQuery.cpp +++ b/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!" ); diff --git a/Engine/source/gfx/D3D9/gfxD3D9TextureManager.cpp b/Engine/source/gfx/D3D9/gfxD3D9TextureManager.cpp index 8eac8c03e..417d7f803 100644 --- a/Engine/source/gfx/D3D9/gfxD3D9TextureManager.cpp +++ b/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 } diff --git a/Engine/source/gfx/D3D9/gfxD3D9TextureManager.h b/Engine/source/gfx/D3D9/gfxD3D9TextureManager.h index ab7dcacbd..528cc32ef 100644 --- a/Engine/source/gfx/D3D9/gfxD3D9TextureManager.h +++ b/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: diff --git a/Engine/source/gfx/D3D9/pc/gfxPCD3D9Device.cpp b/Engine/source/gfx/D3D9/pc/gfxPCD3D9Device.cpp index 3d7f332b8..b3a1b6bd6 100644 --- a/Engine/source/gfx/D3D9/pc/gfxPCD3D9Device.cpp +++ b/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; iCheckDeviceFormat(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 &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 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); } diff --git a/Engine/source/gfx/D3D9/pc/gfxPCD3D9Target.cpp b/Engine/source/gfx/D3D9/pc/gfxPCD3D9Target.cpp index aa1f1fb3d..194e304fd 100644 --- a/Engine/source/gfx/D3D9/pc/gfxPCD3D9Target.cpp +++ b/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, diff --git a/Engine/source/gfx/gfxAdapter.h b/Engine/source/gfx/gfxAdapter.h index 834b84dbd..eccf1d7dc 100644 --- a/Engine/source/gfx/gfxAdapter.h +++ b/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 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; } diff --git a/Engine/source/gfx/gfxInit.cpp b/Engine/source/gfx/gfxInit.cpp index 304e317b4..3b0ef44e1 100644 --- a/Engine/source/gfx/gfxInit.cpp +++ b/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 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; diff --git a/Engine/source/gfx/gfxInit.h b/Engine/source/gfx/gfxInit.h index 6e2d9d8b3..f2be9dbf7 100644 --- a/Engine/source/gfx/gfxInit.h +++ b/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 ); diff --git a/Engine/source/gui/core/guiCanvas.cpp b/Engine/source/gui/core/guiCanvas.cpp index 2d29f1a78..65792e81b 100644 --- a/Engine/source/gui/core/guiCanvas.cpp +++ b/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" diff --git a/Engine/source/platform/platformVideoInfo.cpp b/Engine/source/platform/platformVideoInfo.cpp index 577d20057..197c02277 100644 --- a/Engine/source/platform/platformVideoInfo.cpp +++ b/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::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; diff --git a/Engine/source/platformWin32/videoInfo/wmiVideoInfo.cpp b/Engine/source/platformWin32/videoInfo/wmiVideoInfo.cpp index 24cfb816c..ad3bb3f99 100644 --- a/Engine/source/platformWin32/videoInfo/wmiVideoInfo.cpp +++ b/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'; diff --git a/Engine/source/windowManager/platformWindowMgr.h b/Engine/source/windowManager/platformWindowMgr.h index 8161cbba9..b744af56b 100644 --- a/Engine/source/windowManager/platformWindowMgr.h +++ b/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 ®ions) = 0; diff --git a/Engine/source/windowManager/win32/win32Window.cpp b/Engine/source/windowManager/win32/win32Window.cpp index 8908d1916..2094bc663 100644 --- a/Engine/source/windowManager/win32/win32Window.cpp +++ b/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."); diff --git a/Engine/source/windowManager/win32/win32WindowMgr.cpp b/Engine/source/windowManager/win32/win32WindowMgr.cpp index d37e7ac05..05e889c9a 100644 --- a/Engine/source/windowManager/win32/win32WindowMgr.cpp +++ b/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 * monitors = (Vector*)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()) + 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 * regions = (Vector*)dwData; @@ -120,7 +190,7 @@ BOOL Win32WindowManager::MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRE void Win32WindowManager::getMonitorRegions(Vector ®ions) { - EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (U32)(void*)®ions); + EnumDisplayMonitors(NULL, NULL, MonitorRegionEnumProc, (U32)(void*)®ions); } void Win32WindowManager::getWindows(VectorPtr &windows) diff --git a/Engine/source/windowManager/win32/win32WindowMgr.h b/Engine/source/windowManager/win32/win32WindowMgr.h index e0505680b..a5c747501 100644 --- a/Engine/source/windowManager/win32/win32WindowMgr.h +++ b/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 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 ®ions); virtual PlatformWindow *createWindow(GFXDevice *device, const GFXVideoMode &mode); virtual void getWindows(VectorPtr &windows);