1 /* 2 ----------------------------------------------------------------------------- 3 This source file is part of OGRE 4 (Object-oriented Graphics Rendering Engine) 5 For the latest info, see http://www.ogre3d.org/ 6 7 Copyright (c) 2000-2013 Torus Knot Software Ltd 8 9 Permission is hereby granted, free of charge, to any person obtaining a copy 10 of this software and associated documentation files (the "Software"), to deal 11 in the Software without restriction, including without limitation the rights 12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 copies of the Software, and to permit persons to whom the Software is 14 furnished to do so, subject to the following conditions: 15 16 The above copyright notice and this permission notice shall be included in 17 all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 THE SOFTWARE. 26 ----------------------------------------------------------------------------- 27 */ 28 #include "OgreD3D9DeviceManager.h" 29 #include "OgreD3D9Device.h" 30 #include "OgreD3D9RenderSystem.h" 31 #include "OgreD3D9RenderWindow.h" 32 #include "OgreD3D9Driver.h" 33 #include "OgreD3D9DriverList.h" 34 #include "OgreRoot.h" 35 36 namespace Ogre 37 { 38 //--------------------------------------------------------------------- D3D9DeviceManager()39 D3D9DeviceManager::D3D9DeviceManager() 40 { 41 mActiveDevice = NULL; 42 mActiveRenderWindowDevice = NULL; 43 } 44 45 //--------------------------------------------------------------------- ~D3D9DeviceManager()46 D3D9DeviceManager::~D3D9DeviceManager() 47 { 48 DeviceIterator itDevice = mRenderDevices.begin(); 49 while (mRenderDevices.size() > 0) 50 { 51 mRenderDevices[0]->destroy(); 52 } 53 54 mActiveDevice = NULL; 55 mActiveRenderWindowDevice = NULL; 56 } 57 58 //--------------------------------------------------------------------- setActiveDevice(D3D9Device * device)59 void D3D9DeviceManager::setActiveDevice(D3D9Device* device) 60 { 61 if (mActiveDevice != device) 62 { 63 mActiveDevice = device; 64 65 D3D9RenderSystem* renderSystem = static_cast<D3D9RenderSystem*>(Root::getSingleton().getRenderSystem()); 66 D3D9DriverList* driverList = renderSystem->getDirect3DDrivers(); 67 68 // Update the active driver member. 69 for (uint i=0; i < driverList->count(); ++i) 70 { 71 D3D9Driver* currDriver = driverList->item(i); 72 if (currDriver->getAdapterNumber() == mActiveDevice->getAdapterNumber()) 73 { 74 renderSystem->mActiveD3DDriver = currDriver; 75 break; 76 } 77 } 78 79 // Invalidate active view port. 80 renderSystem->mActiveViewport = NULL; 81 } 82 } 83 84 //--------------------------------------------------------------------- getActiveDevice()85 D3D9Device* D3D9DeviceManager::getActiveDevice() 86 { 87 if (mActiveDevice == NULL) 88 { 89 OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS, 90 "Current active device is NULL !!!", 91 "D3D9RenderSystem::getActiveDevice" ); 92 } 93 94 return mActiveDevice; 95 } 96 97 //--------------------------------------------------------------------- setActiveRenderTargetDevice(D3D9Device * device)98 void D3D9DeviceManager::setActiveRenderTargetDevice(D3D9Device* device) 99 { 100 mActiveRenderWindowDevice = device; 101 if (mActiveRenderWindowDevice != NULL) 102 setActiveDevice(mActiveRenderWindowDevice); 103 } 104 105 //--------------------------------------------------------------------- getActiveRenderTargetDevice()106 D3D9Device* D3D9DeviceManager::getActiveRenderTargetDevice() 107 { 108 return mActiveRenderWindowDevice; 109 } 110 111 //--------------------------------------------------------------------- getDeviceCount()112 UINT D3D9DeviceManager::getDeviceCount() 113 { 114 return static_cast<UINT>(mRenderDevices.size()); 115 } 116 117 //--------------------------------------------------------------------- getDevice(UINT index)118 D3D9Device* D3D9DeviceManager::getDevice(UINT index) 119 { 120 return mRenderDevices[index]; 121 } 122 123 //--------------------------------------------------------------------- linkRenderWindow(D3D9RenderWindow * renderWindow)124 void D3D9DeviceManager::linkRenderWindow(D3D9RenderWindow* renderWindow) 125 { 126 D3D9Device* renderDevice; 127 128 // Detach from previous device. 129 renderDevice = renderWindow->getDevice(); 130 if (renderDevice != NULL) 131 renderDevice->detachRenderWindow(renderWindow); 132 133 D3D9RenderWindowList renderWindowsGroup; 134 135 // Select new device for this window. 136 renderDevice = selectDevice(renderWindow, renderWindowsGroup); 137 138 // Link the windows group to the new device. 139 for (uint i = 0; i < renderWindowsGroup.size(); ++i) 140 { 141 D3D9RenderWindow* currWindow = renderWindowsGroup[i]; 142 143 currWindow->setDevice(renderDevice); 144 renderDevice->attachRenderWindow(currWindow); 145 renderDevice->setAdapterOrdinalIndex(currWindow, i); 146 } 147 148 renderDevice->acquire(); 149 if (mActiveDevice == NULL) 150 setActiveDevice(renderDevice); 151 } 152 153 //--------------------------------------------------------------------- selectDevice(D3D9RenderWindow * renderWindow,D3D9RenderWindowList & renderWindowsGroup)154 D3D9Device* D3D9DeviceManager::selectDevice(D3D9RenderWindow* renderWindow, D3D9RenderWindowList& renderWindowsGroup) 155 { 156 D3D9RenderSystem* renderSystem = static_cast<D3D9RenderSystem*>(Root::getSingleton().getRenderSystem()); 157 D3D9Device* renderDevice = NULL; 158 IDirect3D9* direct3D9 = D3D9RenderSystem::getDirect3D9(); 159 UINT nAdapterOrdinal = D3DADAPTER_DEFAULT; 160 D3DDEVTYPE devType = D3DDEVTYPE_HAL; 161 DWORD extraFlags = 0; 162 D3D9DriverList* driverList = renderSystem->getDirect3DDrivers(); 163 bool nvAdapterFound = false; 164 165 166 // Default group includes at least the given render window. 167 renderWindowsGroup.push_back(renderWindow); 168 169 // Case we use nvidia performance HUD, override the device settings. 170 if (renderWindow->isNvPerfHUDEnable()) 171 { 172 // Look for 'NVIDIA NVPerfHUD' adapter (<= v4) 173 // or 'NVIDIA PerfHUD' (v5) 174 // If it is present, override default settings 175 for (UINT adapter=0; adapter < direct3D9->GetAdapterCount(); ++adapter) 176 { 177 D3D9Driver* currDriver = driverList->item(adapter); 178 const D3DADAPTER_IDENTIFIER9& currAdapterIdentifier = currDriver->getAdapterIdentifier(); 179 180 if(strstr(currAdapterIdentifier.Description, "PerfHUD") != NULL) 181 { 182 renderDevice = NULL; 183 nAdapterOrdinal = adapter; 184 renderSystem->mActiveD3DDriver = currDriver; 185 devType = D3DDEVTYPE_REF; 186 nvAdapterFound = true; 187 break; 188 } 189 } 190 } 191 192 // No special adapter should be used. 193 if (nvAdapterFound == false) 194 { 195 renderSystem->mActiveD3DDriver = findDriver(renderWindow); 196 nAdapterOrdinal = renderSystem->mActiveD3DDriver->getAdapterNumber(); 197 198 bool bTryUsingMultiheadDevice = false; 199 200 if (renderWindow->isFullScreen()) 201 { 202 bTryUsingMultiheadDevice = true; 203 if (renderSystem->getMultiheadUse() == D3D9RenderSystem::mutAuto) 204 { 205 OSVERSIONINFO osVersionInfo; 206 207 osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); 208 209 // Case version info failed -> assume we run on XP. 210 if (FALSE == GetVersionEx(&osVersionInfo)) 211 { 212 osVersionInfo.dwMajorVersion = 5; 213 } 214 215 // XP and below - multi-head will cause artifacts when vsync is on. 216 if (osVersionInfo.dwMajorVersion <= 5 && renderWindow->isVSync()) 217 { 218 bTryUsingMultiheadDevice = false; 219 LogManager::getSingleton().logMessage("D3D9 : Multi head disabled. It causes horizontal line when used in XP + VSync combination"); 220 } 221 222 // Vista and SP1 or SP2 - multi-head device can not be reset - it causes memory corruption. 223 if (osVersionInfo.dwMajorVersion == 6 && 224 (_stricmp(osVersionInfo.szCSDVersion, "Service Pack 1") == 0 || 225 _stricmp(osVersionInfo.szCSDVersion, "Service Pack 2") == 0)) 226 227 { 228 bTryUsingMultiheadDevice = false; 229 LogManager::getSingleton().logMessage("D3D9 : Multi head disabled. It causes application run time crashes when used in Vista + SP 1 or 2 combination"); 230 } 231 } 232 else 233 { 234 bTryUsingMultiheadDevice = renderSystem->getMultiheadUse() == D3D9RenderSystem::mutYes ? true : false; 235 } 236 } 237 238 239 // Check if we can create a group of render windows 240 // on the same device using the multi-head feature. 241 if (bTryUsingMultiheadDevice) 242 { 243 const D3DCAPS9& targetAdapterCaps = renderSystem->mActiveD3DDriver->getD3D9DeviceCaps(); 244 D3DCAPS9 masterAdapterCaps; 245 246 // Find the master device caps. 247 if (targetAdapterCaps.MasterAdapterOrdinal == targetAdapterCaps.AdapterOrdinal) 248 { 249 masterAdapterCaps = targetAdapterCaps; 250 } 251 else 252 { 253 for (uint i = 0; i < driverList->count(); ++i) 254 { 255 D3D9Driver* currDriver = driverList->item(i); 256 const D3DCAPS9& currDeviceCaps = currDriver->getD3D9DeviceCaps(); 257 258 if (currDeviceCaps.AdapterOrdinal == targetAdapterCaps.MasterAdapterOrdinal) 259 { 260 masterAdapterCaps = currDeviceCaps; 261 break; 262 } 263 } 264 } 265 266 // Case the master adapter can handle multiple adapters. 267 if (masterAdapterCaps.NumberOfAdaptersInGroup > 1) 268 { 269 // Create empty list of render windows composing this group. 270 renderWindowsGroup.resize(masterAdapterCaps.NumberOfAdaptersInGroup); 271 for (uint i = 0; i < renderWindowsGroup.size(); ++i) 272 renderWindowsGroup[i] = NULL; 273 274 275 // Assign the current render window to it's place in the group. 276 renderWindowsGroup[targetAdapterCaps.AdapterOrdinalInGroup] = renderWindow; 277 278 279 // For each existing window - check if it belongs to the group. 280 for (uint i = 0; i < renderSystem->mRenderWindows.size(); ++i) 281 { 282 D3D9RenderWindow* currRenderWindow = renderSystem->mRenderWindows[i]; 283 284 if (currRenderWindow->isFullScreen()) 285 { 286 D3D9Driver* currDriver = findDriver(currRenderWindow); 287 const D3DCAPS9& currDeviceCaps = currDriver->getD3D9DeviceCaps(); 288 289 if (currDeviceCaps.MasterAdapterOrdinal == masterAdapterCaps.AdapterOrdinal) 290 { 291 renderWindowsGroup[currDeviceCaps.AdapterOrdinalInGroup] = currRenderWindow; 292 break; 293 } 294 } 295 } 296 297 bool bDeviceGroupFull = true; 298 299 300 // Check if render windows group is full and ready to be driven by 301 // the master device. 302 for (uint i = 0; i < renderWindowsGroup.size(); ++i) 303 { 304 // This group misses required window -> go back to default. 305 if (renderWindowsGroup[i] == NULL) 306 { 307 bDeviceGroupFull = false; 308 renderWindowsGroup.clear(); 309 renderWindowsGroup.push_back(renderWindow); 310 break; 311 } 312 } 313 314 // Case device group is full -> we can use multi head device. 315 if (bDeviceGroupFull) 316 { 317 bool validateAllDevices = false; 318 319 for (uint i = 0; i < renderWindowsGroup.size(); ++i) 320 { 321 D3D9RenderWindow* currRenderWindow = renderWindowsGroup[i]; 322 D3D9Device* currDevice = currRenderWindow->getDevice(); 323 324 // This is the master window 325 if (i == 0) 326 { 327 // If master device exists - just release it. 328 if (currDevice != NULL) 329 { 330 renderDevice = currDevice; 331 renderDevice->release(); 332 } 333 } 334 335 // This is subordinate window. 336 else 337 { 338 // If subordinate device exists - destroy it. 339 if (currDevice != NULL) 340 { 341 currDevice->destroy(); 342 validateAllDevices = true; 343 } 344 } 345 } 346 347 // In case some device was destroyed - make sure all other devices are valid. 348 // A possible scenario is that full screen window has been destroyed and it's handle 349 // was used and the shared focus handle. All other devices used this handle and must be 350 // recreated using other handles otherwise create device will fail. 351 if (validateAllDevices) 352 { 353 for (uint i = 0; i < mRenderDevices.size(); ++i) 354 mRenderDevices[i]->validateFocusWindow(); 355 } 356 } 357 } 358 } 359 } 360 361 362 363 // Do we want to preserve the FPU mode? Might be useful for scientific apps 364 ConfigOptionMap& options = renderSystem->getConfigOptions(); 365 ConfigOptionMap::iterator opti = options.find("Floating-point mode"); 366 if (opti != options.end() && opti->second.currentValue == "Consistent") 367 extraFlags |= D3DCREATE_FPU_PRESERVE; 368 369 #if OGRE_THREAD_SUPPORT == 1 370 extraFlags |= D3DCREATE_MULTITHREADED; 371 #endif 372 373 374 // Try to find a matching device from current device list. 375 if (renderDevice == NULL) 376 { 377 for (uint i = 0; i < mRenderDevices.size(); ++i) 378 { 379 D3D9Device* currDevice = mRenderDevices[i]; 380 381 if (currDevice->getAdapterNumber() == nAdapterOrdinal && 382 currDevice->getDeviceType() == devType && 383 currDevice->isFullScreen() == renderWindow->isFullScreen()) 384 { 385 renderDevice = currDevice; 386 break; 387 } 388 } 389 } 390 391 // No matching device found -> try reference device type (might have been 392 // previously created as a fallback, but don't change devType because HAL 393 // should be preferred on creation) 394 if (renderDevice == NULL) 395 { 396 for (uint i = 0; i < mRenderDevices.size(); ++i) 397 { 398 D3D9Device* currDevice = mRenderDevices[i]; 399 400 if (currDevice->getAdapterNumber() == nAdapterOrdinal && 401 currDevice->getDeviceType() == D3DDEVTYPE_REF) 402 { 403 renderDevice = currDevice; 404 break; 405 } 406 } 407 } 408 409 410 // No matching device found -> create new one. 411 if (renderDevice == NULL) 412 { 413 renderDevice = OGRE_NEW D3D9Device(this, nAdapterOrdinal, direct3D9->GetAdapterMonitor(nAdapterOrdinal), devType, extraFlags); 414 mRenderDevices.push_back(renderDevice); 415 if (mActiveDevice == NULL) 416 setActiveDevice(renderDevice); 417 } 418 419 return renderDevice; 420 } 421 422 //----------------------------------------------------------------------- findDriver(D3D9RenderWindow * renderWindow)423 D3D9Driver* D3D9DeviceManager::findDriver(D3D9RenderWindow* renderWindow) 424 { 425 D3D9RenderSystem* renderSystem = static_cast<D3D9RenderSystem*>(Root::getSingleton().getRenderSystem()); 426 IDirect3D9* direct3D9 = D3D9RenderSystem::getDirect3D9(); 427 UINT nAdapterOrdinal = D3DADAPTER_DEFAULT; 428 HMONITOR hRenderWindowMonitor = NULL; 429 D3D9DriverList* driverList = renderSystem->getDirect3DDrivers(); 430 431 // Find the monitor this render window belongs to. 432 hRenderWindowMonitor = MonitorFromWindow(renderWindow->getWindowHandle(), MONITOR_DEFAULTTONEAREST); 433 434 435 // Find the matching driver using window monitor handle. 436 for (uint i = 0; i < driverList->count(); ++i) 437 { 438 D3D9Driver* currDriver = driverList->item(i); 439 HMONITOR hCurrAdpaterMonitor = direct3D9->GetAdapterMonitor(currDriver->getAdapterNumber()); 440 441 if (hCurrAdpaterMonitor == hRenderWindowMonitor) 442 { 443 return currDriver; 444 } 445 } 446 447 return NULL; 448 } 449 450 //----------------------------------------------------------------------- notifyOnDeviceDestroy(D3D9Device * device)451 void D3D9DeviceManager::notifyOnDeviceDestroy(D3D9Device* device) 452 { 453 if (device != NULL) 454 { 455 if (device == mActiveDevice) 456 mActiveDevice = NULL; 457 458 DeviceIterator itDevice = mRenderDevices.begin(); 459 while (itDevice != mRenderDevices.end()) 460 { 461 if (*itDevice == device) 462 { 463 OGRE_DELETE device; 464 mRenderDevices.erase(itDevice); 465 break; 466 } 467 ++itDevice; 468 } 469 470 if (mActiveDevice == NULL) 471 { 472 DeviceIterator itDevice = mRenderDevices.begin(); 473 if (itDevice != mRenderDevices.end()) 474 mActiveDevice = (*itDevice); 475 } 476 } 477 } 478 479 //--------------------------------------------------------------------- getDeviceFromD3D9Device(IDirect3DDevice9 * d3d9Device)480 D3D9Device* D3D9DeviceManager::getDeviceFromD3D9Device(IDirect3DDevice9* d3d9Device) 481 { 482 DeviceIterator itDevice = mRenderDevices.begin(); 483 while (itDevice != mRenderDevices.end()) 484 { 485 if ((*itDevice)->getD3D9Device() == d3d9Device) 486 { 487 return *itDevice; 488 } 489 ++itDevice; 490 } 491 492 return NULL; 493 } 494 495 //--------------------------------------------------------------------- destroyInactiveRenderDevices()496 void D3D9DeviceManager::destroyInactiveRenderDevices() 497 { 498 DeviceIterator itDevice = mRenderDevices.begin(); 499 while (itDevice != mRenderDevices.end()) 500 { 501 if ((*itDevice)->getRenderWindowCount() == 0 && 502 (*itDevice)->getLastPresentFrame() + 1 < Root::getSingleton().getNextFrameNumber()) 503 { 504 if (*itDevice == mActiveRenderWindowDevice) 505 setActiveRenderTargetDevice(NULL); 506 (*itDevice)->destroy(); 507 break; 508 } 509 ++itDevice; 510 } 511 } 512 513 } 514