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 "OgreD3D9RenderSystem.h" 29 #include "OgreD3D9Prerequisites.h" 30 #include "OgreD3D9DriverList.h" 31 #include "OgreD3D9Driver.h" 32 #include "OgreD3D9VideoModeList.h" 33 #include "OgreD3D9VideoMode.h" 34 #include "OgreD3D9RenderWindow.h" 35 #include "OgreD3D9TextureManager.h" 36 #include "OgreD3D9Texture.h" 37 #include "OgreLogManager.h" 38 #include "OgreLight.h" 39 #include "OgreMath.h" 40 #include "OgreD3D9HardwareBufferManager.h" 41 #include "OgreD3D9HardwareIndexBuffer.h" 42 #include "OgreD3D9HardwareVertexBuffer.h" 43 #include "OgreD3D9VertexDeclaration.h" 44 #include "OgreD3D9GpuProgram.h" 45 #include "OgreD3D9GpuProgramManager.h" 46 #include "OgreD3D9HLSLProgramFactory.h" 47 #include "OgreHighLevelGpuProgramManager.h" 48 #include "OgreD3D9HardwareOcclusionQuery.h" 49 #include "OgreFrustum.h" 50 #include "OgreD3D9MultiRenderTarget.h" 51 #include "OgreCompositorManager.h" 52 #include "OgreD3D9DeviceManager.h" 53 #include "OgreD3D9ResourceManager.h" 54 #include "OgreD3D9DepthBuffer.h" 55 56 #define FLOAT2DWORD(f) *((DWORD*)&f) 57 58 namespace Ogre 59 { 60 D3D9RenderSystem* D3D9RenderSystem::msD3D9RenderSystem = NULL; 61 62 //--------------------------------------------------------------------- D3D9RenderSystem(HINSTANCE hInstance)63 D3D9RenderSystem::D3D9RenderSystem( HINSTANCE hInstance ) : 64 mMultiheadUse(mutAuto), 65 mAllowDirectX9Ex(false), 66 mIsDirectX9Ex(false) 67 { 68 LogManager::getSingleton().logMessage( "D3D9 : " + getName() + " created." ); 69 70 // update singleton access pointer. 71 msD3D9RenderSystem = this; 72 73 // set the instance being passed 74 mhInstance = hInstance; 75 76 // set pointers to NULL 77 mD3D = NULL; 78 mDriverList = NULL; 79 mActiveD3DDriver = NULL; 80 mTextureManager = NULL; 81 mHardwareBufferManager = NULL; 82 mGpuProgramManager = NULL; 83 mUseNVPerfHUD = false; 84 mHLSLProgramFactory = NULL; 85 mDeviceManager = NULL; 86 mPerStageConstantSupport = false; 87 88 // Create the resource manager. 89 mResourceManager = OGRE_NEW D3D9ResourceManager(); 90 91 92 // init lights 93 for(int i = 0; i < MAX_LIGHTS; i++ ) 94 mLights[i] = 0; 95 96 // Create our Direct3D object 97 if( NULL == (mD3D = Direct3DCreate9(D3D_SDK_VERSION)) ) 98 OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Failed to create Direct3D9 object", "D3D9RenderSystem::D3D9RenderSystem" ); 99 100 // set config options defaults 101 initConfigOptions(); 102 103 // fsaa options 104 mFSAAHint = ""; 105 mFSAASamples = 0; 106 107 // set stages desc. to defaults 108 for (size_t n = 0; n < OGRE_MAX_TEXTURE_LAYERS; n++) 109 { 110 mTexStageDesc[n].autoTexCoordType = TEXCALC_NONE; 111 mTexStageDesc[n].coordIndex = 0; 112 mTexStageDesc[n].texType = D3D9Mappings::D3D_TEX_TYPE_NORMAL; 113 mTexStageDesc[n].pTex = 0; 114 mTexStageDesc[n].pVertexTex = 0; 115 } 116 117 mLastVertexSourceCount = 0; 118 119 mCurrentLights.clear(); 120 121 // Enumerate events 122 mEventNames.push_back("DeviceLost"); 123 mEventNames.push_back("DeviceRestored"); 124 } 125 //--------------------------------------------------------------------- ~D3D9RenderSystem()126 D3D9RenderSystem::~D3D9RenderSystem() 127 { 128 shutdown(); 129 130 // Deleting the HLSL program factory 131 if (mHLSLProgramFactory) 132 { 133 // Remove from manager safely 134 if (HighLevelGpuProgramManager::getSingletonPtr()) 135 HighLevelGpuProgramManager::getSingleton().removeFactory(mHLSLProgramFactory); 136 OGRE_DELETE mHLSLProgramFactory; 137 mHLSLProgramFactory = 0; 138 } 139 140 SAFE_RELEASE( mD3D ); 141 142 if (mResourceManager != NULL) 143 { 144 OGRE_DELETE mResourceManager; 145 mResourceManager = NULL; 146 } 147 148 LogManager::getSingleton().logMessage( "D3D9 : " + getName() + " destroyed." ); 149 150 msD3D9RenderSystem = NULL; 151 } 152 //--------------------------------------------------------------------- getName() const153 const String& D3D9RenderSystem::getName() const 154 { 155 static String strName( "Direct3D9 Rendering Subsystem"); 156 return strName; 157 } 158 //--------------------------------------------------------------------- getDirect3DDrivers()159 D3D9DriverList* D3D9RenderSystem::getDirect3DDrivers() 160 { 161 if( !mDriverList ) 162 mDriverList = OGRE_NEW D3D9DriverList(); 163 164 return mDriverList; 165 } 166 //--------------------------------------------------------------------- _checkMultiSampleQuality(D3DMULTISAMPLE_TYPE type,DWORD * outQuality,D3DFORMAT format,UINT adapterNum,D3DDEVTYPE deviceType,BOOL fullScreen)167 bool D3D9RenderSystem::_checkMultiSampleQuality(D3DMULTISAMPLE_TYPE type, DWORD *outQuality, D3DFORMAT format, UINT adapterNum, D3DDEVTYPE deviceType, BOOL fullScreen) 168 { 169 HRESULT hr; 170 hr = mD3D->CheckDeviceMultiSampleType( 171 adapterNum, 172 deviceType, 173 format, 174 fullScreen, 175 type, 176 outQuality); 177 178 if (SUCCEEDED(hr)) 179 return true; 180 else 181 return false; 182 } 183 //--------------------------------------------------------------------- initConfigOptions()184 void D3D9RenderSystem::initConfigOptions() 185 { 186 D3D9DriverList* driverList; 187 D3D9Driver* driver; 188 189 ConfigOption optDevice; 190 ConfigOption optAllowDirectX9Ex; 191 ConfigOption optVideoMode; 192 ConfigOption optFullScreen; 193 ConfigOption optMultihead; 194 ConfigOption optVSync; 195 ConfigOption optVSyncInterval; 196 ConfigOption optAA; 197 ConfigOption optFPUMode; 198 ConfigOption optNVPerfHUD; 199 ConfigOption optSRGB; 200 ConfigOption optResourceCeationPolicy; 201 ConfigOption optMultiDeviceMemHint; 202 ConfigOption optEnableFixedPipeline; 203 204 driverList = this->getDirect3DDrivers(); 205 206 optDevice.name = "Rendering Device"; 207 optDevice.currentValue.clear(); 208 optDevice.possibleValues.clear(); 209 optDevice.immutable = false; 210 211 optAllowDirectX9Ex.name = "Allow DirectX9Ex"; 212 optAllowDirectX9Ex.possibleValues.push_back( "Yes" ); 213 optAllowDirectX9Ex.possibleValues.push_back( "No" ); 214 optAllowDirectX9Ex.currentValue = "No"; 215 optAllowDirectX9Ex.immutable = false; 216 217 optVideoMode.name = "Video Mode"; 218 optVideoMode.currentValue = "800 x 600 @ 32-bit colour"; 219 optVideoMode.immutable = false; 220 221 optFullScreen.name = "Full Screen"; 222 optFullScreen.possibleValues.push_back( "Yes" ); 223 optFullScreen.possibleValues.push_back( "No" ); 224 optFullScreen.currentValue = "Yes"; 225 optFullScreen.immutable = false; 226 227 optMultihead.name = "Use Multihead"; 228 optMultihead.possibleValues.push_back( "Auto" ); 229 optMultihead.possibleValues.push_back( "Yes" ); 230 optMultihead.possibleValues.push_back( "No" ); 231 optMultihead.currentValue = "Auto"; 232 optMultihead.immutable = false; 233 234 optResourceCeationPolicy.name = "Resource Creation Policy"; 235 optResourceCeationPolicy.possibleValues.push_back( "Create on all devices" ); 236 optResourceCeationPolicy.possibleValues.push_back( "Create on active device" ); 237 238 if (mResourceManager->getCreationPolicy() == RCP_CREATE_ON_ACTIVE_DEVICE) 239 optResourceCeationPolicy.currentValue = "Create on active device"; 240 else if (mResourceManager->getCreationPolicy() == RCP_CREATE_ON_ALL_DEVICES) 241 optResourceCeationPolicy.currentValue = "Create on all devices"; 242 else 243 optResourceCeationPolicy.currentValue = "N/A"; 244 optResourceCeationPolicy.immutable = false; 245 246 for( unsigned j=0; j < driverList->count(); j++ ) 247 { 248 driver = driverList->item(j); 249 optDevice.possibleValues.push_back( driver->DriverDescription() ); 250 // Make first one default 251 if( j==0 ) 252 optDevice.currentValue = driver->DriverDescription(); 253 } 254 255 optVSync.name = "VSync"; 256 optVSync.immutable = false; 257 optVSync.possibleValues.push_back( "Yes" ); 258 optVSync.possibleValues.push_back( "No" ); 259 optVSync.currentValue = "No"; 260 261 optVSyncInterval.name = "VSync Interval"; 262 optVSyncInterval.immutable = false; 263 optVSyncInterval.possibleValues.push_back( "1" ); 264 optVSyncInterval.possibleValues.push_back( "2" ); 265 optVSyncInterval.possibleValues.push_back( "3" ); 266 optVSyncInterval.possibleValues.push_back( "4" ); 267 optVSyncInterval.currentValue = "1"; 268 269 optAA.name = "FSAA"; 270 optAA.immutable = false; 271 optAA.possibleValues.push_back( "None" ); 272 optAA.currentValue = "None"; 273 274 optFPUMode.name = "Floating-point mode"; 275 #if OGRE_DOUBLE_PRECISION 276 optFPUMode.currentValue = "Consistent"; 277 #else 278 optFPUMode.currentValue = "Fastest"; 279 #endif 280 optFPUMode.possibleValues.clear(); 281 optFPUMode.possibleValues.push_back("Fastest"); 282 optFPUMode.possibleValues.push_back("Consistent"); 283 optFPUMode.immutable = false; 284 285 optNVPerfHUD.currentValue = "No"; 286 optNVPerfHUD.immutable = false; 287 optNVPerfHUD.name = "Allow NVPerfHUD"; 288 optNVPerfHUD.possibleValues.push_back( "Yes" ); 289 optNVPerfHUD.possibleValues.push_back( "No" ); 290 291 292 // SRGB on auto window 293 optSRGB.name = "sRGB Gamma Conversion"; 294 optSRGB.possibleValues.push_back("Yes"); 295 optSRGB.possibleValues.push_back("No"); 296 optSRGB.currentValue = "No"; 297 optSRGB.immutable = false; 298 299 // Multiple device memory usage hint. 300 optMultiDeviceMemHint.name = "Multi device memory hint"; 301 optMultiDeviceMemHint.possibleValues.push_back("Use minimum system memory"); 302 optMultiDeviceMemHint.possibleValues.push_back("Auto hardware buffers management"); 303 optMultiDeviceMemHint.currentValue = "Use minimum system memory"; 304 optMultiDeviceMemHint.immutable = false; 305 306 optEnableFixedPipeline.name = "Fixed Pipeline Enabled"; 307 optEnableFixedPipeline.possibleValues.push_back( "Yes" ); 308 optEnableFixedPipeline.possibleValues.push_back( "No" ); 309 optEnableFixedPipeline.currentValue = "Yes"; 310 optEnableFixedPipeline.immutable = false; 311 312 mOptions[optDevice.name] = optDevice; 313 mOptions[optAllowDirectX9Ex.name] = optAllowDirectX9Ex; 314 mOptions[optVideoMode.name] = optVideoMode; 315 mOptions[optFullScreen.name] = optFullScreen; 316 mOptions[optMultihead.name] = optMultihead; 317 mOptions[optVSync.name] = optVSync; 318 mOptions[optVSyncInterval.name] = optVSyncInterval; 319 mOptions[optAA.name] = optAA; 320 mOptions[optFPUMode.name] = optFPUMode; 321 mOptions[optNVPerfHUD.name] = optNVPerfHUD; 322 mOptions[optSRGB.name] = optSRGB; 323 mOptions[optResourceCeationPolicy.name] = optResourceCeationPolicy; 324 mOptions[optMultiDeviceMemHint.name] = optMultiDeviceMemHint; 325 mOptions[optEnableFixedPipeline.name] = optEnableFixedPipeline; 326 327 refreshD3DSettings(); 328 329 } 330 //--------------------------------------------------------------------- refreshD3DSettings()331 void D3D9RenderSystem::refreshD3DSettings() 332 { 333 ConfigOption* optVideoMode; 334 D3D9Driver* driver = 0; 335 D3D9VideoMode* videoMode; 336 337 ConfigOptionMap::iterator opt = mOptions.find( "Rendering Device" ); 338 if( opt != mOptions.end() ) 339 { 340 for( unsigned j=0; j < getDirect3DDrivers()->count(); j++ ) 341 { 342 D3D9Driver* curDriver = getDirect3DDrivers()->item(j); 343 if( curDriver->DriverDescription() == opt->second.currentValue ) 344 { 345 driver = curDriver; 346 break; 347 } 348 } 349 350 if (driver) 351 { 352 opt = mOptions.find( "Video Mode" ); 353 optVideoMode = &opt->second; 354 optVideoMode->possibleValues.clear(); 355 // get vide modes for this device 356 for( unsigned k=0; k < driver->getVideoModeList()->count(); k++ ) 357 { 358 videoMode = driver->getVideoModeList()->item( k ); 359 optVideoMode->possibleValues.push_back( videoMode->getDescription() ); 360 } 361 362 // Reset video mode to default if previous doesn't avail in new possible values 363 StringVector::const_iterator itValue = 364 std::find(optVideoMode->possibleValues.begin(), 365 optVideoMode->possibleValues.end(), 366 optVideoMode->currentValue); 367 if (itValue == optVideoMode->possibleValues.end()) 368 { 369 optVideoMode->currentValue = "800 x 600 @ 32-bit colour"; 370 } 371 372 // Also refresh FSAA options 373 refreshFSAAOptions(); 374 } 375 } 376 377 } 378 //--------------------------------------------------------------------- setConfigOption(const String & name,const String & value)379 void D3D9RenderSystem::setConfigOption( const String &name, const String &value ) 380 { 381 382 LogManager::getSingleton().stream() 383 << "D3D9 : RenderSystem Option: " << name << " = " << value; 384 385 bool viewModeChanged = false; 386 387 // Find option 388 ConfigOptionMap::iterator it = mOptions.find( name ); 389 390 // Update 391 if( it != mOptions.end() ) 392 it->second.currentValue = value; 393 else 394 { 395 StringUtil::StrStreamType str; 396 str << "Option named '" << name << "' does not exist."; 397 OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS, str.str(), "D3D9RenderSystem::setConfigOption" ); 398 } 399 400 // Refresh other options if D3DDriver changed 401 if( name == "Rendering Device" ) 402 refreshD3DSettings(); 403 404 if ( name == "Allow DirectX9Ex" ) 405 { 406 if (value == "Yes") 407 mAllowDirectX9Ex = true; 408 else mAllowDirectX9Ex = false; 409 410 // Create our Direct3D object 411 if (mAllowDirectX9Ex && !mIsDirectX9Ex) 412 { 413 SAFE_RELEASE(mD3D); 414 HMODULE hD3D = LoadLibrary(TEXT("d3d9.dll")); 415 if (hD3D) 416 { 417 typedef HRESULT (WINAPI *DIRECT3DCREATE9EXFUNCTION)(UINT, IDirect3D9Ex**); 418 DIRECT3DCREATE9EXFUNCTION pfnCreate9Ex = (DIRECT3DCREATE9EXFUNCTION)GetProcAddress(hD3D, "Direct3DCreate9Ex"); 419 if (pfnCreate9Ex) 420 { 421 IDirect3D9Ex* d3dEx = NULL; 422 (*pfnCreate9Ex)(D3D_SDK_VERSION, &d3dEx); 423 d3dEx->QueryInterface(__uuidof(IDirect3D9), reinterpret_cast<void **>(&mD3D)); 424 mIsDirectX9Ex = true; 425 } 426 FreeLibrary(hD3D); 427 } 428 } 429 if ((mD3D == NULL) || (!mAllowDirectX9Ex && mIsDirectX9Ex)) 430 { 431 if ( NULL == (mD3D = Direct3DCreate9(D3D_SDK_VERSION)) ) 432 OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Failed to create Direct3D9 object", "D3D9RenderSystem::D3D9RenderSystem" ); 433 } 434 } 435 436 if( name == "Full Screen" ) 437 { 438 // Video mode is applicable 439 it = mOptions.find( "Video Mode" ); 440 if (it->second.currentValue.empty()) 441 { 442 it->second.currentValue = "800 x 600 @ 32-bit colour"; 443 viewModeChanged = true; 444 } 445 } 446 447 if( name == "Use Multihead" ) 448 { 449 if (value == "Yes") 450 mMultiheadUse = mutYes; 451 else if (value == "No") 452 mMultiheadUse = mutNo; 453 else mMultiheadUse = mutAuto; 454 } 455 456 if( name == "FSAA" ) 457 { 458 StringVector values = StringUtil::split(value, " ", 1); 459 mFSAASamples = StringConverter::parseUnsignedInt(values[0]); 460 if (values.size() > 1) 461 mFSAAHint = values[1]; 462 463 } 464 465 if( name == "Allow NVPerfHUD" ) 466 { 467 if (value == "Yes") 468 mUseNVPerfHUD = true; 469 else 470 mUseNVPerfHUD = false; 471 } 472 473 if (viewModeChanged || name == "Video Mode") 474 { 475 refreshFSAAOptions(); 476 } 477 478 if (name == "Resource Creation Policy") 479 { 480 if (value == "Create on active device") 481 mResourceManager->setCreationPolicy(RCP_CREATE_ON_ACTIVE_DEVICE); 482 else if (value == "Create on all devices") 483 mResourceManager->setCreationPolicy(RCP_CREATE_ON_ALL_DEVICES); 484 } 485 486 if (name == "Multi device memory hint") 487 { 488 if (value == "Use minimum system memory") 489 mResourceManager->setAutoHardwareBufferManagement(false); 490 else if (value == "Auto hardware buffers management") 491 mResourceManager->setAutoHardwareBufferManagement(true); 492 } 493 494 if (name == "Fixed Pipeline Enabled") 495 { 496 if (value == "Yes") 497 { 498 mEnableFixedPipeline = true; 499 } 500 else 501 mEnableFixedPipeline = false; 502 } 503 504 } 505 //--------------------------------------------------------------------- refreshFSAAOptions()506 void D3D9RenderSystem::refreshFSAAOptions() 507 { 508 509 ConfigOptionMap::iterator it = mOptions.find( "FSAA" ); 510 ConfigOption* optFSAA = &it->second; 511 optFSAA->possibleValues.clear(); 512 optFSAA->possibleValues.push_back("0"); 513 514 it = mOptions.find("Rendering Device"); 515 D3D9Driver *driver = getDirect3DDrivers()->item(it->second.currentValue); 516 if (driver) 517 { 518 it = mOptions.find("Video Mode"); 519 D3D9VideoMode *videoMode = driver->getVideoModeList()->item(it->second.currentValue); 520 if (videoMode) 521 { 522 DWORD numLevels = 0; 523 bool bOK; 524 525 for (unsigned int n = (unsigned int)D3DMULTISAMPLE_2_SAMPLES; n <= (unsigned int)D3DMULTISAMPLE_16_SAMPLES; n++) 526 { 527 bOK = this->_checkMultiSampleQuality( 528 (D3DMULTISAMPLE_TYPE)n, 529 &numLevels, 530 videoMode->getFormat(), 531 driver->getAdapterNumber(), 532 D3DDEVTYPE_HAL, 533 TRUE); 534 if (bOK) 535 { 536 optFSAA->possibleValues.push_back(StringConverter::toString(n)); 537 if (n >= 8) 538 optFSAA->possibleValues.push_back(StringConverter::toString(n) + " [Quality]"); 539 } 540 } 541 542 } 543 } 544 545 // Reset FSAA to none if previous doesn't avail in new possible values 546 StringVector::const_iterator itValue = 547 std::find(optFSAA->possibleValues.begin(), 548 optFSAA->possibleValues.end(), 549 optFSAA->currentValue); 550 if (itValue == optFSAA->possibleValues.end()) 551 { 552 optFSAA->currentValue = "0"; 553 } 554 555 } 556 //--------------------------------------------------------------------- validateConfigOptions()557 String D3D9RenderSystem::validateConfigOptions() 558 { 559 ConfigOptionMap::iterator it; 560 561 // check if video mode is selected 562 it = mOptions.find( "Video Mode" ); 563 if (it->second.currentValue.empty()) 564 return "A video mode must be selected."; 565 566 it = mOptions.find( "Rendering Device" ); 567 bool foundDriver = false; 568 D3D9DriverList* driverList = getDirect3DDrivers(); 569 for( ushort j=0; j < driverList->count(); j++ ) 570 { 571 if( driverList->item(j)->DriverDescription() == it->second.currentValue ) 572 { 573 foundDriver = true; 574 break; 575 } 576 } 577 578 if (!foundDriver) 579 { 580 // Just pick the first driver 581 setConfigOption("Rendering Device", driverList->item(0)->DriverDescription()); 582 return "Your DirectX driver name has changed since the last time you ran OGRE; " 583 "the 'Rendering Device' has been changed."; 584 } 585 586 return StringUtil::BLANK; 587 } 588 //--------------------------------------------------------------------- getConfigOptions()589 ConfigOptionMap& D3D9RenderSystem::getConfigOptions() 590 { 591 // return a COPY of the current config options 592 return mOptions; 593 } 594 //--------------------------------------------------------------------- _initialise(bool autoCreateWindow,const String & windowTitle)595 RenderWindow* D3D9RenderSystem::_initialise( bool autoCreateWindow, const String& windowTitle ) 596 { 597 RenderWindow* autoWindow = NULL; 598 LogManager::getSingleton().logMessage( "D3D9 : Subsystem Initialising" ); 599 600 // Init using current settings 601 mActiveD3DDriver = NULL; 602 ConfigOptionMap::iterator opt = mOptions.find( "Rendering Device" ); 603 for( uint j=0; j < getDirect3DDrivers()->count(); j++ ) 604 { 605 if( getDirect3DDrivers()->item(j)->DriverDescription() == opt->second.currentValue ) 606 { 607 mActiveD3DDriver = getDirect3DDrivers()->item(j); 608 break; 609 } 610 } 611 612 if( !mActiveD3DDriver ) 613 OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS, "Problems finding requested Direct3D driver!", "D3D9RenderSystem::initialise" ); 614 615 // get driver version 616 mDriverVersion.major = HIWORD(mActiveD3DDriver->getAdapterIdentifier().DriverVersion.HighPart); 617 mDriverVersion.minor = LOWORD(mActiveD3DDriver->getAdapterIdentifier().DriverVersion.HighPart); 618 mDriverVersion.release = HIWORD(mActiveD3DDriver->getAdapterIdentifier().DriverVersion.LowPart); 619 mDriverVersion.build = LOWORD(mActiveD3DDriver->getAdapterIdentifier().DriverVersion.LowPart); 620 621 // Create the device manager. 622 mDeviceManager = OGRE_NEW D3D9DeviceManager(); 623 624 // Create the texture manager for use by others 625 mTextureManager = OGRE_NEW D3D9TextureManager(); 626 627 // Also create hardware buffer manager 628 mHardwareBufferManager = OGRE_NEW D3D9HardwareBufferManager(); 629 630 // Create the GPU program manager 631 mGpuProgramManager = OGRE_NEW D3D9GpuProgramManager(); 632 633 // Create & register HLSL factory 634 mHLSLProgramFactory = OGRE_NEW D3D9HLSLProgramFactory(); 635 636 if( autoCreateWindow ) 637 { 638 bool fullScreen; 639 opt = mOptions.find( "Full Screen" ); 640 if( opt == mOptions.end() ) 641 OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Can't find full screen option!", "D3D9RenderSystem::initialise" ); 642 fullScreen = opt->second.currentValue == "Yes"; 643 644 D3D9VideoMode* videoMode = NULL; 645 unsigned int width, height; 646 String temp; 647 648 opt = mOptions.find( "Video Mode" ); 649 if( opt == mOptions.end() ) 650 OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Can't find Video Mode option!", "D3D9RenderSystem::initialise" ); 651 652 // The string we are manipulating looks like this :width x height @ colourDepth 653 // Pull out the colour depth by getting what comes after the @ and a space 654 String colourDepth = opt->second.currentValue.substr(opt->second.currentValue.rfind('@')+1); 655 // Now we know that the width starts a 0, so if we can find the end we can parse that out 656 String::size_type widthEnd = opt->second.currentValue.find(' '); 657 // we know that the height starts 3 characters after the width and goes until the next space 658 String::size_type heightEnd = opt->second.currentValue.find(' ', widthEnd+3); 659 // Now we can parse out the values 660 width = StringConverter::parseInt(opt->second.currentValue.substr(0, widthEnd)); 661 height = StringConverter::parseInt(opt->second.currentValue.substr(widthEnd+3, heightEnd)); 662 663 for( unsigned j=0; j < mActiveD3DDriver->getVideoModeList()->count(); j++ ) 664 { 665 temp = mActiveD3DDriver->getVideoModeList()->item(j)->getDescription(); 666 667 // In full screen we only want to allow supported resolutions, so temp and opt->second.currentValue need to 668 // match exactly, but in windowed mode we can allow for arbitrary window sized, so we only need 669 // to match the colour values 670 if(fullScreen && (temp == opt->second.currentValue) || 671 !fullScreen && (temp.substr(temp.rfind('@')+1) == colourDepth)) 672 { 673 videoMode = mActiveD3DDriver->getVideoModeList()->item(j); 674 break; 675 } 676 } 677 678 if( !videoMode ) 679 OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Can't find requested video mode.", "D3D9RenderSystem::initialise" ); 680 681 // sRGB window option 682 bool hwGamma = false; 683 opt = mOptions.find( "sRGB Gamma Conversion" ); 684 if( opt == mOptions.end() ) 685 OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Can't find sRGB option!", "D3D9RenderSystem::initialise" ); 686 hwGamma = opt->second.currentValue == "Yes"; 687 688 NameValuePairList miscParams; 689 miscParams["colourDepth"] = StringConverter::toString(videoMode->getColourDepth()); 690 miscParams["FSAA"] = StringConverter::toString(mFSAASamples); 691 miscParams["FSAAHint"] = mFSAAHint; 692 miscParams["useNVPerfHUD"] = StringConverter::toString(mUseNVPerfHUD); 693 miscParams["gamma"] = StringConverter::toString(hwGamma); 694 miscParams["monitorIndex"] = StringConverter::toString(static_cast<int>(mActiveD3DDriver->getAdapterNumber())); 695 696 opt = mOptions.find("VSync"); 697 if (opt == mOptions.end()) 698 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Can't find VSync options!", "D3D9RenderSystem::initialise"); 699 bool vsync = (opt->second.currentValue == "Yes"); 700 miscParams["vsync"] = StringConverter::toString(vsync); 701 702 opt = mOptions.find("VSync Interval"); 703 if (opt == mOptions.end()) 704 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Can't find VSync Interval options!", "D3D9RenderSystem::initialise"); 705 miscParams["vsyncInterval"] = opt->second.currentValue; 706 707 autoWindow = _createRenderWindow( windowTitle, width, height, 708 fullScreen, &miscParams ); 709 710 // If we have 16bit depth buffer enable w-buffering. 711 assert( autoWindow ); 712 if ( autoWindow->getColourDepth() == 16 ) 713 { 714 mWBuffer = true; 715 } 716 else 717 { 718 mWBuffer = false; 719 } 720 } 721 722 LogManager::getSingleton().logMessage("***************************************"); 723 LogManager::getSingleton().logMessage("*** D3D9 : Subsystem Initialised OK ***"); 724 LogManager::getSingleton().logMessage("***************************************"); 725 726 // call superclass method 727 RenderSystem::_initialise( autoCreateWindow ); 728 729 730 return autoWindow; 731 } 732 //--------------------------------------------------------------------- reinitialise()733 void D3D9RenderSystem::reinitialise() 734 { 735 LogManager::getSingleton().logMessage( "D3D9 : Reinitialising" ); 736 this->shutdown(); 737 this->_initialise( true ); 738 } 739 //--------------------------------------------------------------------- shutdown()740 void D3D9RenderSystem::shutdown() 741 { 742 RenderSystem::shutdown(); 743 744 if (mDeviceManager != NULL) 745 { 746 OGRE_DELETE mDeviceManager; 747 mDeviceManager = NULL; 748 } 749 750 if (mDriverList != NULL) 751 { 752 OGRE_DELETE mDriverList; 753 mDriverList = NULL; 754 } 755 mActiveD3DDriver = NULL; 756 757 LogManager::getSingleton().logMessage("D3D9 : Shutting down cleanly."); 758 759 if (mTextureManager != NULL) 760 { 761 OGRE_DELETE mTextureManager; 762 mTextureManager = NULL; 763 } 764 765 if (mHardwareBufferManager != NULL) 766 { 767 OGRE_DELETE mHardwareBufferManager; 768 mHardwareBufferManager = NULL; 769 } 770 771 if (mGpuProgramManager != NULL) 772 { 773 OGRE_DELETE mGpuProgramManager; 774 mGpuProgramManager = NULL; 775 } 776 } 777 //--------------------------------------------------------------------- _createRenderWindow(const String & name,unsigned int width,unsigned int height,bool fullScreen,const NameValuePairList * miscParams)778 RenderWindow* D3D9RenderSystem::_createRenderWindow(const String &name, 779 unsigned int width, unsigned int height, bool fullScreen, 780 const NameValuePairList *miscParams) 781 { 782 // Log a message 783 StringStream ss; 784 ss << "D3D9RenderSystem::_createRenderWindow \"" << name << "\", " << 785 width << "x" << height << " "; 786 787 if(fullScreen) 788 ss << "fullscreen "; 789 else 790 ss << "windowed "; 791 792 if(miscParams) 793 { 794 ss << " miscParams: "; 795 NameValuePairList::const_iterator it; 796 for(it=miscParams->begin(); it!=miscParams->end(); ++it) 797 { 798 ss << it->first << "=" << it->second << " "; 799 } 800 LogManager::getSingleton().logMessage(ss.str()); 801 } 802 803 String msg; 804 805 // Make sure we don't already have a render target of the 806 // same name as the one supplied 807 if( mRenderTargets.find( name ) != mRenderTargets.end() ) 808 { 809 msg = "A render target of the same name '" + name + "' already " 810 "exists. You cannot create a new window with this name."; 811 OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, msg, "D3D9RenderSystem::_createRenderWindow" ); 812 } 813 814 D3D9RenderWindow* renderWindow = OGRE_NEW D3D9RenderWindow(mhInstance); 815 816 renderWindow->create(name, width, height, fullScreen, miscParams); 817 818 mResourceManager->lockDeviceAccess(); 819 820 try 821 { 822 mDeviceManager->linkRenderWindow(renderWindow); 823 } 824 catch (const Ogre::RenderingAPIException&) 825 { 826 // after catching the exception, clean up 827 mResourceManager->unlockDeviceAccess(); 828 renderWindow->destroy(); 829 830 // re-throw 831 throw; 832 } 833 834 mResourceManager->unlockDeviceAccess(); 835 836 mRenderWindows.push_back(renderWindow); 837 838 updateRenderSystemCapabilities(renderWindow); 839 840 attachRenderTarget( *renderWindow ); 841 842 return renderWindow; 843 } 844 //--------------------------------------------------------------------- _createRenderWindows(const RenderWindowDescriptionList & renderWindowDescriptions,RenderWindowList & createdWindows)845 bool D3D9RenderSystem::_createRenderWindows(const RenderWindowDescriptionList& renderWindowDescriptions, 846 RenderWindowList& createdWindows) 847 { 848 // Call base render system method. 849 if (false == RenderSystem::_createRenderWindows(renderWindowDescriptions, createdWindows)) 850 return false; 851 852 // Simply call _createRenderWindow in a loop. 853 for (size_t i = 0; i < renderWindowDescriptions.size(); ++i) 854 { 855 const RenderWindowDescription& curRenderWindowDescription = renderWindowDescriptions[i]; 856 RenderWindow* curWindow = NULL; 857 858 curWindow = _createRenderWindow(curRenderWindowDescription.name, 859 curRenderWindowDescription.width, 860 curRenderWindowDescription.height, 861 curRenderWindowDescription.useFullScreen, 862 &curRenderWindowDescription.miscParams); 863 864 createdWindows.push_back(curWindow); 865 } 866 867 return true; 868 } 869 870 //--------------------------------------------------------------------- updateRenderSystemCapabilities(D3D9RenderWindow * renderWindow)871 RenderSystemCapabilities* D3D9RenderSystem::updateRenderSystemCapabilities(D3D9RenderWindow* renderWindow) 872 { 873 RenderSystemCapabilities* rsc = mRealCapabilities; 874 if (rsc == NULL) 875 rsc = OGRE_NEW RenderSystemCapabilities(); 876 877 rsc->setCategoryRelevant(CAPS_CATEGORY_D3D9, true); 878 rsc->setDriverVersion(mDriverVersion); 879 rsc->setDeviceName(mActiveD3DDriver->DriverDescription()); 880 rsc->setRenderSystemName(getName()); 881 882 if(mEnableFixedPipeline) 883 { 884 // Supports fixed-function 885 rsc->setCapability(RSC_FIXED_FUNCTION); 886 } 887 888 889 // Init caps to maximum. 890 rsc->setNumTextureUnits(1024); 891 rsc->setCapability(RSC_ANISOTROPY); 892 rsc->setCapability(RSC_AUTOMIPMAP); 893 rsc->setCapability(RSC_DOT3); 894 rsc->setCapability(RSC_CUBEMAPPING); 895 rsc->setCapability(RSC_SCISSOR_TEST); 896 rsc->setCapability(RSC_TWO_SIDED_STENCIL); 897 rsc->setCapability(RSC_STENCIL_WRAP); 898 rsc->setCapability(RSC_HWOCCLUSION); 899 rsc->setCapability(RSC_USER_CLIP_PLANES); 900 rsc->setCapability(RSC_VERTEX_FORMAT_UBYTE4); 901 rsc->setCapability(RSC_TEXTURE_1D); 902 rsc->setCapability(RSC_TEXTURE_3D); 903 rsc->setCapability(RSC_NON_POWER_OF_2_TEXTURES); 904 rsc->setNonPOW2TexturesLimited(false); 905 rsc->setNumMultiRenderTargets(OGRE_MAX_MULTIPLE_RENDER_TARGETS); 906 rsc->setCapability(RSC_MRT_DIFFERENT_BIT_DEPTHS); 907 rsc->setCapability(RSC_POINT_SPRITES); 908 rsc->setCapability(RSC_POINT_EXTENDED_PARAMETERS); 909 rsc->setMaxPointSize(2.19902e+012f); 910 rsc->setCapability(RSC_MIPMAP_LOD_BIAS); 911 rsc->setCapability(RSC_PERSTAGECONSTANT); 912 rsc->setCapability(RSC_HWSTENCIL); 913 rsc->setStencilBufferBitDepth(8); 914 rsc->setCapability(RSC_ADVANCED_BLEND_OPERATIONS); 915 rsc->setCapability(RSC_RTT_SEPARATE_DEPTHBUFFER); 916 rsc->setCapability(RSC_RTT_MAIN_DEPTHBUFFER_ATTACHABLE); 917 rsc->setCapability(RSC_RTT_DEPTHBUFFER_RESOLUTION_LESSEQUAL); 918 rsc->setCapability(RSC_VERTEX_BUFFER_INSTANCE_DATA); 919 rsc->setCapability(RSC_CAN_GET_COMPILED_SHADER_BUFFER); 920 921 for (uint i=0; i < mDeviceManager->getDeviceCount(); ++i) 922 { 923 D3D9Device* device = mDeviceManager->getDevice(i); 924 IDirect3DDevice9* d3d9Device = device->getD3D9Device(); 925 926 IDirect3DSurface9* pSurf; 927 928 929 // Check for hardware stencil support 930 d3d9Device->GetDepthStencilSurface(&pSurf); 931 932 if (pSurf != NULL) 933 { 934 D3DSURFACE_DESC surfDesc; 935 936 pSurf->GetDesc(&surfDesc); 937 pSurf->Release(); 938 939 if (surfDesc.Format != D3DFMT_D15S1 && 940 surfDesc.Format != D3DFMT_D24S8 && 941 surfDesc.Format != D3DFMT_D24X4S4 && 942 surfDesc.Format != D3DFMT_D24FS8) 943 rsc->unsetCapability(RSC_HWSTENCIL); 944 } 945 946 // Check for hardware occlusion support 947 HRESULT hr = d3d9Device->CreateQuery(D3DQUERYTYPE_OCCLUSION, NULL); 948 949 if (FAILED(hr)) 950 rsc->unsetCapability(RSC_HWOCCLUSION); 951 } 952 953 // Update RS caps using the minimum value found in adapter list. 954 for (unsigned int i=0; i < mDriverList->count(); ++i) 955 { 956 D3D9Driver* pCurDriver = mDriverList->item(i); 957 const D3DCAPS9& rkCurCaps = pCurDriver->getD3D9DeviceCaps(); 958 959 if (rkCurCaps.MaxSimultaneousTextures < rsc->getNumTextureUnits()) 960 { 961 rsc->setNumTextureUnits(static_cast<ushort>(rkCurCaps.MaxSimultaneousTextures)); 962 } 963 964 // Check for Anisotropy. 965 if (rkCurCaps.MaxAnisotropy <= 1) 966 rsc->unsetCapability(RSC_ANISOTROPY); 967 968 // Check automatic mipmap generation. 969 if ((rkCurCaps.Caps2 & D3DCAPS2_CANAUTOGENMIPMAP) == 0) 970 rsc->unsetCapability(RSC_AUTOMIPMAP); 971 972 // Check Dot product 3. 973 if ((rkCurCaps.TextureOpCaps & D3DTEXOPCAPS_DOTPRODUCT3) == 0) 974 rsc->unsetCapability(RSC_DOT3); 975 976 // Scissor test 977 if ((rkCurCaps.RasterCaps & D3DPRASTERCAPS_SCISSORTEST) == 0) 978 rsc->unsetCapability(RSC_SCISSOR_TEST); 979 980 981 // Two-sided stencil 982 if ((rkCurCaps.StencilCaps & D3DSTENCILCAPS_TWOSIDED) == 0) 983 rsc->unsetCapability(RSC_TWO_SIDED_STENCIL); 984 985 // stencil wrap 986 if ((rkCurCaps.StencilCaps & D3DSTENCILCAPS_INCR) == 0 || 987 (rkCurCaps.StencilCaps & D3DSTENCILCAPS_DECR) == 0) 988 rsc->unsetCapability(RSC_STENCIL_WRAP); 989 990 // User clip planes 991 if (rkCurCaps.MaxUserClipPlanes == 0) 992 rsc->unsetCapability(RSC_USER_CLIP_PLANES); 993 994 // UBYTE4 type? 995 if ((rkCurCaps.DeclTypes & D3DDTCAPS_UBYTE4) == 0) 996 rsc->unsetCapability(RSC_VERTEX_FORMAT_UBYTE4); 997 998 // Check cube map support. 999 if ((rkCurCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP) == 0) 1000 rsc->unsetCapability(RSC_CUBEMAPPING); 1001 1002 // 3D textures? 1003 if ((rkCurCaps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP) == 0) 1004 rsc->unsetCapability(RSC_TEXTURE_3D); 1005 1006 if (rkCurCaps.TextureCaps & D3DPTEXTURECAPS_POW2) 1007 { 1008 // Conditional support for non POW2 1009 if (rkCurCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) 1010 rsc->setNonPOW2TexturesLimited(true); 1011 1012 // Only power of 2 supported. 1013 else 1014 rsc->unsetCapability(RSC_NON_POWER_OF_2_TEXTURES); 1015 } 1016 1017 // Number of render targets 1018 if (rkCurCaps.NumSimultaneousRTs < rsc->getNumMultiRenderTargets()) 1019 { 1020 rsc->setNumMultiRenderTargets(std::min((ushort)rkCurCaps.NumSimultaneousRTs, (ushort)OGRE_MAX_MULTIPLE_RENDER_TARGETS)); 1021 } 1022 1023 if((rkCurCaps.PrimitiveMiscCaps & D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS) == 0) 1024 { 1025 rsc->unsetCapability(RSC_MRT_DIFFERENT_BIT_DEPTHS); 1026 } 1027 1028 // Point sprites 1029 if (rkCurCaps.MaxPointSize <= 1.0f) 1030 { 1031 rsc->unsetCapability(RSC_POINT_SPRITES); 1032 // sprites and extended parameters go together in D3D 1033 rsc->unsetCapability(RSC_POINT_EXTENDED_PARAMETERS); 1034 } 1035 1036 // Take the minimum point size. 1037 if (rkCurCaps.MaxPointSize < rsc->getMaxPointSize()) 1038 rsc->setMaxPointSize(rkCurCaps.MaxPointSize); 1039 1040 // Mipmap LOD biasing? 1041 if ((rkCurCaps.RasterCaps & D3DPRASTERCAPS_MIPMAPLODBIAS) == 0) 1042 rsc->unsetCapability(RSC_MIPMAP_LOD_BIAS); 1043 1044 1045 // Do we support per-stage src_manual constants? 1046 // HACK - ATI drivers seem to be buggy and don't support per-stage constants properly? 1047 // TODO: move this to RSC 1048 if((rkCurCaps.PrimitiveMiscCaps & D3DPMISCCAPS_PERSTAGECONSTANT) == 0) 1049 rsc->unsetCapability(RSC_PERSTAGECONSTANT); 1050 1051 // Advanced blend operations? min max subtract rev 1052 if((rkCurCaps.PrimitiveMiscCaps & D3DPMISCCAPS_BLENDOP) == 0) 1053 rsc->unsetCapability(RSC_ADVANCED_BLEND_OPERATIONS); 1054 } 1055 1056 // Blending between stages supported 1057 rsc->setCapability(RSC_BLENDING); 1058 1059 1060 // We always support compression, D3DX will decompress if device does not support 1061 rsc->setCapability(RSC_TEXTURE_COMPRESSION); 1062 rsc->setCapability(RSC_TEXTURE_COMPRESSION_DXT); 1063 1064 // We always support VBOs 1065 rsc->setCapability(RSC_VBO); 1066 1067 1068 convertVertexShaderCaps(rsc); 1069 convertPixelShaderCaps(rsc); 1070 1071 // Adapter details 1072 const D3DADAPTER_IDENTIFIER9& adapterID = mActiveD3DDriver->getAdapterIdentifier(); 1073 1074 // determine vendor 1075 // Full list of vendors here: http://www.pcidatabase.com/vendors.php?sort=id 1076 switch(adapterID.VendorId) 1077 { 1078 case 0x10DE: 1079 rsc->setVendor(GPU_NVIDIA); 1080 break; 1081 case 0x1002: 1082 rsc->setVendor(GPU_AMD); 1083 break; 1084 case 0x163C: 1085 case 0x8086: 1086 rsc->setVendor(GPU_INTEL); 1087 break; 1088 case 0x5333: 1089 rsc->setVendor(GPU_S3); 1090 break; 1091 case 0x3D3D: 1092 rsc->setVendor(GPU_3DLABS); 1093 break; 1094 case 0x102B: 1095 rsc->setVendor(GPU_MATROX); 1096 break; 1097 case 0x1039: 1098 rsc->setVendor(GPU_SIS); 1099 break; 1100 default: 1101 rsc->setVendor(GPU_UNKNOWN); 1102 break; 1103 }; 1104 1105 // Infinite projection? 1106 // We have no capability for this, so we have to base this on our 1107 // experience and reports from users 1108 // Non-vertex program capable hardware does not appear to support it 1109 if (rsc->hasCapability(RSC_VERTEX_PROGRAM)) 1110 { 1111 // GeForce4 Ti (and presumably GeForce3) does not 1112 // render infinite projection properly, even though it does in GL 1113 // So exclude all cards prior to the FX range from doing infinite 1114 if (rsc->getVendor() != GPU_NVIDIA || // not nVidia 1115 !((adapterID.DeviceId >= 0x200 && adapterID.DeviceId <= 0x20F) || //gf3 1116 (adapterID.DeviceId >= 0x250 && adapterID.DeviceId <= 0x25F) || //gf4ti 1117 (adapterID.DeviceId >= 0x280 && adapterID.DeviceId <= 0x28F) || //gf4ti 1118 (adapterID.DeviceId >= 0x170 && adapterID.DeviceId <= 0x18F) || //gf4 go 1119 (adapterID.DeviceId >= 0x280 && adapterID.DeviceId <= 0x28F))) //gf4ti go 1120 { 1121 rsc->setCapability(RSC_INFINITE_FAR_PLANE); 1122 } 1123 1124 } 1125 1126 // We always support rendertextures bigger than the frame buffer 1127 rsc->setCapability(RSC_HWRENDER_TO_TEXTURE); 1128 1129 // Determine if any floating point texture format is supported 1130 D3DFORMAT floatFormats[6] = {D3DFMT_R16F, D3DFMT_G16R16F, 1131 D3DFMT_A16B16G16R16F, D3DFMT_R32F, D3DFMT_G32R32F, 1132 D3DFMT_A32B32G32R32F}; 1133 IDirect3DSurface9* bbSurf; 1134 renderWindow->getCustomAttribute("DDBACKBUFFER", &bbSurf); 1135 D3DSURFACE_DESC bbSurfDesc; 1136 bbSurf->GetDesc(&bbSurfDesc); 1137 1138 for (int i = 0; i < 6; ++i) 1139 { 1140 if (SUCCEEDED(mD3D->CheckDeviceFormat(mActiveD3DDriver->getAdapterNumber(), 1141 D3DDEVTYPE_HAL, bbSurfDesc.Format, 1142 0, D3DRTYPE_TEXTURE, floatFormats[i]))) 1143 { 1144 rsc->setCapability(RSC_TEXTURE_FLOAT); 1145 break; 1146 } 1147 1148 } 1149 1150 1151 // TODO: make convertVertex/Fragment fill in rsc 1152 // TODO: update the below line to use rsc 1153 // Vertex textures 1154 if (rsc->isShaderProfileSupported("vs_3_0")) 1155 { 1156 // Run through all the texture formats looking for any which support 1157 // vertex texture fetching. Must have at least one! 1158 // All ATI Radeon up to X1n00 say they support vs_3_0, 1159 // but they support no texture formats for vertex texture fetch (cheaters!) 1160 if (checkVertexTextureFormats(renderWindow)) 1161 { 1162 rsc->setCapability(RSC_VERTEX_TEXTURE_FETCH); 1163 // always 4 vertex texture units in vs_3_0, and never shared 1164 rsc->setNumVertexTextureUnits(4); 1165 rsc->setVertexTextureUnitsShared(false); 1166 } 1167 } 1168 else 1169 { 1170 //True HW Instancing is supported since Shader model 3.0 ATI has a nasty 1171 //hack for enabling it in their SM 2.0 cards, but we don't (and won't) support it 1172 rsc->unsetCapability( RSC_VERTEX_BUFFER_INSTANCE_DATA ); 1173 } 1174 1175 // Check alpha to coverage support 1176 // this varies per vendor! But at least SM3 is required 1177 if (rsc->isShaderProfileSupported("ps_3_0")) 1178 { 1179 // NVIDIA needs a separate check 1180 if (rsc->getVendor() == GPU_NVIDIA) 1181 { 1182 if (mD3D->CheckDeviceFormat( 1183 D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, 0,D3DRTYPE_SURFACE, 1184 (D3DFORMAT)MAKEFOURCC('A', 'T', 'O', 'C')) == S_OK) 1185 { 1186 rsc->setCapability(RSC_ALPHA_TO_COVERAGE); 1187 } 1188 1189 } 1190 else if (rsc->getVendor() == GPU_AMD) 1191 { 1192 // There is no check on ATI, we have to assume SM3 == support 1193 rsc->setCapability(RSC_ALPHA_TO_COVERAGE); 1194 } 1195 1196 // no other cards have Dx9 hacks for alpha to coverage, as far as I know 1197 } 1198 1199 1200 if (mRealCapabilities == NULL) 1201 { 1202 mRealCapabilities = rsc; 1203 mRealCapabilities->addShaderProfile("hlsl"); 1204 1205 // if we are using custom capabilities, then 1206 // mCurrentCapabilities has already been loaded 1207 if(!mUseCustomCapabilities) 1208 mCurrentCapabilities = mRealCapabilities; 1209 1210 fireEvent("RenderSystemCapabilitiesCreated"); 1211 1212 initialiseFromRenderSystemCapabilities(mCurrentCapabilities, renderWindow); 1213 } 1214 1215 return rsc; 1216 } 1217 //--------------------------------------------------------------------- convertVertexShaderCaps(RenderSystemCapabilities * rsc) const1218 void D3D9RenderSystem::convertVertexShaderCaps(RenderSystemCapabilities* rsc) const 1219 { 1220 ushort major = 0xFF; 1221 ushort minor = 0xFF; 1222 D3DCAPS9 minVSCaps; 1223 1224 // Find the device with the lowest vertex shader caps. 1225 for (unsigned int i=0; i < mDriverList->count(); ++i) 1226 { 1227 D3D9Driver* pCurDriver = mDriverList->item(i); 1228 const D3DCAPS9& rkCurCaps = pCurDriver->getD3D9DeviceCaps(); 1229 ushort currMajor = static_cast<ushort>((rkCurCaps.VertexShaderVersion & 0x0000FF00) >> 8); 1230 ushort currMinor = static_cast<ushort>(rkCurCaps.VertexShaderVersion & 0x000000FF); 1231 1232 if (currMajor < major) 1233 { 1234 major = currMajor; 1235 minor = currMinor; 1236 minVSCaps = rkCurCaps; 1237 } 1238 else if (currMajor == major && currMinor < minor) 1239 { 1240 minor = currMinor; 1241 minVSCaps = rkCurCaps; 1242 } 1243 } 1244 1245 // In case we didn't found any vertex shader support 1246 // try the IDirect3DDevice9 caps instead of the IDirect3D9 1247 // software vertex processing is reported there 1248 if (major == 0 && minor == 0) 1249 { 1250 IDirect3DDevice9* lpD3DDevice9 = getActiveD3D9Device(); 1251 D3DCAPS9 d3dDeviceCaps9; 1252 lpD3DDevice9->GetDeviceCaps(&d3dDeviceCaps9); 1253 major = static_cast<ushort>((d3dDeviceCaps9.VertexShaderVersion & 0x0000FF00) >> 8); 1254 minor = static_cast<ushort>(d3dDeviceCaps9.VertexShaderVersion & 0x000000FF); 1255 } 1256 1257 bool vs2x = false; 1258 bool vs2a = false; 1259 1260 // Special case detection for vs_2_x/a support 1261 if (major >= 2) 1262 { 1263 if ((minVSCaps.VS20Caps.Caps & D3DVS20CAPS_PREDICATION) && 1264 (minVSCaps.VS20Caps.DynamicFlowControlDepth > 0) && 1265 (minVSCaps.VS20Caps.NumTemps >= 12)) 1266 { 1267 vs2x = true; 1268 } 1269 1270 if ((minVSCaps.VS20Caps.Caps & D3DVS20CAPS_PREDICATION) && 1271 (minVSCaps.VS20Caps.DynamicFlowControlDepth > 0) && 1272 (minVSCaps.VS20Caps.NumTemps >= 13)) 1273 { 1274 vs2a = true; 1275 } 1276 } 1277 1278 // Populate max param count 1279 switch (major) 1280 { 1281 case 1: 1282 // No boolean params allowed 1283 rsc->setVertexProgramConstantBoolCount(0); 1284 // No integer params allowed 1285 rsc->setVertexProgramConstantIntCount(0); 1286 // float params, always 4D 1287 rsc->setVertexProgramConstantFloatCount(static_cast<ushort>(minVSCaps.MaxVertexShaderConst)); 1288 1289 break; 1290 case 2: 1291 // 16 boolean params allowed 1292 rsc->setVertexProgramConstantBoolCount(16); 1293 // 16 integer params allowed, 4D 1294 rsc->setVertexProgramConstantIntCount(16); 1295 // float params, always 4D 1296 rsc->setVertexProgramConstantFloatCount(static_cast<ushort>(minVSCaps.MaxVertexShaderConst)); 1297 break; 1298 case 3: 1299 // 16 boolean params allowed 1300 rsc->setVertexProgramConstantBoolCount(16); 1301 // 16 integer params allowed, 4D 1302 rsc->setVertexProgramConstantIntCount(16); 1303 // float params, always 4D 1304 rsc->setVertexProgramConstantFloatCount(static_cast<ushort>(minVSCaps.MaxVertexShaderConst)); 1305 break; 1306 } 1307 1308 // populate syntax codes in program manager (no breaks in this one so it falls through) 1309 switch(major) 1310 { 1311 case 3: 1312 rsc->addShaderProfile("vs_3_0"); 1313 case 2: 1314 if (vs2x) 1315 rsc->addShaderProfile("vs_2_x"); 1316 if (vs2a) 1317 rsc->addShaderProfile("vs_2_a"); 1318 1319 rsc->addShaderProfile("vs_2_0"); 1320 case 1: 1321 rsc->addShaderProfile("vs_1_1"); 1322 rsc->setCapability(RSC_VERTEX_PROGRAM); 1323 } 1324 } 1325 //--------------------------------------------------------------------- convertPixelShaderCaps(RenderSystemCapabilities * rsc) const1326 void D3D9RenderSystem::convertPixelShaderCaps(RenderSystemCapabilities* rsc) const 1327 { 1328 ushort major = 0xFF; 1329 ushort minor = 0xFF; 1330 D3DCAPS9 minPSCaps; 1331 1332 // Find the device with the lowest pixel shader caps. 1333 for (unsigned int i=0; i < mDriverList->count(); ++i) 1334 { 1335 D3D9Driver* pCurDriver = mDriverList->item(i); 1336 const D3DCAPS9& currCaps = pCurDriver->getD3D9DeviceCaps(); 1337 ushort currMajor = static_cast<ushort>((currCaps.PixelShaderVersion & 0x0000FF00) >> 8); 1338 ushort currMinor = static_cast<ushort>(currCaps.PixelShaderVersion & 0x000000FF); 1339 1340 if (currMajor < major) 1341 { 1342 major = currMajor; 1343 minor = currMinor; 1344 minPSCaps = currCaps; 1345 } 1346 else if (currMajor == major && currMinor < minor) 1347 { 1348 minor = currMinor; 1349 minPSCaps = currCaps; 1350 } 1351 } 1352 1353 bool ps2a = false; 1354 bool ps2b = false; 1355 bool ps2x = false; 1356 1357 // Special case detection for ps_2_x/a/b support 1358 if (major >= 2) 1359 { 1360 if ((minPSCaps.PS20Caps.Caps & D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT) && 1361 (minPSCaps.PS20Caps.NumTemps >= 32)) 1362 { 1363 ps2b = true; 1364 } 1365 1366 if ((minPSCaps.PS20Caps.Caps & D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT) && 1367 (minPSCaps.PS20Caps.Caps & D3DPS20CAPS_NODEPENDENTREADLIMIT) && 1368 (minPSCaps.PS20Caps.Caps & D3DPS20CAPS_ARBITRARYSWIZZLE) && 1369 (minPSCaps.PS20Caps.Caps & D3DPS20CAPS_GRADIENTINSTRUCTIONS) && 1370 (minPSCaps.PS20Caps.Caps & D3DPS20CAPS_PREDICATION) && 1371 (minPSCaps.PS20Caps.NumTemps >= 22)) 1372 { 1373 ps2a = true; 1374 } 1375 1376 // Does this enough? 1377 if (ps2a || ps2b) 1378 { 1379 ps2x = true; 1380 } 1381 } 1382 1383 switch (major) 1384 { 1385 case 1: 1386 // no boolean params allowed 1387 rsc->setFragmentProgramConstantBoolCount(0); 1388 // no integer params allowed 1389 rsc->setFragmentProgramConstantIntCount(0); 1390 // float params, always 4D 1391 // NB in ps_1_x these are actually stored as fixed point values, 1392 // but they are entered as floats 1393 rsc->setFragmentProgramConstantFloatCount(8); 1394 break; 1395 case 2: 1396 // 16 boolean params allowed 1397 rsc->setFragmentProgramConstantBoolCount(16); 1398 // 16 integer params allowed, 4D 1399 rsc->setFragmentProgramConstantIntCount(16); 1400 // float params, always 4D 1401 rsc->setFragmentProgramConstantFloatCount(32); 1402 break; 1403 case 3: 1404 // 16 boolean params allowed 1405 rsc->setFragmentProgramConstantBoolCount(16); 1406 // 16 integer params allowed, 4D 1407 rsc->setFragmentProgramConstantIntCount(16); 1408 // float params, always 4D 1409 rsc->setFragmentProgramConstantFloatCount(224); 1410 break; 1411 } 1412 1413 // populate syntax codes in program manager (no breaks in this one so it falls through) 1414 switch(major) 1415 { 1416 case 3: 1417 if (minor > 0) 1418 rsc->addShaderProfile("ps_3_x"); 1419 1420 rsc->addShaderProfile("ps_3_0"); 1421 case 2: 1422 if (ps2x) 1423 rsc->addShaderProfile("ps_2_x"); 1424 if (ps2a) 1425 rsc->addShaderProfile("ps_2_a"); 1426 if (ps2b) 1427 rsc->addShaderProfile("ps_2_b"); 1428 1429 rsc->addShaderProfile("ps_2_0"); 1430 case 1: 1431 if (major > 1 || minor >= 4) 1432 rsc->addShaderProfile("ps_1_4"); 1433 if (major > 1 || minor >= 3) 1434 rsc->addShaderProfile("ps_1_3"); 1435 if (major > 1 || minor >= 2) 1436 rsc->addShaderProfile("ps_1_2"); 1437 1438 rsc->addShaderProfile("ps_1_1"); 1439 rsc->setCapability(RSC_FRAGMENT_PROGRAM); 1440 } 1441 } 1442 //----------------------------------------------------------------------- checkVertexTextureFormats(D3D9RenderWindow * renderWindow) const1443 bool D3D9RenderSystem::checkVertexTextureFormats(D3D9RenderWindow* renderWindow) const 1444 { 1445 bool anySupported = false; 1446 1447 IDirect3DSurface9* bbSurf; 1448 renderWindow->getCustomAttribute("DDBACKBUFFER", &bbSurf); 1449 D3DSURFACE_DESC bbSurfDesc; 1450 bbSurf->GetDesc(&bbSurfDesc); 1451 1452 for (uint ipf = static_cast<uint>(PF_L8); ipf < static_cast<uint>(PF_COUNT); ++ipf) 1453 { 1454 PixelFormat pf = (PixelFormat)ipf; 1455 1456 D3DFORMAT fmt = 1457 D3D9Mappings::_getPF(D3D9Mappings::_getClosestSupportedPF(pf)); 1458 1459 if (SUCCEEDED(mD3D->CheckDeviceFormat( 1460 mActiveD3DDriver->getAdapterNumber(), D3DDEVTYPE_HAL, bbSurfDesc.Format, 1461 D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, fmt))) 1462 { 1463 // cool, at least one supported 1464 anySupported = true; 1465 LogManager::getSingleton().stream() 1466 << "D3D9: Vertex texture format supported - " 1467 << PixelUtil::getFormatName(pf); 1468 } 1469 } 1470 1471 return anySupported; 1472 1473 } 1474 //----------------------------------------------------------------------- initialiseFromRenderSystemCapabilities(RenderSystemCapabilities * caps,RenderTarget * primary)1475 void D3D9RenderSystem::initialiseFromRenderSystemCapabilities(RenderSystemCapabilities* caps, RenderTarget* primary) 1476 { 1477 if (caps->getRenderSystemName() != getName()) 1478 { 1479 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 1480 "Trying to initialize D3D9RenderSystem from RenderSystemCapabilities that do not support Direct3D9", 1481 "D3D9RenderSystem::initialiseFromRenderSystemCapabilities"); 1482 } 1483 if (caps->isShaderProfileSupported("hlsl")) 1484 HighLevelGpuProgramManager::getSingleton().addFactory(mHLSLProgramFactory); 1485 1486 Log* defaultLog = LogManager::getSingleton().getDefaultLog(); 1487 if (defaultLog) 1488 { 1489 caps->log(defaultLog); 1490 } 1491 } 1492 1493 //----------------------------------------------------------------------- _checkTextureFilteringSupported(TextureType ttype,PixelFormat format,int usage)1494 bool D3D9RenderSystem::_checkTextureFilteringSupported(TextureType ttype, PixelFormat format, int usage) 1495 { 1496 // Gets D3D format 1497 D3DFORMAT d3dPF = D3D9Mappings::_getPF(format); 1498 if (d3dPF == D3DFMT_UNKNOWN) 1499 return false; 1500 1501 for (uint i = 0; i < mDeviceManager->getDeviceCount(); ++i) 1502 { 1503 D3D9Device* currDevice = mDeviceManager->getDevice(i); 1504 D3D9RenderWindow* currDevicePrimaryWindow = currDevice->getPrimaryWindow(); 1505 IDirect3DSurface9* pSurface = currDevicePrimaryWindow->getRenderSurface(); 1506 D3DSURFACE_DESC srfDesc; 1507 1508 // Get surface desc 1509 if (FAILED(pSurface->GetDesc(&srfDesc))) 1510 return false; 1511 1512 // Calculate usage 1513 DWORD d3dusage = D3DUSAGE_QUERY_FILTER; 1514 if (usage & TU_RENDERTARGET) 1515 d3dusage |= D3DUSAGE_RENDERTARGET; 1516 if (usage & TU_DYNAMIC) 1517 d3dusage |= D3DUSAGE_DYNAMIC; 1518 1519 // Detect resource type 1520 D3DRESOURCETYPE rtype; 1521 switch(ttype) 1522 { 1523 case TEX_TYPE_1D: 1524 case TEX_TYPE_2D: 1525 rtype = D3DRTYPE_TEXTURE; 1526 break; 1527 case TEX_TYPE_3D: 1528 rtype = D3DRTYPE_VOLUMETEXTURE; 1529 break; 1530 case TEX_TYPE_CUBE_MAP: 1531 rtype = D3DRTYPE_CUBETEXTURE; 1532 break; 1533 default: 1534 return false; 1535 } 1536 1537 HRESULT hr = mD3D->CheckDeviceFormat( 1538 currDevice->getAdapterNumber(), 1539 currDevice->getDeviceType(), 1540 srfDesc.Format, 1541 d3dusage, 1542 rtype, 1543 d3dPF); 1544 1545 if (FAILED(hr)) 1546 return false; 1547 } 1548 1549 return true; 1550 } 1551 //----------------------------------------------------------------------- createMultiRenderTarget(const String & name)1552 MultiRenderTarget * D3D9RenderSystem::createMultiRenderTarget(const String & name) 1553 { 1554 MultiRenderTarget *retval; 1555 retval = OGRE_NEW D3D9MultiRenderTarget(name); 1556 attachRenderTarget(*retval); 1557 1558 return retval; 1559 } 1560 //--------------------------------------------------------------------- detachRenderTarget(const String & name)1561 RenderTarget* D3D9RenderSystem::detachRenderTarget(const String &name) 1562 { 1563 RenderTarget* target = RenderSystem::detachRenderTarget(name); 1564 detachRenderTargetImpl(name); 1565 return target; 1566 } 1567 //--------------------------------------------------------------------- detachRenderTargetImpl(const String & name)1568 void D3D9RenderSystem::detachRenderTargetImpl(const String& name) 1569 { 1570 // Check render windows 1571 D3D9RenderWindowList::iterator sw; 1572 for (sw = mRenderWindows.begin(); sw != mRenderWindows.end(); ++sw) 1573 { 1574 if ((*sw)->getName() == name) 1575 { 1576 mRenderWindows.erase(sw); 1577 break; 1578 } 1579 } 1580 } 1581 //--------------------------------------------------------------------- destroyRenderTarget(const String & name)1582 void D3D9RenderSystem::destroyRenderTarget(const String& name) 1583 { 1584 detachRenderTargetImpl(name); 1585 1586 // Do the real removal 1587 RenderSystem::destroyRenderTarget(name); 1588 } 1589 //--------------------------------------------------------------------- getErrorDescription(long errorNumber) const1590 String D3D9RenderSystem::getErrorDescription( long errorNumber ) const 1591 { 1592 const String errMsg = DXGetErrorDescription( errorNumber ); 1593 return errMsg; 1594 } 1595 //--------------------------------------------------------------------- getColourVertexElementType() const1596 VertexElementType D3D9RenderSystem::getColourVertexElementType() const 1597 { 1598 return VET_COLOUR_ARGB; 1599 } 1600 //--------------------------------------------------------------------- _convertProjectionMatrix(const Matrix4 & matrix,Matrix4 & dest,bool forGpuProgram)1601 void D3D9RenderSystem::_convertProjectionMatrix(const Matrix4& matrix, 1602 Matrix4& dest, bool forGpuProgram) 1603 { 1604 dest = matrix; 1605 1606 // Convert depth range from [-1,+1] to [0,1] 1607 dest[2][0] = (dest[2][0] + dest[3][0]) / 2; 1608 dest[2][1] = (dest[2][1] + dest[3][1]) / 2; 1609 dest[2][2] = (dest[2][2] + dest[3][2]) / 2; 1610 dest[2][3] = (dest[2][3] + dest[3][3]) / 2; 1611 1612 if (!forGpuProgram) 1613 { 1614 // Convert right-handed to left-handed 1615 dest[0][2] = -dest[0][2]; 1616 dest[1][2] = -dest[1][2]; 1617 dest[2][2] = -dest[2][2]; 1618 dest[3][2] = -dest[3][2]; 1619 } 1620 } 1621 //--------------------------------------------------------------------- _makeProjectionMatrix(const Radian & fovy,Real aspect,Real nearPlane,Real farPlane,Matrix4 & dest,bool forGpuProgram)1622 void D3D9RenderSystem::_makeProjectionMatrix(const Radian& fovy, Real aspect, Real nearPlane, 1623 Real farPlane, Matrix4& dest, bool forGpuProgram) 1624 { 1625 Radian theta ( fovy * 0.5 ); 1626 Real h = 1 / Math::Tan(theta); 1627 Real w = h / aspect; 1628 Real q, qn; 1629 if (farPlane == 0) 1630 { 1631 q = 1 - Frustum::INFINITE_FAR_PLANE_ADJUST; 1632 qn = nearPlane * (Frustum::INFINITE_FAR_PLANE_ADJUST - 1); 1633 } 1634 else 1635 { 1636 q = farPlane / ( farPlane - nearPlane ); 1637 qn = -q * nearPlane; 1638 } 1639 1640 dest = Matrix4::ZERO; 1641 dest[0][0] = w; 1642 dest[1][1] = h; 1643 1644 if (forGpuProgram) 1645 { 1646 dest[2][2] = -q; 1647 dest[3][2] = -1.0f; 1648 } 1649 else 1650 { 1651 dest[2][2] = q; 1652 dest[3][2] = 1.0f; 1653 } 1654 1655 dest[2][3] = qn; 1656 } 1657 //--------------------------------------------------------------------- _makeOrthoMatrix(const Radian & fovy,Real aspect,Real nearPlane,Real farPlane,Matrix4 & dest,bool forGpuProgram)1658 void D3D9RenderSystem::_makeOrthoMatrix(const Radian& fovy, Real aspect, Real nearPlane, Real farPlane, 1659 Matrix4& dest, bool forGpuProgram ) 1660 { 1661 Radian thetaY (fovy / 2.0f); 1662 Real tanThetaY = Math::Tan(thetaY); 1663 1664 //Real thetaX = thetaY * aspect; 1665 Real tanThetaX = tanThetaY * aspect; //Math::Tan(thetaX); 1666 Real half_w = tanThetaX * nearPlane; 1667 Real half_h = tanThetaY * nearPlane; 1668 Real iw = static_cast<Real>(1.0 / half_w); 1669 Real ih = static_cast<Real>(1.0 / half_h); 1670 Real q; 1671 if (farPlane == 0) 1672 { 1673 q = 0; 1674 } 1675 else 1676 { 1677 q = static_cast<Real>(1.0 / (farPlane - nearPlane)); 1678 } 1679 1680 dest = Matrix4::ZERO; 1681 dest[0][0] = iw; 1682 dest[1][1] = ih; 1683 dest[2][2] = q; 1684 dest[2][3] = -nearPlane / (farPlane - nearPlane); 1685 dest[3][3] = 1; 1686 1687 if (forGpuProgram) 1688 { 1689 dest[2][2] = -dest[2][2]; 1690 } 1691 } 1692 //--------------------------------------------------------------------- setAmbientLight(float r,float g,float b)1693 void D3D9RenderSystem::setAmbientLight( float r, float g, float b ) 1694 { 1695 HRESULT hr = __SetRenderState( D3DRS_AMBIENT, D3DCOLOR_COLORVALUE( r, g, b, 1.0f ) ); 1696 if( FAILED( hr ) ) 1697 OGRE_EXCEPT( Exception::ERR_RENDERINGAPI_ERROR, 1698 "Failed to set render stat D3DRS_AMBIENT", "D3D9RenderSystem::setAmbientLight" ); 1699 } 1700 //--------------------------------------------------------------------- _useLights(const LightList & lights,unsigned short limit)1701 void D3D9RenderSystem::_useLights(const LightList& lights, unsigned short limit) 1702 { 1703 IDirect3DDevice9* activeDevice = getActiveD3D9Device(); 1704 LightList::const_iterator i, iend; 1705 iend = lights.end(); 1706 unsigned short num = 0; 1707 for (i = lights.begin(); i != iend && num < limit; ++i, ++num) 1708 { 1709 setD3D9Light(num, *i); 1710 } 1711 // Disable extra lights 1712 for (; num < mCurrentLights[activeDevice]; ++num) 1713 { 1714 setD3D9Light(num, NULL); 1715 } 1716 mCurrentLights[activeDevice] = std::min(limit, static_cast<unsigned short>(lights.size())); 1717 1718 } 1719 //--------------------------------------------------------------------- setShadingType(ShadeOptions so)1720 void D3D9RenderSystem::setShadingType( ShadeOptions so ) 1721 { 1722 HRESULT hr = __SetRenderState( D3DRS_SHADEMODE, D3D9Mappings::get(so) ); 1723 if( FAILED( hr ) ) 1724 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 1725 "Failed to set render stat D3DRS_SHADEMODE", "D3D9RenderSystem::setShadingType" ); 1726 } 1727 //--------------------------------------------------------------------- setLightingEnabled(bool enabled)1728 void D3D9RenderSystem::setLightingEnabled( bool enabled ) 1729 { 1730 HRESULT hr; 1731 if( FAILED( hr = __SetRenderState( D3DRS_LIGHTING, enabled ) ) ) 1732 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 1733 "Failed to set render state D3DRS_LIGHTING", "D3D9RenderSystem::setLightingEnabled" ); 1734 } 1735 //--------------------------------------------------------------------- setD3D9Light(size_t index,Light * lt)1736 void D3D9RenderSystem::setD3D9Light( size_t index, Light* lt ) 1737 { 1738 HRESULT hr; 1739 1740 D3DLIGHT9 d3dLight; 1741 ZeroMemory( &d3dLight, sizeof(d3dLight) ); 1742 1743 if (!lt) 1744 { 1745 if( FAILED( hr = getActiveD3D9Device()->LightEnable( static_cast<DWORD>(index), FALSE) ) ) 1746 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 1747 "Unable to disable light", "D3D9RenderSystem::setD3D9Light" ); 1748 } 1749 else 1750 { 1751 switch( lt->getType() ) 1752 { 1753 case Light::LT_POINT: 1754 d3dLight.Type = D3DLIGHT_POINT; 1755 break; 1756 1757 case Light::LT_DIRECTIONAL: 1758 d3dLight.Type = D3DLIGHT_DIRECTIONAL; 1759 break; 1760 1761 case Light::LT_SPOTLIGHT: 1762 d3dLight.Type = D3DLIGHT_SPOT; 1763 d3dLight.Falloff = lt->getSpotlightFalloff(); 1764 d3dLight.Theta = lt->getSpotlightInnerAngle().valueRadians(); 1765 d3dLight.Phi = lt->getSpotlightOuterAngle().valueRadians(); 1766 break; 1767 } 1768 1769 ColourValue col; 1770 col = lt->getDiffuseColour(); 1771 d3dLight.Diffuse = D3DXCOLOR( col.r, col.g, col.b, col.a ); 1772 1773 col = lt->getSpecularColour(); 1774 d3dLight.Specular = D3DXCOLOR( col.r, col.g, col.b, col.a ); 1775 1776 Vector3 vec; 1777 if( lt->getType() != Light::LT_DIRECTIONAL ) 1778 { 1779 vec = lt->getDerivedPosition(true); 1780 d3dLight.Position = D3DXVECTOR3( vec.x, vec.y, vec.z ); 1781 } 1782 if( lt->getType() != Light::LT_POINT ) 1783 { 1784 vec = lt->getDerivedDirection(); 1785 d3dLight.Direction = D3DXVECTOR3( vec.x, vec.y, vec.z ); 1786 } 1787 1788 d3dLight.Range = lt->getAttenuationRange(); 1789 d3dLight.Attenuation0 = lt->getAttenuationConstant(); 1790 d3dLight.Attenuation1 = lt->getAttenuationLinear(); 1791 d3dLight.Attenuation2 = lt->getAttenuationQuadric(); 1792 1793 if( FAILED( hr = getActiveD3D9Device()->SetLight( static_cast<DWORD>(index), &d3dLight ) ) ) 1794 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set light details", "D3D9RenderSystem::setD3D9Light" ); 1795 1796 if( FAILED( hr = getActiveD3D9Device()->LightEnable( static_cast<DWORD>(index), TRUE ) ) ) 1797 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to enable light", "D3D9RenderSystem::setD3D9Light" ); 1798 } 1799 1800 1801 } 1802 //--------------------------------------------------------------------- _setViewMatrix(const Matrix4 & m)1803 void D3D9RenderSystem::_setViewMatrix( const Matrix4 &m ) 1804 { 1805 // save latest view matrix 1806 mViewMatrix = m; 1807 mViewMatrix[2][0] = -mViewMatrix[2][0]; 1808 mViewMatrix[2][1] = -mViewMatrix[2][1]; 1809 mViewMatrix[2][2] = -mViewMatrix[2][2]; 1810 mViewMatrix[2][3] = -mViewMatrix[2][3]; 1811 1812 mDxViewMat = D3D9Mappings::makeD3DXMatrix( mViewMatrix ); 1813 1814 HRESULT hr; 1815 if( FAILED( hr = getActiveD3D9Device()->SetTransform( D3DTS_VIEW, &mDxViewMat ) ) ) 1816 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Cannot set D3D9 view matrix", "D3D9RenderSystem::_setViewMatrix" ); 1817 1818 // also mark clip planes dirty 1819 if (!mClipPlanes.empty()) 1820 mClipPlanesDirty = true; 1821 } 1822 //--------------------------------------------------------------------- _setProjectionMatrix(const Matrix4 & m)1823 void D3D9RenderSystem::_setProjectionMatrix( const Matrix4 &m ) 1824 { 1825 // save latest matrix 1826 mDxProjMat = D3D9Mappings::makeD3DXMatrix( m ); 1827 1828 if( mActiveRenderTarget->requiresTextureFlipping() ) 1829 { 1830 // Invert transformed y 1831 mDxProjMat._12 = - mDxProjMat._12; 1832 mDxProjMat._22 = - mDxProjMat._22; 1833 mDxProjMat._32 = - mDxProjMat._32; 1834 mDxProjMat._42 = - mDxProjMat._42; 1835 } 1836 1837 HRESULT hr; 1838 if( FAILED( hr = getActiveD3D9Device()->SetTransform( D3DTS_PROJECTION, &mDxProjMat ) ) ) 1839 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Cannot set D3D9 projection matrix", "D3D9RenderSystem::_setProjectionMatrix" ); 1840 1841 // also mark clip planes dirty 1842 if (!mClipPlanes.empty()) 1843 mClipPlanesDirty = true; 1844 1845 } 1846 //--------------------------------------------------------------------- _setWorldMatrix(const Matrix4 & m)1847 void D3D9RenderSystem::_setWorldMatrix( const Matrix4 &m ) 1848 { 1849 // save latest matrix 1850 mDxWorldMat = D3D9Mappings::makeD3DXMatrix( m ); 1851 1852 HRESULT hr; 1853 if( FAILED( hr = getActiveD3D9Device()->SetTransform( D3DTS_WORLD, &mDxWorldMat ) ) ) 1854 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Cannot set D3D9 world matrix", "D3D9RenderSystem::_setWorldMatrix" ); 1855 } 1856 //--------------------------------------------------------------------- _setSurfaceParams(const ColourValue & ambient,const ColourValue & diffuse,const ColourValue & specular,const ColourValue & emissive,Real shininess,TrackVertexColourType tracking)1857 void D3D9RenderSystem::_setSurfaceParams( const ColourValue &ambient, const ColourValue &diffuse, 1858 const ColourValue &specular, const ColourValue &emissive, Real shininess, 1859 TrackVertexColourType tracking ) 1860 { 1861 1862 D3DMATERIAL9 material; 1863 material.Diffuse = D3DXCOLOR( diffuse.r, diffuse.g, diffuse.b, diffuse.a ); 1864 material.Ambient = D3DXCOLOR( ambient.r, ambient.g, ambient.b, ambient.a ); 1865 material.Specular = D3DXCOLOR( specular.r, specular.g, specular.b, specular.a ); 1866 material.Emissive = D3DXCOLOR( emissive.r, emissive.g, emissive.b, emissive.a ); 1867 material.Power = shininess; 1868 1869 HRESULT hr = getActiveD3D9Device()->SetMaterial( &material ); 1870 if( FAILED( hr ) ) 1871 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting D3D material", "D3D9RenderSystem::_setSurfaceParams" ); 1872 1873 1874 if(tracking != TVC_NONE) 1875 { 1876 __SetRenderState(D3DRS_COLORVERTEX, TRUE); 1877 __SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, (tracking&TVC_AMBIENT)?D3DMCS_COLOR1:D3DMCS_MATERIAL); 1878 __SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, (tracking&TVC_DIFFUSE)?D3DMCS_COLOR1:D3DMCS_MATERIAL); 1879 __SetRenderState(D3DRS_SPECULARMATERIALSOURCE, (tracking&TVC_SPECULAR)?D3DMCS_COLOR1:D3DMCS_MATERIAL); 1880 __SetRenderState(D3DRS_EMISSIVEMATERIALSOURCE, (tracking&TVC_EMISSIVE)?D3DMCS_COLOR1:D3DMCS_MATERIAL); 1881 } 1882 else 1883 { 1884 __SetRenderState(D3DRS_COLORVERTEX, FALSE); 1885 } 1886 1887 } 1888 //--------------------------------------------------------------------- _setPointParameters(Real size,bool attenuationEnabled,Real constant,Real linear,Real quadratic,Real minSize,Real maxSize)1889 void D3D9RenderSystem::_setPointParameters(Real size, 1890 bool attenuationEnabled, Real constant, Real linear, Real quadratic, 1891 Real minSize, Real maxSize) 1892 { 1893 if(attenuationEnabled) 1894 { 1895 // scaling required 1896 __SetRenderState(D3DRS_POINTSCALEENABLE, TRUE); 1897 __SetFloatRenderState(D3DRS_POINTSCALE_A, constant); 1898 __SetFloatRenderState(D3DRS_POINTSCALE_B, linear); 1899 __SetFloatRenderState(D3DRS_POINTSCALE_C, quadratic); 1900 } 1901 else 1902 { 1903 // no scaling required 1904 __SetRenderState(D3DRS_POINTSCALEENABLE, FALSE); 1905 } 1906 __SetFloatRenderState(D3DRS_POINTSIZE, size); 1907 __SetFloatRenderState(D3DRS_POINTSIZE_MIN, minSize); 1908 if (maxSize == 0.0f) 1909 maxSize = mCurrentCapabilities->getMaxPointSize(); 1910 __SetFloatRenderState(D3DRS_POINTSIZE_MAX, maxSize); 1911 1912 1913 } 1914 //--------------------------------------------------------------------- _setPointSpritesEnabled(bool enabled)1915 void D3D9RenderSystem::_setPointSpritesEnabled(bool enabled) 1916 { 1917 if (enabled) 1918 { 1919 __SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE); 1920 } 1921 else 1922 { 1923 __SetRenderState(D3DRS_POINTSPRITEENABLE, FALSE); 1924 } 1925 } 1926 //--------------------------------------------------------------------- _setTexture(size_t stage,bool enabled,const TexturePtr & tex)1927 void D3D9RenderSystem::_setTexture( size_t stage, bool enabled, const TexturePtr& tex ) 1928 { 1929 HRESULT hr; 1930 D3D9TexturePtr dt = tex.staticCast<D3D9Texture>(); 1931 if (enabled && !dt.isNull()) 1932 { 1933 // note used 1934 dt->touch(); 1935 1936 IDirect3DBaseTexture9 *pTex = dt->getTexture(); 1937 if (mTexStageDesc[stage].pTex != pTex) 1938 { 1939 hr = getActiveD3D9Device()->SetTexture(static_cast<DWORD>(stage), pTex); 1940 if( hr != S_OK ) 1941 { 1942 String str = "Unable to set texture '" + tex->getName() + "' in D3D9"; 1943 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, str, "D3D9RenderSystem::_setTexture" ); 1944 } 1945 1946 // set stage desc. 1947 mTexStageDesc[stage].pTex = pTex; 1948 mTexStageDesc[stage].texType = D3D9Mappings::get(dt->getTextureType()); 1949 1950 // Set gamma now too 1951 if (dt->isHardwareGammaReadToBeUsed()) 1952 { 1953 __SetSamplerState(getSamplerId(stage), D3DSAMP_SRGBTEXTURE, TRUE); 1954 } 1955 else 1956 { 1957 __SetSamplerState(getSamplerId(stage), D3DSAMP_SRGBTEXTURE, FALSE); 1958 } 1959 } 1960 } 1961 else 1962 { 1963 if (mTexStageDesc[stage].pTex != 0) 1964 { 1965 hr = getActiveD3D9Device()->SetTexture(static_cast<DWORD>(stage), 0); 1966 if( hr != S_OK ) 1967 { 1968 String str = "Unable to disable texture '" + StringConverter::toString(stage) + "' in D3D9"; 1969 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, str, "D3D9RenderSystem::_setTexture" ); 1970 } 1971 } 1972 1973 hr = __SetTextureStageState(static_cast<DWORD>(stage), D3DTSS_COLOROP, D3DTOP_DISABLE); 1974 if( hr != S_OK ) 1975 { 1976 String str = "Unable to disable texture '" + StringConverter::toString(stage) + "' in D3D9"; 1977 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, str, "D3D9RenderSystem::_setTexture" ); 1978 } 1979 1980 // set stage desc. to defaults 1981 mTexStageDesc[stage].pTex = 0; 1982 mTexStageDesc[stage].autoTexCoordType = TEXCALC_NONE; 1983 mTexStageDesc[stage].coordIndex = 0; 1984 mTexStageDesc[stage].texType = D3D9Mappings::D3D_TEX_TYPE_NORMAL; 1985 } 1986 } 1987 //--------------------------------------------------------------------- _setVertexTexture(size_t stage,const TexturePtr & tex)1988 void D3D9RenderSystem::_setVertexTexture(size_t stage, const TexturePtr& tex) 1989 { 1990 if (tex.isNull()) 1991 { 1992 1993 if (mTexStageDesc[stage].pVertexTex != 0) 1994 { 1995 HRESULT hr = getActiveD3D9Device()->SetTexture(D3DVERTEXTEXTURESAMPLER0 + static_cast<DWORD>(stage), 0); 1996 if( hr != S_OK ) 1997 { 1998 String str = "Unable to disable vertex texture '" 1999 + StringConverter::toString(stage) + "' in D3D9"; 2000 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, str, "D3D9RenderSystem::_setVertexTexture" ); 2001 } 2002 } 2003 2004 // set stage desc. to defaults 2005 mTexStageDesc[stage].pVertexTex = 0; 2006 } 2007 else 2008 { 2009 D3D9TexturePtr dt = tex.staticCast<D3D9Texture>(); 2010 // note used 2011 dt->touch(); 2012 2013 IDirect3DBaseTexture9 *pTex = dt->getTexture(); 2014 if (mTexStageDesc[stage].pVertexTex != pTex) 2015 { 2016 HRESULT hr = getActiveD3D9Device()->SetTexture(D3DVERTEXTEXTURESAMPLER0 + static_cast<DWORD>(stage), pTex); 2017 if( hr != S_OK ) 2018 { 2019 String str = "Unable to set vertex texture '" + tex->getName() + "' in D3D9"; 2020 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, str, "D3D9RenderSystem::_setVertexTexture" ); 2021 } 2022 2023 // set stage desc. 2024 mTexStageDesc[stage].pVertexTex = pTex; 2025 } 2026 2027 } 2028 2029 } 2030 //--------------------------------------------------------------------- _disableTextureUnit(size_t texUnit)2031 void D3D9RenderSystem::_disableTextureUnit(size_t texUnit) 2032 { 2033 RenderSystem::_disableTextureUnit(texUnit); 2034 // also disable vertex texture unit 2035 static TexturePtr nullPtr; 2036 _setVertexTexture(texUnit, nullPtr); 2037 } 2038 //--------------------------------------------------------------------- _setTextureCoordSet(size_t stage,size_t index)2039 void D3D9RenderSystem::_setTextureCoordSet( size_t stage, size_t index ) 2040 { 2041 // if vertex shader is being used, stage and index must match 2042 if (mVertexProgramBound) 2043 index = stage; 2044 2045 HRESULT hr; 2046 // Record settings 2047 mTexStageDesc[stage].coordIndex = index; 2048 2049 if (mVertexProgramBound) 2050 hr = __SetTextureStageState( static_cast<DWORD>(stage), D3DTSS_TEXCOORDINDEX, index ); 2051 else 2052 hr = __SetTextureStageState( static_cast<DWORD>(stage), D3DTSS_TEXCOORDINDEX, D3D9Mappings::get(mTexStageDesc[stage].autoTexCoordType, mDeviceManager->getActiveDevice()->getD3D9DeviceCaps()) | index ); 2053 if( FAILED( hr ) ) 2054 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set texture coord. set index", "D3D9RenderSystem::_setTextureCoordSet" ); 2055 } 2056 //--------------------------------------------------------------------- _setTextureCoordCalculation(size_t stage,TexCoordCalcMethod m,const Frustum * frustum)2057 void D3D9RenderSystem::_setTextureCoordCalculation( size_t stage, TexCoordCalcMethod m, 2058 const Frustum* frustum) 2059 { 2060 HRESULT hr; 2061 // record the stage state 2062 mTexStageDesc[stage].autoTexCoordType = m; 2063 mTexStageDesc[stage].frustum = frustum; 2064 2065 if (mVertexProgramBound) 2066 hr = __SetTextureStageState( static_cast<DWORD>(stage), D3DTSS_TEXCOORDINDEX, mTexStageDesc[stage].coordIndex ); 2067 else 2068 hr = __SetTextureStageState( static_cast<DWORD>(stage), D3DTSS_TEXCOORDINDEX, D3D9Mappings::get(m, mDeviceManager->getActiveDevice()->getD3D9DeviceCaps()) | mTexStageDesc[stage].coordIndex ); 2069 if(FAILED(hr)) 2070 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set texture auto tex.coord. generation mode", "D3D9RenderSystem::_setTextureCoordCalculation" ); 2071 } 2072 //--------------------------------------------------------------------- _setTextureMipmapBias(size_t unit,float bias)2073 void D3D9RenderSystem::_setTextureMipmapBias(size_t unit, float bias) 2074 { 2075 if (mCurrentCapabilities->hasCapability(RSC_MIPMAP_LOD_BIAS)) 2076 { 2077 // ugh - have to pass float data through DWORD with no conversion 2078 HRESULT hr = __SetSamplerState(getSamplerId(unit), D3DSAMP_MIPMAPLODBIAS, 2079 *(DWORD*)&bias); 2080 if(FAILED(hr)) 2081 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set texture mipmap bias", 2082 "D3D9RenderSystem::_setTextureMipmapBias" ); 2083 2084 } 2085 } 2086 //--------------------------------------------------------------------- _setTextureMatrix(size_t stage,const Matrix4 & xForm)2087 void D3D9RenderSystem::_setTextureMatrix( size_t stage, const Matrix4& xForm ) 2088 { 2089 HRESULT hr; 2090 D3DXMATRIX d3dMat; // the matrix we'll maybe apply 2091 Matrix4 newMat = xForm; // the matrix we'll apply after conv. to D3D format 2092 // Cache texcoord calc method to register 2093 TexCoordCalcMethod autoTexCoordType = mTexStageDesc[stage].autoTexCoordType; 2094 2095 // if a vertex program is bound, we mustn't set texture transforms 2096 if (mVertexProgramBound) 2097 { 2098 hr = __SetTextureStageState( static_cast<DWORD>(stage), D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE ); 2099 if( FAILED( hr ) ) 2100 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to disable texture coordinate transform", "D3D9RenderSystem::_setTextureMatrix" ); 2101 return; 2102 } 2103 2104 2105 if (autoTexCoordType == TEXCALC_ENVIRONMENT_MAP) 2106 { 2107 if (mDeviceManager->getActiveDevice()->getD3D9DeviceCaps().VertexProcessingCaps & D3DVTXPCAPS_TEXGEN_SPHEREMAP) 2108 { 2109 /** Invert the texture for the spheremap */ 2110 Matrix4 ogreMatEnvMap = Matrix4::IDENTITY; 2111 // set env_map values 2112 ogreMatEnvMap[1][1] = -1.0f; 2113 // concatenate with the xForm 2114 newMat = newMat.concatenate(ogreMatEnvMap); 2115 } 2116 else 2117 { 2118 /* If envmap is applied, but device doesn't support spheremap, 2119 then we have to use texture transform to make the camera space normal 2120 reference the envmap properly. This isn't exactly the same as spheremap 2121 (it looks nasty on flat areas because the camera space normals are the same) 2122 but it's the best approximation we have in the absence of a proper spheremap */ 2123 // concatenate with the xForm 2124 newMat = newMat.concatenate(Matrix4::CLIPSPACE2DTOIMAGESPACE); 2125 } 2126 } 2127 2128 // If this is a cubic reflection, we need to modify using the view matrix 2129 if (autoTexCoordType == TEXCALC_ENVIRONMENT_MAP_REFLECTION) 2130 { 2131 // Get transposed 3x3 2132 // We want to transpose since that will invert an orthonormal matrix ie rotation 2133 Matrix4 ogreViewTransposed; 2134 ogreViewTransposed[0][0] = mViewMatrix[0][0]; 2135 ogreViewTransposed[0][1] = mViewMatrix[1][0]; 2136 ogreViewTransposed[0][2] = mViewMatrix[2][0]; 2137 ogreViewTransposed[0][3] = 0.0f; 2138 2139 ogreViewTransposed[1][0] = mViewMatrix[0][1]; 2140 ogreViewTransposed[1][1] = mViewMatrix[1][1]; 2141 ogreViewTransposed[1][2] = mViewMatrix[2][1]; 2142 ogreViewTransposed[1][3] = 0.0f; 2143 2144 ogreViewTransposed[2][0] = mViewMatrix[0][2]; 2145 ogreViewTransposed[2][1] = mViewMatrix[1][2]; 2146 ogreViewTransposed[2][2] = mViewMatrix[2][2]; 2147 ogreViewTransposed[2][3] = 0.0f; 2148 2149 ogreViewTransposed[3][0] = 0.0f; 2150 ogreViewTransposed[3][1] = 0.0f; 2151 ogreViewTransposed[3][2] = 0.0f; 2152 ogreViewTransposed[3][3] = 1.0f; 2153 2154 newMat = newMat.concatenate(ogreViewTransposed); 2155 } 2156 2157 if (autoTexCoordType == TEXCALC_PROJECTIVE_TEXTURE) 2158 { 2159 // Derive camera space to projector space transform 2160 // To do this, we need to undo the camera view matrix, then 2161 // apply the projector view & projection matrices 2162 newMat = mViewMatrix.inverse(); 2163 if(mTexProjRelative) 2164 { 2165 Matrix4 viewMatrix; 2166 mTexStageDesc[stage].frustum->calcViewMatrixRelative(mTexProjRelativeOrigin, viewMatrix); 2167 newMat = viewMatrix * newMat; 2168 } 2169 else 2170 { 2171 newMat = mTexStageDesc[stage].frustum->getViewMatrix() * newMat; 2172 } 2173 newMat = mTexStageDesc[stage].frustum->getProjectionMatrix() * newMat; 2174 newMat = Matrix4::CLIPSPACE2DTOIMAGESPACE * newMat; 2175 newMat = xForm * newMat; 2176 } 2177 2178 // need this if texture is a cube map, to invert D3D's z coord 2179 if (autoTexCoordType != TEXCALC_NONE && 2180 autoTexCoordType != TEXCALC_PROJECTIVE_TEXTURE) 2181 { 2182 newMat[2][0] = -newMat[2][0]; 2183 newMat[2][1] = -newMat[2][1]; 2184 newMat[2][2] = -newMat[2][2]; 2185 newMat[2][3] = -newMat[2][3]; 2186 } 2187 2188 // convert our matrix to D3D format 2189 d3dMat = D3D9Mappings::makeD3DXMatrix(newMat); 2190 2191 // set the matrix if it's not the identity 2192 if (!D3DXMatrixIsIdentity(&d3dMat)) 2193 { 2194 /* It's seems D3D automatically add a texture coordinate with value 1, 2195 and fill up the remaining texture coordinates with 0 for the input 2196 texture coordinates before pass to texture coordinate transformation. 2197 2198 NOTE: It's difference with D3DDECLTYPE enumerated type expand in 2199 DirectX SDK documentation! 2200 2201 So we should prepare the texcoord transform, make the transformation 2202 just like standardized vector expand, thus, fill w with value 1 and 2203 others with 0. 2204 */ 2205 if (autoTexCoordType == TEXCALC_NONE) 2206 { 2207 /* FIXME: The actually input texture coordinate dimensions should 2208 be determine by texture coordinate vertex element. Now, just trust 2209 user supplied texture type matches texture coordinate vertex element. 2210 */ 2211 if (mTexStageDesc[stage].texType == D3D9Mappings::D3D_TEX_TYPE_NORMAL) 2212 { 2213 /* It's 2D input texture coordinate: 2214 2215 texcoord in vertex buffer D3D expanded to We are adjusted to 2216 --> --> 2217 (u, v) (u, v, 1, 0) (u, v, 0, 1) 2218 */ 2219 std::swap(d3dMat._31, d3dMat._41); 2220 std::swap(d3dMat._32, d3dMat._42); 2221 std::swap(d3dMat._33, d3dMat._43); 2222 std::swap(d3dMat._34, d3dMat._44); 2223 } 2224 } 2225 else 2226 { 2227 // All texgen generate 3D input texture coordinates. 2228 } 2229 2230 // tell D3D the dimension of tex. coord. 2231 int texCoordDim = D3DTTFF_COUNT2; 2232 if (mTexStageDesc[stage].autoTexCoordType == TEXCALC_PROJECTIVE_TEXTURE) 2233 { 2234 /* We want texcoords (u, v, w, q) always get divided by q, but D3D 2235 projected texcoords is divided by the last element (in the case of 2236 2D texcoord, is w). So we tweak the transform matrix, transform the 2237 texcoords with w and q swapped: (u, v, q, w), and then D3D will 2238 divide u, v by q. The w and q just ignored as it wasn't used by 2239 rasterizer. 2240 */ 2241 switch (mTexStageDesc[stage].texType) 2242 { 2243 case D3D9Mappings::D3D_TEX_TYPE_NORMAL: 2244 std::swap(d3dMat._13, d3dMat._14); 2245 std::swap(d3dMat._23, d3dMat._24); 2246 std::swap(d3dMat._33, d3dMat._34); 2247 std::swap(d3dMat._43, d3dMat._44); 2248 2249 texCoordDim = D3DTTFF_PROJECTED | D3DTTFF_COUNT3; 2250 break; 2251 2252 case D3D9Mappings::D3D_TEX_TYPE_CUBE: 2253 case D3D9Mappings::D3D_TEX_TYPE_VOLUME: 2254 // Yes, we support 3D projective texture. 2255 texCoordDim = D3DTTFF_PROJECTED | D3DTTFF_COUNT4; 2256 break; 2257 } 2258 } 2259 else 2260 { 2261 switch (mTexStageDesc[stage].texType) 2262 { 2263 case D3D9Mappings::D3D_TEX_TYPE_NORMAL: 2264 texCoordDim = D3DTTFF_COUNT2; 2265 break; 2266 case D3D9Mappings::D3D_TEX_TYPE_CUBE: 2267 case D3D9Mappings::D3D_TEX_TYPE_VOLUME: 2268 texCoordDim = D3DTTFF_COUNT3; 2269 break; 2270 } 2271 } 2272 2273 hr = __SetTextureStageState( static_cast<DWORD>(stage), D3DTSS_TEXTURETRANSFORMFLAGS, texCoordDim ); 2274 if (FAILED(hr)) 2275 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set texture coord. dimension", "D3D9RenderSystem::_setTextureMatrix" ); 2276 2277 hr = getActiveD3D9Device()->SetTransform( (D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0 + stage), &d3dMat ); 2278 if (FAILED(hr)) 2279 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set texture matrix", "D3D9RenderSystem::_setTextureMatrix" ); 2280 } 2281 else 2282 { 2283 // disable all of this 2284 hr = __SetTextureStageState( static_cast<DWORD>(stage), D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE ); 2285 if( FAILED( hr ) ) 2286 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to disable texture coordinate transform", "D3D9RenderSystem::_setTextureMatrix" ); 2287 2288 // Needless to sets texture transform here, it's never used at all 2289 } 2290 } 2291 //--------------------------------------------------------------------- _setTextureAddressingMode(size_t stage,const TextureUnitState::UVWAddressingMode & uvw)2292 void D3D9RenderSystem::_setTextureAddressingMode( size_t stage, 2293 const TextureUnitState::UVWAddressingMode& uvw ) 2294 { 2295 HRESULT hr; 2296 if( FAILED( hr = __SetSamplerState( getSamplerId(stage), D3DSAMP_ADDRESSU, D3D9Mappings::get(uvw.u, mDeviceManager->getActiveDevice()->getD3D9DeviceCaps()) ) ) ) 2297 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set texture addressing mode for U", "D3D9RenderSystem::_setTextureAddressingMode" ); 2298 if( FAILED( hr = __SetSamplerState( getSamplerId(stage), D3DSAMP_ADDRESSV, D3D9Mappings::get(uvw.v, mDeviceManager->getActiveDevice()->getD3D9DeviceCaps()) ) ) ) 2299 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set texture addressing mode for V", "D3D9RenderSystem::_setTextureAddressingMode" ); 2300 if( FAILED( hr = __SetSamplerState( getSamplerId(stage), D3DSAMP_ADDRESSW, D3D9Mappings::get(uvw.w, mDeviceManager->getActiveDevice()->getD3D9DeviceCaps()) ) ) ) 2301 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set texture addressing mode for W", "D3D9RenderSystem::_setTextureAddressingMode" ); 2302 } 2303 //----------------------------------------------------------------------------- _setTextureBorderColour(size_t stage,const ColourValue & colour)2304 void D3D9RenderSystem::_setTextureBorderColour(size_t stage, 2305 const ColourValue& colour) 2306 { 2307 HRESULT hr; 2308 if( FAILED( hr = __SetSamplerState( getSamplerId(stage), D3DSAMP_BORDERCOLOR, colour.getAsARGB()) ) ) 2309 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set texture border colour", "D3D9RenderSystem::_setTextureBorderColour" ); 2310 } 2311 //--------------------------------------------------------------------- _setTextureBlendMode(size_t stage,const LayerBlendModeEx & bm)2312 void D3D9RenderSystem::_setTextureBlendMode( size_t stage, const LayerBlendModeEx& bm ) 2313 { 2314 HRESULT hr = S_OK; 2315 D3DTEXTURESTAGESTATETYPE tss; 2316 D3DCOLOR manualD3D; 2317 2318 // choose type of blend. 2319 if( bm.blendType == LBT_COLOUR ) 2320 tss = D3DTSS_COLOROP; 2321 else if( bm.blendType == LBT_ALPHA ) 2322 tss = D3DTSS_ALPHAOP; 2323 else 2324 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 2325 "Invalid blend type", "D3D9RenderSystem::_setTextureBlendMode"); 2326 2327 // set manual factor if required by operation 2328 if (bm.operation == LBX_BLEND_MANUAL) 2329 { 2330 hr = __SetRenderState( D3DRS_TEXTUREFACTOR, D3DXCOLOR(0.0, 0.0, 0.0, bm.factor) ); 2331 if (FAILED(hr)) 2332 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set manual factor", "D3D9RenderSystem::_setTextureBlendMode" ); 2333 } 2334 // set operation 2335 hr = __SetTextureStageState( static_cast<DWORD>(stage), tss, D3D9Mappings::get(bm.operation, mDeviceManager->getActiveDevice()->getD3D9DeviceCaps()) ); 2336 if (FAILED(hr)) 2337 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set operation", "D3D9RenderSystem::_setTextureBlendMode" ); 2338 2339 // choose source 1 2340 if( bm.blendType == LBT_COLOUR ) 2341 { 2342 tss = D3DTSS_COLORARG1; 2343 manualD3D = D3DXCOLOR( bm.colourArg1.r, bm.colourArg1.g, bm.colourArg1.b, bm.colourArg1.a ); 2344 mManualBlendColours[stage][0] = bm.colourArg1; 2345 } 2346 else if( bm.blendType == LBT_ALPHA ) 2347 { 2348 tss = D3DTSS_ALPHAARG1; 2349 manualD3D = D3DXCOLOR( mManualBlendColours[stage][0].r, 2350 mManualBlendColours[stage][0].g, 2351 mManualBlendColours[stage][0].b, bm.alphaArg1 ); 2352 } 2353 else 2354 { 2355 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 2356 "Invalid blend type", "D3D9RenderSystem::_setTextureBlendMode"); 2357 } 2358 // Set manual factor if required 2359 if (bm.source1 == LBS_MANUAL) 2360 { 2361 if (mCurrentCapabilities->hasCapability(RSC_PERSTAGECONSTANT)) 2362 { 2363 // Per-stage state 2364 hr = __SetTextureStageState(static_cast<DWORD>(stage), D3DTSS_CONSTANT, manualD3D); 2365 } 2366 else 2367 { 2368 // Global state 2369 hr = __SetRenderState( D3DRS_TEXTUREFACTOR, manualD3D ); 2370 } 2371 if (FAILED(hr)) 2372 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set manual factor", "D3D9RenderSystem::_setTextureBlendMode" ); 2373 } 2374 // set source 1 2375 hr = __SetTextureStageState( static_cast<DWORD>(stage), tss, D3D9Mappings::get(bm.source1, mCurrentCapabilities->hasCapability(RSC_PERSTAGECONSTANT)) ); 2376 if (FAILED(hr)) 2377 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set source1", "D3D9RenderSystem::_setTextureBlendMode" ); 2378 2379 // choose source 2 2380 if( bm.blendType == LBT_COLOUR ) 2381 { 2382 tss = D3DTSS_COLORARG2; 2383 manualD3D = D3DXCOLOR( bm.colourArg2.r, bm.colourArg2.g, bm.colourArg2.b, bm.colourArg2.a ); 2384 mManualBlendColours[stage][1] = bm.colourArg2; 2385 } 2386 else if( bm.blendType == LBT_ALPHA ) 2387 { 2388 tss = D3DTSS_ALPHAARG2; 2389 manualD3D = D3DXCOLOR( mManualBlendColours[stage][1].r, 2390 mManualBlendColours[stage][1].g, 2391 mManualBlendColours[stage][1].b, 2392 bm.alphaArg2 ); 2393 } 2394 // Set manual factor if required 2395 if (bm.source2 == LBS_MANUAL) 2396 { 2397 if (mCurrentCapabilities->hasCapability(RSC_PERSTAGECONSTANT)) 2398 { 2399 // Per-stage state 2400 hr = __SetTextureStageState(static_cast<DWORD>(stage), D3DTSS_CONSTANT, manualD3D); 2401 } 2402 else 2403 { 2404 hr = __SetRenderState( D3DRS_TEXTUREFACTOR, manualD3D ); 2405 } 2406 if (FAILED(hr)) 2407 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set manual factor", "D3D9RenderSystem::_setTextureBlendMode" ); 2408 } 2409 // Now set source 2 2410 hr = __SetTextureStageState( static_cast<DWORD>(stage), tss, D3D9Mappings::get(bm.source2, mCurrentCapabilities->hasCapability(RSC_PERSTAGECONSTANT)) ); 2411 if (FAILED(hr)) 2412 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set source 2", "D3D9RenderSystem::_setTextureBlendMode" ); 2413 2414 // Set interpolation factor if lerping 2415 if (bm.operation == LBX_BLEND_DIFFUSE_COLOUR && 2416 mDeviceManager->getActiveDevice()->getD3D9DeviceCaps().TextureOpCaps & D3DTEXOPCAPS_LERP) 2417 { 2418 // choose source 0 (lerp factor) 2419 if( bm.blendType == LBT_COLOUR ) 2420 { 2421 tss = D3DTSS_COLORARG0; 2422 } 2423 else if( bm.blendType == LBT_ALPHA ) 2424 { 2425 tss = D3DTSS_ALPHAARG0; 2426 } 2427 hr = __SetTextureStageState(static_cast<DWORD>(stage), tss, D3DTA_DIFFUSE); 2428 2429 if (FAILED(hr)) 2430 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set lerp source 0", 2431 "D3D9RenderSystem::_setTextureBlendMode" ); 2432 2433 } 2434 } 2435 //--------------------------------------------------------------------- _setSceneBlending(SceneBlendFactor sourceFactor,SceneBlendFactor destFactor,SceneBlendOperation op)2436 void D3D9RenderSystem::_setSceneBlending( SceneBlendFactor sourceFactor, SceneBlendFactor destFactor, SceneBlendOperation op ) 2437 { 2438 HRESULT hr; 2439 if( sourceFactor == SBF_ONE && destFactor == SBF_ZERO) 2440 { 2441 if (FAILED(hr = __SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE))) 2442 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set alpha blending option", "D3D9RenderSystem::_setSceneBlending" ); 2443 } 2444 else 2445 { 2446 if (FAILED(hr = __SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE))) 2447 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set alpha blending option", "D3D9RenderSystem::_setSceneBlending" ); 2448 if (FAILED(hr = __SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE))) 2449 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set separate alpha blending option", "D3D9RenderSystem::_setSceneBlending" ); 2450 if( FAILED( hr = __SetRenderState( D3DRS_SRCBLEND, D3D9Mappings::get(sourceFactor) ) ) ) 2451 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set source blend", "D3D9RenderSystem::_setSceneBlending" ); 2452 if( FAILED( hr = __SetRenderState( D3DRS_DESTBLEND, D3D9Mappings::get(destFactor) ) ) ) 2453 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set destination blend", "D3D9RenderSystem::_setSceneBlending" ); 2454 } 2455 2456 if (FAILED(hr = __SetRenderState(D3DRS_BLENDOP, D3D9Mappings::get(op)))) 2457 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set scene blending operation option", "D3D9RenderSystem::_setSceneBlendingOperation" ); 2458 if (FAILED(hr = __SetRenderState(D3DRS_BLENDOPALPHA, D3D9Mappings::get(op)))) 2459 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set scene blending operation option", "D3D9RenderSystem::_setSceneBlendingOperation" ); 2460 } 2461 //--------------------------------------------------------------------- _setSeparateSceneBlending(SceneBlendFactor sourceFactor,SceneBlendFactor destFactor,SceneBlendFactor sourceFactorAlpha,SceneBlendFactor destFactorAlpha,SceneBlendOperation op,SceneBlendOperation alphaOp)2462 void D3D9RenderSystem::_setSeparateSceneBlending( SceneBlendFactor sourceFactor, SceneBlendFactor destFactor, SceneBlendFactor sourceFactorAlpha, 2463 SceneBlendFactor destFactorAlpha, SceneBlendOperation op, SceneBlendOperation alphaOp ) 2464 { 2465 HRESULT hr; 2466 if( sourceFactor == SBF_ONE && destFactor == SBF_ZERO && 2467 sourceFactorAlpha == SBF_ONE && destFactorAlpha == SBF_ZERO) 2468 { 2469 if (FAILED(hr = __SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE))) 2470 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set alpha blending option", "D3D9RenderSystem::_setSceneBlending" ); 2471 } 2472 else 2473 { 2474 if (FAILED(hr = __SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE))) 2475 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set alpha blending option", "D3D9RenderSystem::_setSeperateSceneBlending" ); 2476 if (FAILED(hr = __SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE))) 2477 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set separate alpha blending option", "D3D9RenderSystem::_setSeperateSceneBlending" ); 2478 if( FAILED( hr = __SetRenderState( D3DRS_SRCBLEND, D3D9Mappings::get(sourceFactor) ) ) ) 2479 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set source blend", "D3D9RenderSystem::_setSeperateSceneBlending" ); 2480 if( FAILED( hr = __SetRenderState( D3DRS_DESTBLEND, D3D9Mappings::get(destFactor) ) ) ) 2481 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set destination blend", "D3D9RenderSystem::_setSeperateSceneBlending" ); 2482 if( FAILED( hr = __SetRenderState( D3DRS_SRCBLENDALPHA, D3D9Mappings::get(sourceFactorAlpha) ) ) ) 2483 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set alpha source blend", "D3D9RenderSystem::_setSeperateSceneBlending" ); 2484 if( FAILED( hr = __SetRenderState( D3DRS_DESTBLENDALPHA, D3D9Mappings::get(destFactorAlpha) ) ) ) 2485 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set alpha destination blend", "D3D9RenderSystem::_setSeperateSceneBlending" ); 2486 } 2487 2488 if (FAILED(hr = __SetRenderState(D3DRS_BLENDOP, D3D9Mappings::get(op)))) 2489 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set scene blending operation option", "D3D9RenderSystem::_setSceneBlendingOperation" ); 2490 if (FAILED(hr = __SetRenderState(D3DRS_BLENDOPALPHA, D3D9Mappings::get(alphaOp)))) 2491 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set alpha scene blending operation option", "D3D9RenderSystem::_setSceneBlendingOperation" ); 2492 } 2493 //--------------------------------------------------------------------- _setAlphaRejectSettings(CompareFunction func,unsigned char value,bool alphaToCoverage)2494 void D3D9RenderSystem::_setAlphaRejectSettings( CompareFunction func, unsigned char value, bool alphaToCoverage ) 2495 { 2496 HRESULT hr; 2497 bool a2c = false; 2498 static bool lasta2c = false; 2499 2500 if (func != CMPF_ALWAYS_PASS) 2501 { 2502 if( FAILED( hr = __SetRenderState( D3DRS_ALPHATESTENABLE, TRUE ) ) ) 2503 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to enable alpha testing", 2504 "D3D9RenderSystem::_setAlphaRejectSettings" ); 2505 2506 a2c = alphaToCoverage; 2507 } 2508 else 2509 { 2510 if( FAILED( hr = __SetRenderState( D3DRS_ALPHATESTENABLE, FALSE ) ) ) 2511 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to disable alpha testing", 2512 "D3D9RenderSystem::_setAlphaRejectSettings" ); 2513 } 2514 // Set always just be sure 2515 if( FAILED( hr = __SetRenderState( D3DRS_ALPHAFUNC, D3D9Mappings::get(func) ) ) ) 2516 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set alpha reject function", "D3D9RenderSystem::_setAlphaRejectSettings" ); 2517 if( FAILED( hr = __SetRenderState( D3DRS_ALPHAREF, value ) ) ) 2518 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set render state D3DRS_ALPHAREF", "D3D9RenderSystem::_setAlphaRejectSettings" ); 2519 2520 // Alpha to coverage 2521 if (getCapabilities()->hasCapability(RSC_ALPHA_TO_COVERAGE)) 2522 { 2523 // Vendor-specific hacks on renderstate, gotta love 'em 2524 if (getCapabilities()->getVendor() == GPU_NVIDIA) 2525 { 2526 if (a2c) 2527 { 2528 if( FAILED( hr = __SetRenderState( D3DRS_ADAPTIVETESS_Y, (D3DFORMAT)MAKEFOURCC('A', 'T', 'O', 'C') ) ) ) 2529 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set alpha to coverage option", "D3D9RenderSystem::_setAlphaRejectSettings" ); 2530 } 2531 else 2532 { 2533 if( FAILED( hr = __SetRenderState( D3DRS_ADAPTIVETESS_Y, D3DFMT_UNKNOWN ) ) ) 2534 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set alpha to coverage option", "D3D9RenderSystem::_setAlphaRejectSettings" ); 2535 } 2536 2537 } 2538 else if ((getCapabilities()->getVendor() == GPU_AMD)) 2539 { 2540 if (a2c) 2541 { 2542 if( FAILED( hr = __SetRenderState( D3DRS_POINTSIZE, MAKEFOURCC('A','2','M','1') ) ) ) 2543 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set alpha to coverage option", "D3D9RenderSystem::_setAlphaRejectSettings" ); 2544 } 2545 else 2546 { 2547 // discovered this through trial and error, seems to work 2548 if( FAILED( hr = __SetRenderState( D3DRS_POINTSIZE, MAKEFOURCC('A','2','M','0') ) ) ) 2549 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set alpha to coverage option", "D3D9RenderSystem::_setAlphaRejectSettings" ); 2550 } 2551 } 2552 // no hacks available for any other vendors? 2553 lasta2c = a2c; 2554 } 2555 2556 } 2557 //--------------------------------------------------------------------- _setCullingMode(CullingMode mode)2558 void D3D9RenderSystem::_setCullingMode( CullingMode mode ) 2559 { 2560 mCullingMode = mode; 2561 HRESULT hr; 2562 bool flip = ((mActiveRenderTarget->requiresTextureFlipping() && !mInvertVertexWinding) || 2563 (!mActiveRenderTarget->requiresTextureFlipping() && mInvertVertexWinding)); 2564 2565 if( FAILED (hr = __SetRenderState(D3DRS_CULLMODE, 2566 D3D9Mappings::get(mode, flip))) ) 2567 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set culling mode", "D3D9RenderSystem::_setCullingMode" ); 2568 } 2569 //--------------------------------------------------------------------- _setDepthBufferParams(bool depthTest,bool depthWrite,CompareFunction depthFunction)2570 void D3D9RenderSystem::_setDepthBufferParams( bool depthTest, bool depthWrite, CompareFunction depthFunction ) 2571 { 2572 _setDepthBufferCheckEnabled( depthTest ); 2573 _setDepthBufferWriteEnabled( depthWrite ); 2574 _setDepthBufferFunction( depthFunction ); 2575 } 2576 //--------------------------------------------------------------------- _setDepthBufferCheckEnabled(bool enabled)2577 void D3D9RenderSystem::_setDepthBufferCheckEnabled( bool enabled ) 2578 { 2579 HRESULT hr; 2580 2581 if( enabled ) 2582 { 2583 // Use w-buffer if available and enabled 2584 if( mWBuffer && mDeviceManager->getActiveDevice()->getD3D9DeviceCaps().RasterCaps & D3DPRASTERCAPS_WBUFFER ) 2585 hr = __SetRenderState( D3DRS_ZENABLE, D3DZB_USEW ); 2586 else 2587 hr = __SetRenderState( D3DRS_ZENABLE, D3DZB_TRUE ); 2588 } 2589 else 2590 hr = __SetRenderState( D3DRS_ZENABLE, D3DZB_FALSE ); 2591 2592 if( FAILED( hr ) ) 2593 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting depth buffer test state", "D3D9RenderSystem::_setDepthBufferCheckEnabled" ); 2594 } 2595 //--------------------------------------------------------------------- _setDepthBufferWriteEnabled(bool enabled)2596 void D3D9RenderSystem::_setDepthBufferWriteEnabled( bool enabled ) 2597 { 2598 HRESULT hr; 2599 2600 if( FAILED( hr = __SetRenderState( D3DRS_ZWRITEENABLE, enabled ) ) ) 2601 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting depth buffer write state", "D3D9RenderSystem::_setDepthBufferWriteEnabled" ); 2602 } 2603 //--------------------------------------------------------------------- _setDepthBufferFunction(CompareFunction func)2604 void D3D9RenderSystem::_setDepthBufferFunction( CompareFunction func ) 2605 { 2606 HRESULT hr; 2607 if( FAILED( hr = __SetRenderState( D3DRS_ZFUNC, D3D9Mappings::get(func) ) ) ) 2608 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting depth buffer test function", "D3D9RenderSystem::_setDepthBufferFunction" ); 2609 } 2610 //--------------------------------------------------------------------- _setDepthBias(float constantBias,float slopeScaleBias)2611 void D3D9RenderSystem::_setDepthBias(float constantBias, float slopeScaleBias) 2612 { 2613 2614 if ((mDeviceManager->getActiveDevice()->getD3D9DeviceCaps().RasterCaps & D3DPRASTERCAPS_DEPTHBIAS) != 0) 2615 { 2616 // Negate bias since D3D is backward 2617 // D3D also expresses the constant bias as an absolute value, rather than 2618 // relative to minimum depth unit, so scale to fit 2619 constantBias = -constantBias / 250000.0f; 2620 HRESULT hr = __SetRenderState(D3DRS_DEPTHBIAS, FLOAT2DWORD(constantBias)); 2621 if (FAILED(hr)) 2622 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting constant depth bias", 2623 "D3D9RenderSystem::_setDepthBias"); 2624 } 2625 2626 if ((mDeviceManager->getActiveDevice()->getD3D9DeviceCaps().RasterCaps & D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS) != 0) 2627 { 2628 // Negate bias since D3D is backward 2629 slopeScaleBias = -slopeScaleBias; 2630 HRESULT hr = __SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, FLOAT2DWORD(slopeScaleBias)); 2631 if (FAILED(hr)) 2632 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting slope scale depth bias", 2633 "D3D9RenderSystem::_setDepthBias"); 2634 } 2635 2636 2637 } 2638 //--------------------------------------------------------------------- _setColourBufferWriteEnabled(bool red,bool green,bool blue,bool alpha)2639 void D3D9RenderSystem::_setColourBufferWriteEnabled(bool red, bool green, 2640 bool blue, bool alpha) 2641 { 2642 DWORD val = 0; 2643 if (red) 2644 val |= D3DCOLORWRITEENABLE_RED; 2645 if (green) 2646 val |= D3DCOLORWRITEENABLE_GREEN; 2647 if (blue) 2648 val |= D3DCOLORWRITEENABLE_BLUE; 2649 if (alpha) 2650 val |= D3DCOLORWRITEENABLE_ALPHA; 2651 HRESULT hr = __SetRenderState(D3DRS_COLORWRITEENABLE, val); 2652 if (FAILED(hr)) 2653 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting colour write enable flags", 2654 "D3D9RenderSystem::_setColourBufferWriteEnabled"); 2655 } 2656 //--------------------------------------------------------------------- _setFog(FogMode mode,const ColourValue & colour,Real densitiy,Real start,Real end)2657 void D3D9RenderSystem::_setFog( FogMode mode, const ColourValue& colour, Real densitiy, Real start, Real end ) 2658 { 2659 HRESULT hr; 2660 2661 D3DRENDERSTATETYPE fogType, fogTypeNot; 2662 2663 if (mDeviceManager->getActiveDevice()->getD3D9DeviceCaps().RasterCaps & D3DPRASTERCAPS_FOGTABLE) 2664 { 2665 fogType = D3DRS_FOGTABLEMODE; 2666 fogTypeNot = D3DRS_FOGVERTEXMODE; 2667 } 2668 else 2669 { 2670 fogType = D3DRS_FOGVERTEXMODE; 2671 fogTypeNot = D3DRS_FOGTABLEMODE; 2672 } 2673 2674 if( mode == FOG_NONE) 2675 { 2676 // just disable 2677 hr = __SetRenderState(fogType, D3DFOG_NONE ); 2678 hr = __SetRenderState(D3DRS_FOGENABLE, FALSE); 2679 } 2680 else 2681 { 2682 // Allow fog 2683 hr = __SetRenderState( D3DRS_FOGENABLE, TRUE ); 2684 hr = __SetRenderState( fogTypeNot, D3DFOG_NONE ); 2685 hr = __SetRenderState( fogType, D3D9Mappings::get(mode) ); 2686 2687 hr = __SetRenderState( D3DRS_FOGCOLOR, colour.getAsARGB() ); 2688 hr = __SetFloatRenderState( D3DRS_FOGSTART, start ); 2689 hr = __SetFloatRenderState( D3DRS_FOGEND, end ); 2690 hr = __SetFloatRenderState( D3DRS_FOGDENSITY, densitiy ); 2691 } 2692 2693 if( FAILED( hr ) ) 2694 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting render state", "D3D9RenderSystem::_setFog" ); 2695 } 2696 //--------------------------------------------------------------------- _setPolygonMode(PolygonMode level)2697 void D3D9RenderSystem::_setPolygonMode(PolygonMode level) 2698 { 2699 HRESULT hr = __SetRenderState(D3DRS_FILLMODE, D3D9Mappings::get(level)); 2700 if (FAILED(hr)) 2701 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting polygon mode.", "D3D9RenderSystem::setPolygonMode"); 2702 } 2703 //--------------------------------------------------------------------- setStencilCheckEnabled(bool enabled)2704 void D3D9RenderSystem::setStencilCheckEnabled(bool enabled) 2705 { 2706 // Allow stencilling 2707 HRESULT hr = __SetRenderState(D3DRS_STENCILENABLE, enabled); 2708 if (FAILED(hr)) 2709 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error enabling / disabling stencilling.", 2710 "D3D9RenderSystem::setStencilCheckEnabled"); 2711 } 2712 //--------------------------------------------------------------------- setStencilBufferParams(CompareFunction func,uint32 refValue,uint32 compareMask,uint32 writeMask,StencilOperation stencilFailOp,StencilOperation depthFailOp,StencilOperation passOp,bool twoSidedOperation)2713 void D3D9RenderSystem::setStencilBufferParams(CompareFunction func, 2714 uint32 refValue, uint32 compareMask, uint32 writeMask, StencilOperation stencilFailOp, 2715 StencilOperation depthFailOp, StencilOperation passOp, 2716 bool twoSidedOperation) 2717 { 2718 HRESULT hr; 2719 bool flip; 2720 2721 // 2-sided operation 2722 if (twoSidedOperation) 2723 { 2724 if (!mCurrentCapabilities->hasCapability(RSC_TWO_SIDED_STENCIL)) 2725 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "2-sided stencils are not supported", 2726 "D3D9RenderSystem::setStencilBufferParams"); 2727 hr = __SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE); 2728 if (FAILED(hr)) 2729 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting 2-sided stencil mode.", 2730 "D3D9RenderSystem::setStencilBufferParams"); 2731 // NB: We should always treat CCW as front face for consistent with default 2732 // culling mode. Therefore, we must take care with two-sided stencil settings. 2733 flip = (mInvertVertexWinding && mActiveRenderTarget->requiresTextureFlipping()) || 2734 (!mInvertVertexWinding && !mActiveRenderTarget->requiresTextureFlipping()); 2735 2736 // Set alternative versions of ops 2737 // fail op 2738 hr = __SetRenderState(D3DRS_CCW_STENCILFAIL, D3D9Mappings::get(stencilFailOp, !flip)); 2739 if (FAILED(hr)) 2740 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil fail operation (2-sided).", 2741 "D3D9RenderSystem::setStencilBufferParams"); 2742 2743 // depth fail op 2744 hr = __SetRenderState(D3DRS_CCW_STENCILZFAIL, D3D9Mappings::get(depthFailOp, !flip)); 2745 if (FAILED(hr)) 2746 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil depth fail operation (2-sided).", 2747 "D3D9RenderSystem::setStencilBufferParams"); 2748 2749 // pass op 2750 hr = __SetRenderState(D3DRS_CCW_STENCILPASS, D3D9Mappings::get(passOp, !flip)); 2751 if (FAILED(hr)) 2752 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil pass operation (2-sided).", 2753 "D3D9RenderSystem::setStencilBufferParams"); 2754 } 2755 else 2756 { 2757 hr = __SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE); 2758 if (FAILED(hr)) 2759 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting 1-sided stencil mode.", 2760 "D3D9RenderSystem::setStencilBufferParams"); 2761 flip = false; 2762 } 2763 2764 // func 2765 hr = __SetRenderState(D3DRS_STENCILFUNC, D3D9Mappings::get(func)); 2766 if (FAILED(hr)) 2767 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil buffer test function.", 2768 "D3D9RenderSystem::setStencilBufferParams"); 2769 2770 // reference value 2771 hr = __SetRenderState(D3DRS_STENCILREF, refValue); 2772 if (FAILED(hr)) 2773 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil buffer reference value.", 2774 "D3D9RenderSystem::setStencilBufferParams"); 2775 2776 // compare mask 2777 hr = __SetRenderState(D3DRS_STENCILMASK, compareMask); 2778 if (FAILED(hr)) 2779 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil buffer compare mask.", 2780 "D3D9RenderSystem::setStencilBufferParams"); 2781 2782 // compare mask 2783 hr = __SetRenderState(D3DRS_STENCILWRITEMASK, writeMask); 2784 if (FAILED(hr)) 2785 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil buffer write mask.", 2786 "D3D9RenderSystem::setStencilBufferParams"); 2787 2788 // fail op 2789 hr = __SetRenderState(D3DRS_STENCILFAIL, D3D9Mappings::get(stencilFailOp, flip)); 2790 if (FAILED(hr)) 2791 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil fail operation.", 2792 "D3D9RenderSystem::setStencilBufferParams"); 2793 2794 // depth fail op 2795 hr = __SetRenderState(D3DRS_STENCILZFAIL, D3D9Mappings::get(depthFailOp, flip)); 2796 if (FAILED(hr)) 2797 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil depth fail operation.", 2798 "D3D9RenderSystem::setStencilBufferParams"); 2799 2800 // pass op 2801 hr = __SetRenderState(D3DRS_STENCILPASS, D3D9Mappings::get(passOp, flip)); 2802 if (FAILED(hr)) 2803 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil pass operation.", 2804 "D3D9RenderSystem::setStencilBufferParams"); 2805 } 2806 //--------------------------------------------------------------------- _setTextureUnitFiltering(size_t unit,FilterType ftype,FilterOptions filter)2807 void D3D9RenderSystem::_setTextureUnitFiltering(size_t unit, FilterType ftype, 2808 FilterOptions filter) 2809 { 2810 HRESULT hr; 2811 D3D9Mappings::eD3DTexType texType = mTexStageDesc[unit].texType; 2812 hr = __SetSamplerState( getSamplerId(unit), D3D9Mappings::get(ftype), 2813 D3D9Mappings::get(ftype, filter, mDeviceManager->getActiveDevice()->getD3D9DeviceCaps(), texType)); 2814 if (FAILED(hr)) 2815 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set texture filter ", "D3D9RenderSystem::_setTextureUnitFiltering"); 2816 } 2817 //--------------------------------------------------------------------- _setTextureUnitCompareFunction(size_t unit,CompareFunction function)2818 void D3D9RenderSystem::_setTextureUnitCompareFunction(size_t unit, CompareFunction function) 2819 { 2820 //no effect in directX9 rendersystem 2821 } 2822 //--------------------------------------------------------------------- _setTextureUnitCompareEnabled(size_t unit,bool compare)2823 void D3D9RenderSystem::_setTextureUnitCompareEnabled(size_t unit, bool compare) 2824 { 2825 //no effect in directX9 rendersystem 2826 } 2827 //--------------------------------------------------------------------- _getCurrentAnisotropy(size_t unit)2828 DWORD D3D9RenderSystem::_getCurrentAnisotropy(size_t unit) 2829 { 2830 DWORD oldVal; 2831 getActiveD3D9Device()->GetSamplerState(static_cast<DWORD>(unit), D3DSAMP_MAXANISOTROPY, &oldVal); 2832 return oldVal; 2833 } 2834 //--------------------------------------------------------------------- _setTextureLayerAnisotropy(size_t unit,unsigned int maxAnisotropy)2835 void D3D9RenderSystem::_setTextureLayerAnisotropy(size_t unit, unsigned int maxAnisotropy) 2836 { 2837 if (static_cast<DWORD>(maxAnisotropy) > mDeviceManager->getActiveDevice()->getD3D9DeviceCaps().MaxAnisotropy) 2838 maxAnisotropy = mDeviceManager->getActiveDevice()->getD3D9DeviceCaps().MaxAnisotropy; 2839 2840 if (_getCurrentAnisotropy(unit) != maxAnisotropy) 2841 __SetSamplerState( getSamplerId(unit), D3DSAMP_MAXANISOTROPY, maxAnisotropy ); 2842 } 2843 //--------------------------------------------------------------------- __SetRenderState(D3DRENDERSTATETYPE state,DWORD value)2844 HRESULT D3D9RenderSystem::__SetRenderState(D3DRENDERSTATETYPE state, DWORD value) 2845 { 2846 HRESULT hr; 2847 DWORD oldVal; 2848 2849 if ( FAILED( hr = getActiveD3D9Device()->GetRenderState(state, &oldVal) ) ) 2850 return hr; 2851 if ( oldVal == value ) 2852 return D3D_OK; 2853 else 2854 return getActiveD3D9Device()->SetRenderState(state, value); 2855 } 2856 //--------------------------------------------------------------------- __SetSamplerState(DWORD sampler,D3DSAMPLERSTATETYPE type,DWORD value)2857 HRESULT D3D9RenderSystem::__SetSamplerState(DWORD sampler, D3DSAMPLERSTATETYPE type, DWORD value) 2858 { 2859 HRESULT hr; 2860 DWORD oldVal; 2861 2862 if ( FAILED( hr = getActiveD3D9Device()->GetSamplerState(sampler, type, &oldVal) ) ) 2863 return hr; 2864 if ( oldVal == value ) 2865 return D3D_OK; 2866 else 2867 return getActiveD3D9Device()->SetSamplerState(sampler, type, value); 2868 } 2869 //--------------------------------------------------------------------- __SetTextureStageState(DWORD stage,D3DTEXTURESTAGESTATETYPE type,DWORD value)2870 HRESULT D3D9RenderSystem::__SetTextureStageState(DWORD stage, D3DTEXTURESTAGESTATETYPE type, DWORD value) 2871 { 2872 HRESULT hr; 2873 DWORD oldVal; 2874 2875 // can only set fixed-function texture stage state 2876 if (stage < 8) 2877 { 2878 if ( FAILED( hr = getActiveD3D9Device()->GetTextureStageState(stage, type, &oldVal) ) ) 2879 return hr; 2880 if ( oldVal == value ) 2881 return D3D_OK; 2882 else 2883 return getActiveD3D9Device()->SetTextureStageState(stage, type, value); 2884 } 2885 else 2886 { 2887 return D3D_OK; 2888 } 2889 } 2890 //--------------------------------------------------------------------- _createDepthBufferFor(RenderTarget * renderTarget)2891 DepthBuffer* D3D9RenderSystem::_createDepthBufferFor( RenderTarget *renderTarget ) 2892 { 2893 IDirect3DSurface9* pBack[OGRE_MAX_MULTIPLE_RENDER_TARGETS]; 2894 memset (pBack, 0, sizeof(pBack) ); 2895 renderTarget->getCustomAttribute( "DDBACKBUFFER", &pBack ); 2896 if( !pBack[0] ) 2897 return 0; 2898 2899 D3DSURFACE_DESC srfDesc; 2900 if( FAILED(pBack[0]->GetDesc(&srfDesc)) ) 2901 { 2902 OGRE_EXCEPT( Exception::ERR_RENDERINGAPI_ERROR, 2903 "Failed to retrieve Surface Description from BackBuffer. RenderTarget: " + 2904 renderTarget->getName(), 2905 "D3D9RenderSystem::_createDepthBufferFor" ); 2906 } 2907 2908 //Find an appropiarte format for this depth buffer that best matches the RenderTarget's 2909 D3DFORMAT dsfmt = _getDepthStencilFormatFor( srfDesc.Format ); 2910 2911 //Create the depthstencil surface 2912 IDirect3DSurface9 *depthBufferSurface = NULL; 2913 IDirect3DDevice9* activeDevice = getActiveD3D9Device(); 2914 HRESULT hr = activeDevice->CreateDepthStencilSurface( 2915 srfDesc.Width, srfDesc.Height, dsfmt, 2916 srfDesc.MultiSampleType, srfDesc.MultiSampleQuality, 2917 TRUE, // discard true or false? 2918 &depthBufferSurface, NULL); 2919 if( FAILED(hr) ) 2920 { 2921 String msg = DXGetErrorDescription(hr); 2922 OGRE_EXCEPT( Exception::ERR_RENDERINGAPI_ERROR, 2923 "Error CreateDepthStencilSurface : " + msg, 2924 "D3D9RenderSystem::_createDepthBufferFor" ); 2925 } 2926 2927 D3D9DepthBuffer *newDepthBuffer = OGRE_NEW D3D9DepthBuffer( DepthBuffer::POOL_DEFAULT, this, 2928 activeDevice, depthBufferSurface, 2929 dsfmt, srfDesc.Width, srfDesc.Height, 2930 srfDesc.MultiSampleType, srfDesc.MultiSampleQuality, false ); 2931 2932 return newDepthBuffer; 2933 } 2934 2935 //--------------------------------------------------------------------- _addManualDepthBuffer(IDirect3DDevice9 * depthSurfaceDevice,IDirect3DSurface9 * depthSurface)2936 DepthBuffer* D3D9RenderSystem::_addManualDepthBuffer( IDirect3DDevice9* depthSurfaceDevice, IDirect3DSurface9 *depthSurface ) 2937 { 2938 //If this depth buffer was already added, return that one 2939 DepthBufferVec::const_iterator itor = mDepthBufferPool[DepthBuffer::POOL_DEFAULT].begin(); 2940 DepthBufferVec::const_iterator end = mDepthBufferPool[DepthBuffer::POOL_DEFAULT].end(); 2941 2942 while( itor != end ) 2943 { 2944 if( static_cast<D3D9DepthBuffer*>(*itor)->getDepthBufferSurface() == depthSurface ) 2945 return *itor; 2946 2947 ++itor; 2948 } 2949 2950 //Nope, get the info about this depth buffer and create a new container fot it 2951 D3DSURFACE_DESC dsDesc; 2952 if( FAILED(depthSurface->GetDesc(&dsDesc)) ) 2953 return 0; 2954 2955 D3D9DepthBuffer *newDepthBuffer = OGRE_NEW D3D9DepthBuffer( DepthBuffer::POOL_DEFAULT, this, 2956 depthSurfaceDevice, depthSurface, 2957 dsDesc.Format, dsDesc.Width, dsDesc.Height, 2958 dsDesc.MultiSampleType, dsDesc.MultiSampleQuality, true ); 2959 2960 //Add the 'main' depth buffer to the pool 2961 mDepthBufferPool[newDepthBuffer->getPoolId()].push_back( newDepthBuffer ); 2962 2963 return newDepthBuffer; 2964 } 2965 //--------------------------------------------------------------------- _cleanupDepthBuffers(IDirect3DDevice9 * creator)2966 void D3D9RenderSystem::_cleanupDepthBuffers( IDirect3DDevice9 *creator ) 2967 { 2968 assert( creator ); 2969 2970 DepthBufferMap::iterator itMap = mDepthBufferPool.begin(); 2971 DepthBufferMap::iterator enMap = mDepthBufferPool.end(); 2972 2973 while( itMap != enMap ) 2974 { 2975 DepthBufferVec::iterator itor = itMap->second.begin(); 2976 DepthBufferVec::iterator end = itMap->second.end(); 2977 2978 while( itor != end ) 2979 { 2980 //Only delete those who match the specified creator 2981 if( static_cast<D3D9DepthBuffer*>(*itor)->getDeviceCreator() == creator ) 2982 { 2983 OGRE_DELETE *itor; 2984 2985 //Erasing a vector invalidates iterators, we need to recalculate 2986 //to avoid memory corruption and asserts. The new itor will point 2987 //to the next iterator 2988 const size_t idx = itor - itMap->second.begin(); 2989 itMap->second.erase( itor ); //Erase 2990 itor = itMap->second.begin() + idx; 2991 end = itMap->second.end(); 2992 } 2993 else 2994 ++itor; 2995 } 2996 2997 //Erase the pool if it's now empty. Note erasing from a map is 2998 //valid while iterating through it 2999 if( itMap->second.empty() ) 3000 { 3001 DepthBufferMap::iterator deadi = itMap++; 3002 mDepthBufferPool.erase( deadi ); 3003 } 3004 else 3005 ++itMap; 3006 } 3007 } 3008 //--------------------------------------------------------------------- _cleanupDepthBuffers(IDirect3DSurface9 * manualSurface)3009 void D3D9RenderSystem::_cleanupDepthBuffers( IDirect3DSurface9 *manualSurface ) 3010 { 3011 assert( manualSurface ); 3012 3013 DepthBufferMap::iterator itMap = mDepthBufferPool.begin(); 3014 DepthBufferMap::iterator enMap = mDepthBufferPool.end(); 3015 3016 while( itMap != enMap ) 3017 { 3018 DepthBufferVec::iterator itor = itMap->second.begin(); 3019 DepthBufferVec::iterator end = itMap->second.end(); 3020 3021 while( itor != end ) 3022 { 3023 //Only delete those who match the specified surface 3024 if( static_cast<D3D9DepthBuffer*>(*itor)->getDepthBufferSurface() == manualSurface ) 3025 { 3026 OGRE_DELETE *itor; 3027 3028 //Erasing a vector invalidates iterators, we need to recalculate 3029 //to avoid memory corruption and asserts. The new itor will point 3030 //to the next iterator 3031 const size_t idx = itor - itMap->second.begin(); 3032 itMap->second.erase( itor ); //Erase 3033 itor = itMap->second.begin() + idx; 3034 end = itMap->second.end(); 3035 } 3036 else 3037 ++itor; 3038 } 3039 3040 //Erase the pool if it's now empty. Note erasing from a map is 3041 //valid while iterating through it 3042 if( itMap->second.empty() ) 3043 { 3044 DepthBufferMap::iterator deadi = itMap++; 3045 mDepthBufferPool.erase( deadi ); 3046 } 3047 else 3048 ++itMap; 3049 } 3050 } 3051 //--------------------------------------------------------------------- _setRenderTarget(RenderTarget * target)3052 void D3D9RenderSystem::_setRenderTarget(RenderTarget *target) 3053 { 3054 mActiveRenderTarget = target; 3055 3056 if (mActiveRenderTarget) 3057 { 3058 HRESULT hr; 3059 3060 // If this is called without going through RenderWindow::update, then 3061 // the device will not have been set. Calling it twice is safe, the 3062 // implementation ensures nothing happens if the same device is set twice 3063 if (std::find(mRenderWindows.begin(), mRenderWindows.end(), target) != mRenderWindows.end()) 3064 { 3065 D3D9RenderWindow *window = static_cast<D3D9RenderWindow*>(target); 3066 mDeviceManager->setActiveRenderTargetDevice(window->getDevice()); 3067 // also make sure we validate the device; if this never went 3068 // through update() it won't be set 3069 window->_validateDevice(); 3070 } 3071 3072 // Retrieve render surfaces (up to OGRE_MAX_MULTIPLE_RENDER_TARGETS) 3073 IDirect3DSurface9* pBack[OGRE_MAX_MULTIPLE_RENDER_TARGETS]; 3074 memset(pBack, 0, sizeof(pBack)); 3075 target->getCustomAttribute( "DDBACKBUFFER", &pBack ); 3076 if (!pBack[0]) 3077 return; 3078 3079 D3D9DepthBuffer *depthBuffer = static_cast<D3D9DepthBuffer*>(target->getDepthBuffer()); 3080 3081 if( target->getDepthBufferPool() != DepthBuffer::POOL_NO_DEPTH && 3082 (!depthBuffer || depthBuffer->getDeviceCreator() != getActiveD3D9Device() ) ) 3083 { 3084 //Depth is automatically managed and there is no depth buffer attached to this RT 3085 //or the Current D3D device doesn't match the one this Depth buffer was created 3086 setDepthBufferFor( target ); 3087 3088 //Retrieve depth buffer again 3089 depthBuffer = static_cast<D3D9DepthBuffer*>(target->getDepthBuffer()); 3090 } 3091 3092 if ((depthBuffer != NULL) && ( depthBuffer->getDeviceCreator() != getActiveD3D9Device())) 3093 { 3094 OGRE_EXCEPT( Exception::ERR_RENDERINGAPI_ERROR, 3095 "Can't use a depth buffer from a different device!", 3096 "D3D9RenderSystem::_setRenderTarget" ); 3097 } 3098 3099 IDirect3DSurface9 *depthSurface = depthBuffer ? depthBuffer->getDepthBufferSurface() : NULL; 3100 3101 // Bind render targets 3102 uint count = mCurrentCapabilities->getNumMultiRenderTargets(); 3103 for(uint x=0; x<count; ++x) 3104 { 3105 hr = getActiveD3D9Device()->SetRenderTarget(x, pBack[x]); 3106 if (FAILED(hr)) 3107 { 3108 String msg = DXGetErrorDescription(hr); 3109 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to setRenderTarget : " + msg, "D3D9RenderSystem::_setViewport" ); 3110 } 3111 } 3112 hr = getActiveD3D9Device()->SetDepthStencilSurface( depthSurface ); 3113 if (FAILED(hr)) 3114 { 3115 String msg = DXGetErrorDescription(hr); 3116 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to setDepthStencil : " + msg, "D3D9RenderSystem::_setViewport" ); 3117 } 3118 } 3119 } 3120 //--------------------------------------------------------------------- _setViewport(Viewport * vp)3121 void D3D9RenderSystem::_setViewport( Viewport *vp ) 3122 { 3123 if (!vp) 3124 { 3125 mActiveViewport = NULL; 3126 _setRenderTarget(NULL); 3127 } 3128 else if( vp != mActiveViewport || vp->_isUpdated() ) 3129 { 3130 mActiveViewport = vp; 3131 3132 // ok, it's different, time to set render target and viewport params 3133 D3DVIEWPORT9 d3dvp; 3134 HRESULT hr; 3135 3136 // Set render target 3137 RenderTarget* target = vp->getTarget(); 3138 _setRenderTarget(target); 3139 3140 //Reset the viewport after the render target has been set. If the device 3141 //had been reset the viewport would have been set to NULL. 3142 mActiveViewport = vp; 3143 3144 _setCullingMode( mCullingMode ); 3145 3146 // set viewport dimensions 3147 d3dvp.X = vp->getActualLeft(); 3148 d3dvp.Y = vp->getActualTop(); 3149 d3dvp.Width = vp->getActualWidth(); 3150 d3dvp.Height = vp->getActualHeight(); 3151 if (target->requiresTextureFlipping()) 3152 { 3153 // Convert "top-left" to "bottom-left" 3154 d3dvp.Y = target->getHeight() - d3dvp.Height - d3dvp.Y; 3155 } 3156 3157 // Z-values from 0.0 to 1.0 (TODO: standardise with OpenGL) 3158 d3dvp.MinZ = 0.0f; 3159 d3dvp.MaxZ = 1.0f; 3160 3161 if( FAILED( hr = getActiveD3D9Device()->SetViewport( &d3dvp ) ) ) 3162 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set viewport.", "D3D9RenderSystem::_setViewport" ); 3163 3164 // Set sRGB write mode 3165 __SetRenderState(D3DRS_SRGBWRITEENABLE, target->isHardwareGammaEnabled()); 3166 3167 vp->_clearUpdatedFlag(); 3168 } 3169 } 3170 //--------------------------------------------------------------------- _beginFrame()3171 void D3D9RenderSystem::_beginFrame() 3172 { 3173 HRESULT hr; 3174 3175 if( !mActiveViewport ) 3176 OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Cannot begin frame - no viewport selected.", "D3D9RenderSystem::_beginFrame" ); 3177 3178 if( FAILED( hr = getActiveD3D9Device()->BeginScene() ) ) 3179 { 3180 String msg = DXGetErrorDescription(hr); 3181 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error beginning frame :" + msg, "D3D9RenderSystem::_beginFrame" ); 3182 } 3183 3184 mLastVertexSourceCount = 0; 3185 3186 // Clear left overs of previous viewport. 3187 // I.E: Viewport A can use 3 different textures and light states 3188 // When trying to render viewport B these settings should be cleared, otherwise 3189 // graphical artifacts might occur. 3190 mDeviceManager->getActiveDevice()->clearDeviceStreams(); 3191 } 3192 //--------------------------------------------------------------------- _endFrame()3193 void D3D9RenderSystem::_endFrame() 3194 { 3195 HRESULT hr; 3196 if( FAILED( hr = getActiveD3D9Device()->EndScene() ) ) 3197 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error ending frame", "D3D9RenderSystem::_endFrame" ); 3198 3199 mDeviceManager->destroyInactiveRenderDevices(); 3200 } 3201 //--------------------------------------------------------------------- 3202 struct D3D9RenderContext : public RenderSystem::RenderSystemContext 3203 { 3204 RenderTarget* target; 3205 }; 3206 //--------------------------------------------------------------------- _pauseFrame(void)3207 RenderSystem::RenderSystemContext* D3D9RenderSystem::_pauseFrame(void) 3208 { 3209 //Stop rendering 3210 _endFrame(); 3211 3212 D3D9RenderContext* context = OGRE_ALLOC_T(D3D9RenderContext, 1, MEMCATEGORY_RENDERSYS); 3213 context->target = mActiveRenderTarget; 3214 3215 3216 return context; 3217 } 3218 //--------------------------------------------------------------------- _resumeFrame(RenderSystemContext * context)3219 void D3D9RenderSystem::_resumeFrame(RenderSystemContext* context) 3220 { 3221 //Resume rendering 3222 _beginFrame(); 3223 D3D9RenderContext* d3dContext = static_cast<D3D9RenderContext*>(context); 3224 3225 OGRE_FREE(context, MEMCATEGORY_RENDERSYS); 3226 } setVertexDeclaration(VertexDeclaration * decl)3227 void D3D9RenderSystem::setVertexDeclaration(VertexDeclaration* decl) 3228 { 3229 setVertexDeclaration(decl, true); 3230 } 3231 //--------------------------------------------------------------------- setVertexDeclaration(VertexDeclaration * decl,bool useGlobalInstancingVertexBufferIsAvailable)3232 void D3D9RenderSystem::setVertexDeclaration(VertexDeclaration* decl, bool useGlobalInstancingVertexBufferIsAvailable) 3233 { 3234 HRESULT hr; 3235 3236 D3D9VertexDeclaration* d3ddecl = 3237 static_cast<D3D9VertexDeclaration*>(decl); 3238 3239 if (FAILED(hr = getActiveD3D9Device()->SetVertexDeclaration(d3ddecl->getD3DVertexDeclaration(getGlobalInstanceVertexBufferVertexDeclaration(), useGlobalInstancingVertexBufferIsAvailable)))) 3240 { 3241 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set D3D9 vertex declaration", 3242 "D3D9RenderSystem::setVertexDeclaration"); 3243 } 3244 3245 } 3246 //--------------------------------------------------------------------- setVertexBufferBinding(VertexBufferBinding * binding)3247 void D3D9RenderSystem::setVertexBufferBinding(VertexBufferBinding* binding) 3248 { 3249 setVertexBufferBinding(binding, 1, true, false); 3250 } 3251 //--------------------------------------------------------------------- setVertexBufferBinding(VertexBufferBinding * binding,size_t numberOfInstances,bool useGlobalInstancingVertexBufferIsAvailable,bool indexesUsed)3252 void D3D9RenderSystem::setVertexBufferBinding( 3253 VertexBufferBinding* binding, size_t numberOfInstances, bool useGlobalInstancingVertexBufferIsAvailable, bool indexesUsed) 3254 { 3255 /*if (!prg) 3256 { 3257 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 3258 "Null program bound.", 3259 "D3D9RenderSystem::bindGpuProgram"); 3260 }*/ 3261 3262 HRESULT hr; 3263 3264 if (useGlobalInstancingVertexBufferIsAvailable) 3265 { 3266 numberOfInstances *= getGlobalNumberOfInstances(); 3267 } 3268 3269 HardwareVertexBufferSharedPtr globalInstanceVertexBuffer = getGlobalInstanceVertexBuffer(); 3270 VertexDeclaration* globalVertexDeclaration = getGlobalInstanceVertexBufferVertexDeclaration(); 3271 bool hasInstanceData = useGlobalInstancingVertexBufferIsAvailable && 3272 !globalInstanceVertexBuffer.isNull() && globalVertexDeclaration != NULL 3273 || binding->hasInstanceData(); 3274 3275 3276 // TODO: attempt to detect duplicates 3277 const VertexBufferBinding::VertexBufferBindingMap& binds = binding->getBindings(); 3278 VertexBufferBinding::VertexBufferBindingMap::const_iterator i, iend; 3279 size_t source = 0; 3280 iend = binds.end(); 3281 for (i = binds.begin(); i != iend; ++i, ++source) 3282 { 3283 D3D9HardwareVertexBuffer* d3d9buf = 3284 static_cast<D3D9HardwareVertexBuffer*>(i->second.get()); 3285 3286 // Unbind gap sources 3287 for ( ; source < i->first; ++source) 3288 { 3289 hr = getActiveD3D9Device()->SetStreamSource(static_cast<UINT>(source), NULL, 0, 0); 3290 if (FAILED(hr)) 3291 { 3292 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to reset unused D3D9 stream source", 3293 "D3D9RenderSystem::setVertexBufferBinding"); 3294 } 3295 } 3296 3297 hr = getActiveD3D9Device()->SetStreamSource( 3298 static_cast<UINT>(source), 3299 d3d9buf->getD3D9VertexBuffer(), 3300 0, // no stream offset, this is handled in _render instead 3301 static_cast<UINT>(d3d9buf->getVertexSize()) // stride 3302 ); 3303 3304 if (FAILED(hr)) 3305 { 3306 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set D3D9 stream source for buffer binding", 3307 "D3D9RenderSystem::setVertexBufferBinding"); 3308 } 3309 3310 // SetStreamSourceFreq 3311 if ( hasInstanceData ) 3312 { 3313 if ( d3d9buf->isInstanceData() ) 3314 { 3315 hr = getActiveD3D9Device()->SetStreamSourceFreq( static_cast<UINT>(source), D3DSTREAMSOURCE_INSTANCEDATA | d3d9buf->getInstanceDataStepRate() ); 3316 } 3317 else 3318 { 3319 if ( !indexesUsed ) 3320 { 3321 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Instance data used without index data.", 3322 "D3D9RenderSystem::setVertexBufferBinding"); 3323 } 3324 hr = getActiveD3D9Device()->SetStreamSourceFreq( static_cast<UINT>(source), D3DSTREAMSOURCE_INDEXEDDATA | numberOfInstances ); 3325 } 3326 if (FAILED(hr)) 3327 { 3328 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set D3D9 stream source Freq", 3329 "D3D9RenderSystem::setVertexBufferBinding"); 3330 } 3331 } 3332 else 3333 { 3334 hr = getActiveD3D9Device()->SetStreamSourceFreq( static_cast<UINT>(source), 1 ); 3335 if (FAILED(hr)) 3336 { 3337 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to reset unused D3D9 stream source Freq", 3338 "D3D9RenderSystem::setVertexBufferBinding"); 3339 } 3340 } 3341 3342 } 3343 3344 if (useGlobalInstancingVertexBufferIsAvailable) 3345 { 3346 // bind global instance buffer if exist 3347 if( !globalInstanceVertexBuffer.isNull() ) 3348 { 3349 if ( !indexesUsed ) 3350 { 3351 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Instance data used without index data.", 3352 "D3D9RenderSystem::setVertexBufferBinding"); 3353 } 3354 3355 D3D9HardwareVertexBuffer * d3d9buf = 3356 static_cast<D3D9HardwareVertexBuffer*>(globalInstanceVertexBuffer.get()); 3357 3358 hr = getActiveD3D9Device()->SetStreamSource( 3359 static_cast<UINT>(source), 3360 d3d9buf->getD3D9VertexBuffer(), 3361 0, // no stream offset, this is handled in _render instead 3362 static_cast<UINT>(d3d9buf->getVertexSize()) // stride 3363 ); 3364 3365 if (FAILED(hr)) 3366 { 3367 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set D3D9 stream source for buffer binding", 3368 "D3D9RenderSystem::setVertexBufferBinding"); 3369 } 3370 3371 hr = getActiveD3D9Device()->SetStreamSourceFreq( static_cast<UINT>(source), D3DSTREAMSOURCE_INSTANCEDATA | d3d9buf->getInstanceDataStepRate() ); 3372 if (FAILED(hr)) 3373 { 3374 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set D3D9 stream source Freq", 3375 "D3D9RenderSystem::setVertexBufferBinding"); 3376 } 3377 } 3378 3379 } 3380 3381 // Unbind any unused sources 3382 for (size_t unused = source; unused < mLastVertexSourceCount; ++unused) 3383 { 3384 3385 hr = getActiveD3D9Device()->SetStreamSource(static_cast<UINT>(unused), NULL, 0, 0); 3386 if (FAILED(hr)) 3387 { 3388 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to reset unused D3D9 stream source", 3389 "D3D9RenderSystem::setVertexBufferBinding"); 3390 } 3391 3392 hr = getActiveD3D9Device()->SetStreamSourceFreq( static_cast<UINT>(unused), 1 ); 3393 if (FAILED(hr)) 3394 { 3395 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to reset unused D3D9 stream source Freq", 3396 "D3D9RenderSystem::setVertexBufferBinding"); 3397 } 3398 3399 } 3400 mLastVertexSourceCount = source; 3401 3402 } 3403 //--------------------------------------------------------------------- _render(const RenderOperation & op)3404 void D3D9RenderSystem::_render(const RenderOperation& op) 3405 { 3406 // Exit immediately if there is nothing to render 3407 // This caused a problem on FireGL 8800 3408 if (op.vertexData->vertexCount == 0) 3409 return; 3410 3411 // Call super class 3412 RenderSystem::_render(op); 3413 3414 3415 if ( !mEnableFixedPipeline && !mRealCapabilities->hasCapability(RSC_FIXED_FUNCTION) 3416 && 3417 ( 3418 ( !mVertexProgramBound ) || 3419 (!mFragmentProgramBound && op.operationType != RenderOperation::OT_POINT_LIST) 3420 ) 3421 ) 3422 { 3423 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 3424 "Attempted to render using the fixed pipeline when it is disabled.", 3425 "D3D9RenderSystem::_render"); 3426 } 3427 3428 // To think about: possibly remove setVertexDeclaration and 3429 // setVertexBufferBinding from RenderSystem since the sequence is 3430 // a bit too D3D9-specific? 3431 setVertexDeclaration(op.vertexData->vertexDeclaration, op.useGlobalInstancingVertexBufferIsAvailable); 3432 setVertexBufferBinding(op.vertexData->vertexBufferBinding, op.numberOfInstances, op.useGlobalInstancingVertexBufferIsAvailable, op.useIndexes); 3433 3434 // Determine rendering operation 3435 D3DPRIMITIVETYPE primType = D3DPT_TRIANGLELIST; 3436 DWORD primCount = 0; 3437 switch( op.operationType ) 3438 { 3439 case RenderOperation::OT_POINT_LIST: 3440 primType = D3DPT_POINTLIST; 3441 primCount = static_cast<DWORD>(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount); 3442 break; 3443 3444 case RenderOperation::OT_LINE_LIST: 3445 primType = D3DPT_LINELIST; 3446 primCount = static_cast<DWORD>(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) / 2; 3447 break; 3448 3449 case RenderOperation::OT_LINE_STRIP: 3450 primType = D3DPT_LINESTRIP; 3451 primCount = static_cast<DWORD>(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) - 1; 3452 break; 3453 3454 case RenderOperation::OT_TRIANGLE_LIST: 3455 primType = D3DPT_TRIANGLELIST; 3456 primCount = static_cast<DWORD>(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) / 3; 3457 break; 3458 3459 case RenderOperation::OT_TRIANGLE_STRIP: 3460 primType = D3DPT_TRIANGLESTRIP; 3461 primCount = static_cast<DWORD>(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) - 2; 3462 break; 3463 3464 case RenderOperation::OT_TRIANGLE_FAN: 3465 primType = D3DPT_TRIANGLEFAN; 3466 primCount = static_cast<DWORD>(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) - 2; 3467 break; 3468 } 3469 3470 if (!primCount) 3471 return; 3472 3473 // Issue the op 3474 HRESULT hr; 3475 if( op.useIndexes ) 3476 { 3477 D3D9HardwareIndexBuffer* d3dIdxBuf = 3478 static_cast<D3D9HardwareIndexBuffer*>(op.indexData->indexBuffer.get()); 3479 hr = getActiveD3D9Device()->SetIndices( d3dIdxBuf->getD3DIndexBuffer() ); 3480 if (FAILED(hr)) 3481 { 3482 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set index buffer", "D3D9RenderSystem::_render" ); 3483 } 3484 3485 do 3486 { 3487 // Update derived depth bias 3488 if (mDerivedDepthBias && mCurrentPassIterationNum > 0) 3489 { 3490 _setDepthBias(mDerivedDepthBiasBase + 3491 mDerivedDepthBiasMultiplier * mCurrentPassIterationNum, 3492 mDerivedDepthBiasSlopeScale); 3493 } 3494 // do indexed draw operation 3495 hr = getActiveD3D9Device()->DrawIndexedPrimitive( 3496 primType, 3497 static_cast<INT>(op.vertexData->vertexStart), 3498 0, // Min vertex index - assume we can go right down to 0 3499 static_cast<UINT>(op.vertexData->vertexCount), 3500 static_cast<UINT>(op.indexData->indexStart), 3501 static_cast<UINT>(primCount) 3502 ); 3503 3504 } while (updatePassIterationRenderState()); 3505 } 3506 else 3507 { 3508 // nfz: gpu_iterate 3509 do 3510 { 3511 // Update derived depth bias 3512 if (mDerivedDepthBias && mCurrentPassIterationNum > 0) 3513 { 3514 _setDepthBias(mDerivedDepthBiasBase + 3515 mDerivedDepthBiasMultiplier * mCurrentPassIterationNum, 3516 mDerivedDepthBiasSlopeScale); 3517 } 3518 // Unindexed, a little simpler! 3519 hr = getActiveD3D9Device()->DrawPrimitive( 3520 primType, 3521 static_cast<UINT>(op.vertexData->vertexStart), 3522 static_cast<UINT>(primCount) 3523 ); 3524 3525 } while (updatePassIterationRenderState()); 3526 } 3527 3528 if( FAILED( hr ) ) 3529 { 3530 String msg = DXGetErrorDescription(hr); 3531 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to DrawPrimitive : " + msg, "D3D9RenderSystem::_render" ); 3532 } 3533 3534 } 3535 //--------------------------------------------------------------------- setNormaliseNormals(bool normalise)3536 void D3D9RenderSystem::setNormaliseNormals(bool normalise) 3537 { 3538 __SetRenderState(D3DRS_NORMALIZENORMALS, 3539 normalise ? TRUE : FALSE); 3540 } 3541 //--------------------------------------------------------------------- bindGpuProgram(GpuProgram * prg)3542 void D3D9RenderSystem::bindGpuProgram(GpuProgram* prg) 3543 { 3544 if (!prg) 3545 { 3546 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 3547 "Null program bound.", 3548 "D3D9RenderSystem::bindGpuProgram"); 3549 } 3550 3551 HRESULT hr; 3552 switch (prg->getType()) 3553 { 3554 case GPT_VERTEX_PROGRAM: 3555 hr = getActiveD3D9Device()->SetVertexShader( 3556 static_cast<D3D9GpuVertexProgram*>(prg)->getVertexShader()); 3557 if (FAILED(hr)) 3558 { 3559 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error calling SetVertexShader", "D3D9RenderSystem::bindGpuProgram"); 3560 } 3561 break; 3562 case GPT_FRAGMENT_PROGRAM: 3563 hr = getActiveD3D9Device()->SetPixelShader( 3564 static_cast<D3D9GpuFragmentProgram*>(prg)->getPixelShader()); 3565 if (FAILED(hr)) 3566 { 3567 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error calling SetPixelShader", "D3D9RenderSystem::bindGpuProgram"); 3568 } 3569 break; 3570 }; 3571 3572 // Make sure texcoord index is equal to stage value, As SDK Doc suggests: 3573 // "When rendering using vertex shaders, each stage's texture coordinate index must be set to its default value." 3574 // This solves such an errors when working with the Debug runtime - 3575 // "Direct3D9: (ERROR) :Stage 1 - Texture coordinate index in the stage must be equal to the stage index when programmable vertex pipeline is used". 3576 for (unsigned int nStage=0; nStage < 8; ++nStage) 3577 __SetTextureStageState(nStage, D3DTSS_TEXCOORDINDEX, nStage); 3578 3579 RenderSystem::bindGpuProgram(prg); 3580 3581 } 3582 //--------------------------------------------------------------------- unbindGpuProgram(GpuProgramType gptype)3583 void D3D9RenderSystem::unbindGpuProgram(GpuProgramType gptype) 3584 { 3585 /*if (!prg) 3586 { 3587 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 3588 "Null program bound.", 3589 "D3D9RenderSystem::bindGpuProgram"); 3590 }*/ 3591 3592 HRESULT hr; 3593 switch(gptype) 3594 { 3595 case GPT_VERTEX_PROGRAM: 3596 mActiveVertexGpuProgramParameters.setNull(); 3597 hr = getActiveD3D9Device()->SetVertexShader(NULL); 3598 if (FAILED(hr)) 3599 { 3600 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error resetting SetVertexShader to NULL", 3601 "D3D9RenderSystem::unbindGpuProgram"); 3602 } 3603 break; 3604 case GPT_FRAGMENT_PROGRAM: 3605 mActiveFragmentGpuProgramParameters.setNull(); 3606 hr = getActiveD3D9Device()->SetPixelShader(NULL); 3607 if (FAILED(hr)) 3608 { 3609 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error resetting SetPixelShader to NULL", 3610 "D3D9RenderSystem::unbindGpuProgram"); 3611 } 3612 break; 3613 }; 3614 RenderSystem::unbindGpuProgram(gptype); 3615 } 3616 //--------------------------------------------------------------------- bindGpuProgramParameters(GpuProgramType gptype,GpuProgramParametersSharedPtr params,uint16 variability)3617 void D3D9RenderSystem::bindGpuProgramParameters(GpuProgramType gptype, 3618 GpuProgramParametersSharedPtr params, uint16 variability) 3619 { 3620 // special case pass iteration 3621 if (variability == (uint16)GPV_PASS_ITERATION_NUMBER) 3622 { 3623 bindGpuProgramPassIterationParameters(gptype); 3624 return; 3625 } 3626 3627 if (variability & (uint16)GPV_GLOBAL) 3628 { 3629 // D3D9 doesn't support shared constant buffers, so use copy routine 3630 params->_copySharedParams(); 3631 } 3632 3633 HRESULT hr; 3634 GpuLogicalBufferStructPtr floatLogical = params->getFloatLogicalBufferStruct(); 3635 GpuLogicalBufferStructPtr intLogical = params->getIntLogicalBufferStruct(); 3636 3637 switch(gptype) 3638 { 3639 case GPT_VERTEX_PROGRAM: 3640 mActiveVertexGpuProgramParameters = params; 3641 { 3642 OGRE_LOCK_MUTEX(floatLogical->mutex); 3643 3644 for (GpuLogicalIndexUseMap::const_iterator i = floatLogical->map.begin(); 3645 i != floatLogical->map.end(); ++i) 3646 { 3647 if (i->second.variability & variability) 3648 { 3649 size_t logicalIndex = i->first; 3650 const float* pFloat = params->getFloatPointer(i->second.physicalIndex); 3651 size_t slotCount = i->second.currentSize / 4; 3652 assert (i->second.currentSize % 4 == 0 && "Should not have any " 3653 "elements less than 4 wide for D3D9"); 3654 3655 if (FAILED(hr = getActiveD3D9Device()->SetVertexShaderConstantF( 3656 (UINT)logicalIndex, pFloat, (UINT)slotCount))) 3657 { 3658 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 3659 "Unable to upload vertex shader float parameters", 3660 "D3D9RenderSystem::bindGpuProgramParameters"); 3661 } 3662 } 3663 3664 } 3665 3666 } 3667 // bind ints 3668 { 3669 OGRE_LOCK_MUTEX(intLogical->mutex); 3670 3671 for (GpuLogicalIndexUseMap::const_iterator i = intLogical->map.begin(); 3672 i != intLogical->map.end(); ++i) 3673 { 3674 if (i->second.variability & variability) 3675 { 3676 size_t logicalIndex = i->first; 3677 const int* pInt = params->getIntPointer(i->second.physicalIndex); 3678 size_t slotCount = i->second.currentSize / 4; 3679 assert (i->second.currentSize % 4 == 0 && "Should not have any " 3680 "elements less than 4 wide for D3D9"); 3681 3682 if (FAILED(hr = getActiveD3D9Device()->SetVertexShaderConstantI( 3683 static_cast<UINT>(logicalIndex), pInt, static_cast<UINT>(slotCount)))) 3684 { 3685 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 3686 "Unable to upload vertex shader int parameters", 3687 "D3D9RenderSystem::bindGpuProgramParameters"); 3688 } 3689 } 3690 } 3691 3692 } 3693 3694 break; 3695 case GPT_FRAGMENT_PROGRAM: 3696 mActiveFragmentGpuProgramParameters = params; 3697 { 3698 OGRE_LOCK_MUTEX(floatLogical->mutex); 3699 3700 for (GpuLogicalIndexUseMap::const_iterator i = floatLogical->map.begin(); 3701 i != floatLogical->map.end(); ++i) 3702 { 3703 if (i->second.variability & variability) 3704 { 3705 size_t logicalIndex = i->first; 3706 const float* pFloat = params->getFloatPointer(i->second.physicalIndex); 3707 size_t slotCount = i->second.currentSize / 4; 3708 assert (i->second.currentSize % 4 == 0 && "Should not have any " 3709 "elements less than 4 wide for D3D9"); 3710 3711 if (FAILED(hr = getActiveD3D9Device()->SetPixelShaderConstantF( 3712 static_cast<UINT>(logicalIndex), pFloat, static_cast<UINT>(slotCount)))) 3713 { 3714 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 3715 "Unable to upload pixel shader float parameters", 3716 "D3D9RenderSystem::bindGpuProgramParameters"); 3717 } 3718 } 3719 } 3720 3721 } 3722 // bind ints 3723 { 3724 OGRE_LOCK_MUTEX(intLogical->mutex); 3725 3726 for (GpuLogicalIndexUseMap::const_iterator i = intLogical->map.begin(); 3727 i != intLogical->map.end(); ++i) 3728 { 3729 if (i->second.variability & variability) 3730 { 3731 size_t logicalIndex = i->first; 3732 const int* pInt = params->getIntPointer(i->second.physicalIndex); 3733 size_t slotCount = i->second.currentSize / 4; 3734 assert (i->second.currentSize % 4 == 0 && "Should not have any " 3735 "elements less than 4 wide for D3D9"); 3736 3737 if (FAILED(hr = getActiveD3D9Device()->SetPixelShaderConstantI( 3738 static_cast<UINT>(logicalIndex), pInt, static_cast<UINT>(slotCount)))) 3739 { 3740 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 3741 "Unable to upload pixel shader int parameters", 3742 "D3D9RenderSystem::bindGpuProgramParameters"); 3743 } 3744 } 3745 3746 } 3747 3748 } 3749 break; 3750 }; 3751 } 3752 //--------------------------------------------------------------------- bindGpuProgramPassIterationParameters(GpuProgramType gptype)3753 void D3D9RenderSystem::bindGpuProgramPassIterationParameters(GpuProgramType gptype) 3754 { 3755 3756 HRESULT hr; 3757 size_t physicalIndex = 0; 3758 size_t logicalIndex = 0; 3759 const float* pFloat; 3760 3761 switch(gptype) 3762 { 3763 case GPT_VERTEX_PROGRAM: 3764 if (mActiveVertexGpuProgramParameters->hasPassIterationNumber()) 3765 { 3766 physicalIndex = mActiveVertexGpuProgramParameters->getPassIterationNumberIndex(); 3767 logicalIndex = mActiveVertexGpuProgramParameters->getFloatLogicalIndexForPhysicalIndex(physicalIndex); 3768 pFloat = mActiveVertexGpuProgramParameters->getFloatPointer(physicalIndex); 3769 3770 if (FAILED(hr = getActiveD3D9Device()->SetVertexShaderConstantF( 3771 static_cast<UINT>(logicalIndex), pFloat, 1))) 3772 { 3773 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 3774 "Unable to upload vertex shader multi pass parameters", 3775 "D3D9RenderSystem::bindGpuProgramMultiPassParameters"); 3776 } 3777 } 3778 break; 3779 3780 case GPT_FRAGMENT_PROGRAM: 3781 if (mActiveFragmentGpuProgramParameters->hasPassIterationNumber()) 3782 { 3783 physicalIndex = mActiveFragmentGpuProgramParameters->getPassIterationNumberIndex(); 3784 logicalIndex = mActiveFragmentGpuProgramParameters->getFloatLogicalIndexForPhysicalIndex(physicalIndex); 3785 pFloat = mActiveFragmentGpuProgramParameters->getFloatPointer(physicalIndex); 3786 if (FAILED(hr = getActiveD3D9Device()->SetPixelShaderConstantF( 3787 static_cast<UINT>(logicalIndex), pFloat, 1))) 3788 { 3789 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 3790 "Unable to upload pixel shader multi pass parameters", 3791 "D3D9RenderSystem::bindGpuProgramMultiPassParameters"); 3792 } 3793 } 3794 break; 3795 3796 } 3797 } 3798 //--------------------------------------------------------------------- setClipPlanesImpl(const PlaneList & clipPlanes)3799 void D3D9RenderSystem::setClipPlanesImpl(const PlaneList& clipPlanes) 3800 { 3801 size_t i; 3802 size_t numClipPlanes; 3803 D3DXPLANE dx9ClipPlane; 3804 DWORD mask = 0; 3805 HRESULT hr; 3806 3807 numClipPlanes = clipPlanes.size(); 3808 for (i = 0; i < numClipPlanes; ++i) 3809 { 3810 const Plane& plane = clipPlanes[i]; 3811 3812 dx9ClipPlane.a = plane.normal.x; 3813 dx9ClipPlane.b = plane.normal.y; 3814 dx9ClipPlane.c = plane.normal.z; 3815 dx9ClipPlane.d = plane.d; 3816 3817 if (mVertexProgramBound) 3818 { 3819 // programmable clips in clip space (ugh) 3820 // must transform worldspace planes by view/proj 3821 D3DXMATRIX xform; 3822 D3DXMatrixMultiply(&xform, &mDxViewMat, &mDxProjMat); 3823 D3DXMatrixInverse(&xform, NULL, &xform); 3824 D3DXMatrixTranspose(&xform, &xform); 3825 D3DXPlaneTransform(&dx9ClipPlane, &dx9ClipPlane, &xform); 3826 } 3827 3828 hr = getActiveD3D9Device()->SetClipPlane(static_cast<DWORD>(i), dx9ClipPlane); 3829 if (FAILED(hr)) 3830 { 3831 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set clip plane", 3832 "D3D9RenderSystem::setClipPlanes"); 3833 } 3834 3835 mask |= (1 << i); 3836 } 3837 3838 hr = __SetRenderState(D3DRS_CLIPPLANEENABLE, mask); 3839 if (FAILED(hr)) 3840 { 3841 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set render state for clip planes", 3842 "D3D9RenderSystem::setClipPlanes"); 3843 } 3844 } 3845 //--------------------------------------------------------------------- setScissorTest(bool enabled,size_t left,size_t top,size_t right,size_t bottom)3846 void D3D9RenderSystem::setScissorTest(bool enabled, size_t left, size_t top, size_t right, 3847 size_t bottom) 3848 { 3849 HRESULT hr; 3850 if (enabled) 3851 { 3852 if (FAILED(hr = __SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE))) 3853 { 3854 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to enable scissor rendering state; " + getErrorDescription(hr), 3855 "D3D9RenderSystem::setScissorTest"); 3856 } 3857 RECT rect; 3858 rect.left = static_cast<LONG>(left); 3859 rect.top = static_cast<LONG>(top); 3860 rect.bottom = static_cast<LONG>(bottom); 3861 rect.right = static_cast<LONG>(right); 3862 if (FAILED(hr = getActiveD3D9Device()->SetScissorRect(&rect))) 3863 { 3864 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set scissor rectangle; " + getErrorDescription(hr), 3865 "D3D9RenderSystem::setScissorTest"); 3866 } 3867 } 3868 else 3869 { 3870 if (FAILED(hr = __SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE))) 3871 { 3872 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to disable scissor rendering state; " + getErrorDescription(hr), 3873 "D3D9RenderSystem::setScissorTest"); 3874 } 3875 } 3876 } 3877 //--------------------------------------------------------------------- clearFrameBuffer(unsigned int buffers,const ColourValue & colour,Real depth,unsigned short stencil)3878 void D3D9RenderSystem::clearFrameBuffer(unsigned int buffers, 3879 const ColourValue& colour, Real depth, unsigned short stencil) 3880 { 3881 DWORD flags = 0; 3882 if (buffers & FBT_COLOUR) 3883 { 3884 flags |= D3DCLEAR_TARGET; 3885 } 3886 if (buffers & FBT_DEPTH) 3887 { 3888 flags |= D3DCLEAR_ZBUFFER; 3889 } 3890 // Only try to clear the stencil buffer if supported 3891 if (buffers & FBT_STENCIL && mCurrentCapabilities->hasCapability(RSC_HWSTENCIL)) 3892 { 3893 flags |= D3DCLEAR_STENCIL; 3894 } 3895 HRESULT hr; 3896 if( FAILED( hr = getActiveD3D9Device()->Clear( 3897 0, 3898 NULL, 3899 flags, 3900 colour.getAsARGB(), 3901 depth, 3902 stencil ) ) ) 3903 { 3904 String msg = DXGetErrorDescription(hr); 3905 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error clearing frame buffer : " 3906 + msg, "D3D9RenderSystem::clearFrameBuffer" ); 3907 } 3908 } 3909 //--------------------------------------------------------------------- _makeProjectionMatrix(Real left,Real right,Real bottom,Real top,Real nearPlane,Real farPlane,Matrix4 & dest,bool forGpuProgram)3910 void D3D9RenderSystem::_makeProjectionMatrix(Real left, Real right, 3911 Real bottom, Real top, Real nearPlane, Real farPlane, Matrix4& dest, 3912 bool forGpuProgram) 3913 { 3914 // Correct position for off-axis projection matrix 3915 if (!forGpuProgram) 3916 { 3917 Real offsetX = left + right; 3918 Real offsetY = top + bottom; 3919 3920 left -= offsetX; 3921 right -= offsetX; 3922 top -= offsetY; 3923 bottom -= offsetY; 3924 } 3925 3926 Real width = right - left; 3927 Real height = top - bottom; 3928 Real q, qn; 3929 if (farPlane == 0) 3930 { 3931 q = 1 - Frustum::INFINITE_FAR_PLANE_ADJUST; 3932 qn = nearPlane * (Frustum::INFINITE_FAR_PLANE_ADJUST - 1); 3933 } 3934 else 3935 { 3936 q = farPlane / ( farPlane - nearPlane ); 3937 qn = -q * nearPlane; 3938 } 3939 dest = Matrix4::ZERO; 3940 dest[0][0] = 2 * nearPlane / width; 3941 dest[0][2] = (right+left) / width; 3942 dest[1][1] = 2 * nearPlane / height; 3943 dest[1][2] = (top+bottom) / height; 3944 if (forGpuProgram) 3945 { 3946 dest[2][2] = -q; 3947 dest[3][2] = -1.0f; 3948 } 3949 else 3950 { 3951 dest[2][2] = q; 3952 dest[3][2] = 1.0f; 3953 } 3954 dest[2][3] = qn; 3955 } 3956 3957 // ------------------------------------------------------------------ setClipPlane(ushort index,Real A,Real B,Real C,Real D)3958 void D3D9RenderSystem::setClipPlane (ushort index, Real A, Real B, Real C, Real D) 3959 { 3960 float plane[4] = { A, B, C, D }; 3961 getActiveD3D9Device()->SetClipPlane (index, plane); 3962 } 3963 3964 // ------------------------------------------------------------------ enableClipPlane(ushort index,bool enable)3965 void D3D9RenderSystem::enableClipPlane (ushort index, bool enable) 3966 { 3967 DWORD prev; 3968 getActiveD3D9Device()->GetRenderState(D3DRS_CLIPPLANEENABLE, &prev); 3969 __SetRenderState(D3DRS_CLIPPLANEENABLE, enable? 3970 (prev | (1 << index)) : (prev & ~(1 << index))); 3971 } 3972 //--------------------------------------------------------------------- createHardwareOcclusionQuery()3973 HardwareOcclusionQuery* D3D9RenderSystem::createHardwareOcclusionQuery() 3974 { 3975 D3D9HardwareOcclusionQuery* ret = OGRE_NEW D3D9HardwareOcclusionQuery(); 3976 mHwOcclusionQueries.push_back(ret); 3977 return ret; 3978 } 3979 //--------------------------------------------------------------------- getHorizontalTexelOffset()3980 Real D3D9RenderSystem::getHorizontalTexelOffset() 3981 { 3982 // D3D considers the origin to be in the center of a pixel 3983 return -0.5f; 3984 } 3985 //--------------------------------------------------------------------- getVerticalTexelOffset()3986 Real D3D9RenderSystem::getVerticalTexelOffset() 3987 { 3988 // D3D considers the origin to be in the center of a pixel 3989 return -0.5f; 3990 } 3991 //--------------------------------------------------------------------- _applyObliqueDepthProjection(Matrix4 & matrix,const Plane & plane,bool forGpuProgram)3992 void D3D9RenderSystem::_applyObliqueDepthProjection(Matrix4& matrix, const Plane& plane, 3993 bool forGpuProgram) 3994 { 3995 // Thanks to Eric Lenyel for posting this calculation at www.terathon.com 3996 3997 // Calculate the clip-space corner point opposite the clipping plane 3998 // as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and 3999 // transform it into camera space by multiplying it 4000 // by the inverse of the projection matrix 4001 4002 /* generalised version 4003 Vector4 q = matrix.inverse() * 4004 Vector4(Math::Sign(plane.normal.x), Math::Sign(plane.normal.y), 1.0f, 1.0f); 4005 */ 4006 Vector4 q; 4007 q.x = Math::Sign(plane.normal.x) / matrix[0][0]; 4008 q.y = Math::Sign(plane.normal.y) / matrix[1][1]; 4009 q.z = 1.0F; 4010 // flip the next bit from Lengyel since we're right-handed 4011 if (forGpuProgram) 4012 { 4013 q.w = (1.0F - matrix[2][2]) / matrix[2][3]; 4014 } 4015 else 4016 { 4017 q.w = (1.0F + matrix[2][2]) / matrix[2][3]; 4018 } 4019 4020 // Calculate the scaled plane vector 4021 Vector4 clipPlane4d(plane.normal.x, plane.normal.y, plane.normal.z, plane.d); 4022 Vector4 c = clipPlane4d * (1.0F / (clipPlane4d.dotProduct(q))); 4023 4024 // Replace the third row of the projection matrix 4025 matrix[2][0] = c.x; 4026 matrix[2][1] = c.y; 4027 // flip the next bit from Lengyel since we're right-handed 4028 if (forGpuProgram) 4029 { 4030 matrix[2][2] = c.z; 4031 } 4032 else 4033 { 4034 matrix[2][2] = -c.z; 4035 } 4036 matrix[2][3] = c.w; 4037 } 4038 //--------------------------------------------------------------------- getMinimumDepthInputValue()4039 Real D3D9RenderSystem::getMinimumDepthInputValue() 4040 { 4041 // Range [0.0f, 1.0f] 4042 return 0.0f; 4043 } 4044 //--------------------------------------------------------------------- getMaximumDepthInputValue()4045 Real D3D9RenderSystem::getMaximumDepthInputValue() 4046 { 4047 // Range [0.0f, 1.0f] 4048 // D3D inverts even identity view matrices, so maximum INPUT is -1.0 4049 return -1.0f; 4050 } 4051 //--------------------------------------------------------------------- getDirect3D9()4052 IDirect3D9* D3D9RenderSystem::getDirect3D9() 4053 { 4054 IDirect3D9* pDirect3D9 = msD3D9RenderSystem->mD3D; 4055 4056 if (pDirect3D9 == NULL) 4057 { 4058 OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS, 4059 "Direct3D9 interface is NULL !!!", 4060 "D3D9RenderSystem::getDirect3D9" ); 4061 } 4062 4063 return pDirect3D9; 4064 } 4065 4066 //--------------------------------------------------------------------- getResourceCreationDeviceCount()4067 UINT D3D9RenderSystem::getResourceCreationDeviceCount() 4068 { 4069 D3D9ResourceCreationPolicy creationPolicy = msD3D9RenderSystem->mResourceManager->getCreationPolicy(); 4070 4071 if (creationPolicy == RCP_CREATE_ON_ACTIVE_DEVICE) 4072 { 4073 return 1; 4074 } 4075 else if (creationPolicy == RCP_CREATE_ON_ALL_DEVICES) 4076 { 4077 return msD3D9RenderSystem->mDeviceManager->getDeviceCount(); 4078 } 4079 4080 OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS, 4081 "Invalid resource creation policy !!!", 4082 "D3D9RenderSystem::getResourceCreationDeviceCount" ); 4083 4084 return 0; 4085 } 4086 4087 //--------------------------------------------------------------------- getResourceCreationDevice(UINT index)4088 IDirect3DDevice9* D3D9RenderSystem::getResourceCreationDevice(UINT index) 4089 { 4090 D3D9ResourceCreationPolicy creationPolicy = msD3D9RenderSystem->mResourceManager->getCreationPolicy(); 4091 IDirect3DDevice9* d3d9Device = NULL; 4092 4093 if (creationPolicy == RCP_CREATE_ON_ACTIVE_DEVICE) 4094 { 4095 d3d9Device = msD3D9RenderSystem->getActiveD3D9Device(); 4096 } 4097 else if (creationPolicy == RCP_CREATE_ON_ALL_DEVICES) 4098 { 4099 d3d9Device = msD3D9RenderSystem->mDeviceManager->getDevice(index)->getD3D9Device(); 4100 } 4101 else 4102 { 4103 OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS, 4104 "Invalid resource creation policy !!!", 4105 "D3D9RenderSystem::getResourceCreationDevice" ); 4106 } 4107 4108 return d3d9Device; 4109 } 4110 4111 //--------------------------------------------------------------------- getActiveD3D9Device()4112 IDirect3DDevice9* D3D9RenderSystem::getActiveD3D9Device() 4113 { 4114 D3D9Device* activeDevice = msD3D9RenderSystem->mDeviceManager->getActiveDevice(); 4115 IDirect3DDevice9* d3d9Device; 4116 4117 d3d9Device = activeDevice->getD3D9Device(); 4118 4119 if (d3d9Device == NULL) 4120 { 4121 OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS, 4122 "Current d3d9 device is NULL !!!", 4123 "D3D9RenderSystem::getActiveD3D9Device" ); 4124 } 4125 4126 return d3d9Device; 4127 } 4128 4129 //--------------------------------------------------------------------- 4130 // Formats to try, in decreasing order of preference 4131 D3DFORMAT ddDepthStencilFormats[]={ 4132 D3DFMT_D24FS8, 4133 D3DFMT_D24S8, 4134 D3DFMT_D24X4S4, 4135 D3DFMT_D24X8, 4136 D3DFMT_D15S1, 4137 D3DFMT_D16, 4138 D3DFMT_D32 4139 }; 4140 #define NDSFORMATS (sizeof(ddDepthStencilFormats)/sizeof(D3DFORMAT)) 4141 _getDepthStencilFormatFor(D3DFORMAT fmt)4142 D3DFORMAT D3D9RenderSystem::_getDepthStencilFormatFor(D3DFORMAT fmt) 4143 { 4144 /// Check if result is cached 4145 DepthStencilHash::iterator i = mDepthStencilHash.find((unsigned int)fmt); 4146 if(i != mDepthStencilHash.end()) 4147 return i->second; 4148 /// If not, probe with CheckDepthStencilMatch 4149 D3DFORMAT dsfmt = D3DFMT_UNKNOWN; 4150 4151 /// Get description of primary render target 4152 D3D9Device* activeDevice = mDeviceManager->getActiveDevice(); 4153 IDirect3DSurface9* mSurface = activeDevice->getPrimaryWindow()->getRenderSurface(); 4154 D3DSURFACE_DESC srfDesc; 4155 4156 if(mSurface && SUCCEEDED(mSurface->GetDesc(&srfDesc))) 4157 { 4158 /// Probe all depth stencil formats 4159 /// Break on first one that matches 4160 for(size_t x=0; x<NDSFORMATS; ++x) 4161 { 4162 // Verify that the depth format exists 4163 if (mD3D->CheckDeviceFormat( 4164 activeDevice->getAdapterNumber(), 4165 activeDevice->getDeviceType(), 4166 srfDesc.Format, 4167 D3DUSAGE_DEPTHSTENCIL, 4168 D3DRTYPE_SURFACE, 4169 ddDepthStencilFormats[x]) != D3D_OK) 4170 { 4171 continue; 4172 } 4173 // Verify that the depth format is compatible 4174 if(mD3D->CheckDepthStencilMatch( 4175 activeDevice->getAdapterNumber(), 4176 activeDevice->getDeviceType(), 4177 srfDesc.Format, 4178 fmt, ddDepthStencilFormats[x]) == D3D_OK) 4179 { 4180 dsfmt = ddDepthStencilFormats[x]; 4181 break; 4182 } 4183 } 4184 } 4185 /// Cache result 4186 mDepthStencilHash[(unsigned int)fmt] = dsfmt; 4187 return dsfmt; 4188 } 4189 //--------------------------------------------------------------------- registerThread()4190 void D3D9RenderSystem::registerThread() 4191 { 4192 // nothing to do - D3D9 shares rendering context already 4193 } 4194 //--------------------------------------------------------------------- unregisterThread()4195 void D3D9RenderSystem::unregisterThread() 4196 { 4197 // nothing to do - D3D9 shares rendering context already 4198 } 4199 //--------------------------------------------------------------------- preExtraThreadsStarted()4200 void D3D9RenderSystem::preExtraThreadsStarted() 4201 { 4202 // nothing to do - D3D9 shares rendering context already 4203 } 4204 //--------------------------------------------------------------------- postExtraThreadsStarted()4205 void D3D9RenderSystem::postExtraThreadsStarted() 4206 { 4207 // nothing to do - D3D9 shares rendering context already 4208 } 4209 //--------------------------------------------------------------------- getResourceManager()4210 D3D9ResourceManager* D3D9RenderSystem::getResourceManager() 4211 { 4212 return msD3D9RenderSystem->mResourceManager; 4213 } 4214 4215 //--------------------------------------------------------------------- getDeviceManager()4216 D3D9DeviceManager* D3D9RenderSystem::getDeviceManager() 4217 { 4218 return msD3D9RenderSystem->mDeviceManager; 4219 } 4220 4221 //--------------------------------------------------------------------- createRenderSystemCapabilities() const4222 RenderSystemCapabilities* D3D9RenderSystem::createRenderSystemCapabilities() const 4223 { 4224 return mRealCapabilities; 4225 } 4226 4227 //--------------------------------------------------------------------- getDisplayMonitorCount() const4228 unsigned int D3D9RenderSystem::getDisplayMonitorCount() const 4229 { 4230 return mD3D->GetAdapterCount(); 4231 } 4232 4233 //--------------------------------------------------------------------- beginProfileEvent(const String & eventName)4234 void D3D9RenderSystem::beginProfileEvent( const String &eventName ) 4235 { 4236 if( eventName.empty() ) 4237 return; 4238 4239 vector<wchar_t>::type result(eventName.length() + 1, '\0'); 4240 (void)MultiByteToWideChar(CP_ACP, 0, eventName.data(), eventName.length(), &result[0], result.size()); 4241 (void)D3DPERF_BeginEvent(D3DCOLOR_ARGB(1, 0, 1, 0), &result[0]); 4242 } 4243 4244 //--------------------------------------------------------------------- endProfileEvent(void)4245 void D3D9RenderSystem::endProfileEvent( void ) 4246 { 4247 (void)D3DPERF_EndEvent(); 4248 } 4249 4250 //--------------------------------------------------------------------- markProfileEvent(const String & eventName)4251 void D3D9RenderSystem::markProfileEvent( const String &eventName ) 4252 { 4253 if( eventName.empty() ) 4254 return; 4255 4256 vector<wchar_t>::type result(eventName.length() + 1, '\0'); 4257 (void)MultiByteToWideChar(CP_ACP, 0, eventName.data(), eventName.length(), &result[0], result.size()); 4258 (void)D3DPERF_SetMarker(D3DCOLOR_ARGB(1, 0, 1, 0), &result[0]); 4259 } 4260 4261 //--------------------------------------------------------------------- getSamplerId(size_t unit)4262 DWORD D3D9RenderSystem::getSamplerId(size_t unit) 4263 { 4264 return static_cast<DWORD>(unit) + 4265 ((mTexStageDesc[unit].pVertexTex == NULL) ? 0 : D3DVERTEXTEXTURESAMPLER0); 4266 } 4267 4268 //--------------------------------------------------------------------- notifyOnDeviceLost(D3D9Device * device)4269 void D3D9RenderSystem::notifyOnDeviceLost(D3D9Device* device) 4270 { 4271 StringStream ss; 4272 4273 ss << "D3D9 Device 0x[" << device->getD3D9Device() << "] entered lost state"; 4274 LogManager::getSingleton().logMessage(ss.str()); 4275 4276 fireDeviceEvent(device, "DeviceLost"); 4277 4278 } 4279 4280 //--------------------------------------------------------------------- notifyOnDeviceReset(D3D9Device * device)4281 void D3D9RenderSystem::notifyOnDeviceReset(D3D9Device* device) 4282 { 4283 // Reset state attributes. 4284 mVertexProgramBound = false; 4285 mFragmentProgramBound = false; 4286 mLastVertexSourceCount = 0; 4287 4288 4289 // Force all compositors to reconstruct their internal resources 4290 // render textures will have been changed without their knowledge 4291 CompositorManager::getSingleton()._reconstructAllCompositorResources(); 4292 4293 // Restore previous active device. 4294 4295 // Invalidate active view port. 4296 mActiveViewport = NULL; 4297 4298 StringStream ss; 4299 4300 // Reset the texture stages, they will need to be rebound 4301 for (size_t i = 0; i < OGRE_MAX_TEXTURE_LAYERS; ++i) 4302 _setTexture(i, false, TexturePtr()); 4303 4304 LogManager::getSingleton().logMessage("!!! Direct3D Device successfully restored."); 4305 4306 ss << "D3D9 device: 0x[" << device->getD3D9Device() << "] was reset"; 4307 LogManager::getSingleton().logMessage(ss.str()); 4308 4309 fireDeviceEvent(device, "DeviceRestored"); 4310 4311 } 4312 4313 //--------------------------------------------------------------------- determineFSAASettings(IDirect3DDevice9 * d3d9Device,size_t fsaa,const String & fsaaHint,D3DFORMAT d3dPixelFormat,bool fullScreen,D3DMULTISAMPLE_TYPE * outMultisampleType,DWORD * outMultisampleQuality)4314 void D3D9RenderSystem::determineFSAASettings(IDirect3DDevice9* d3d9Device, 4315 size_t fsaa, const String& fsaaHint, D3DFORMAT d3dPixelFormat, 4316 bool fullScreen, D3DMULTISAMPLE_TYPE *outMultisampleType, DWORD *outMultisampleQuality) 4317 { 4318 bool ok = false; 4319 bool qualityHint = fsaaHint.find("Quality") != String::npos; 4320 size_t origFSAA = fsaa; 4321 4322 D3D9DriverList* driverList = getDirect3DDrivers(); 4323 D3D9Driver* deviceDriver = mActiveD3DDriver; 4324 D3D9Device* device = mDeviceManager->getDeviceFromD3D9Device(d3d9Device); 4325 4326 for (uint i = 0; i < driverList->count(); ++i) 4327 { 4328 D3D9Driver* currDriver = driverList->item(i); 4329 4330 if (currDriver->getAdapterNumber() == device->getAdapterNumber()) 4331 { 4332 deviceDriver = currDriver; 4333 break; 4334 } 4335 } 4336 4337 bool tryCSAA = false; 4338 // NVIDIA, prefer CSAA if available for 8+ 4339 // it would be tempting to use getCapabilities()->getVendor() == GPU_NVIDIA but 4340 // if this is the first window, caps will not be initialised yet 4341 if (deviceDriver->getAdapterIdentifier().VendorId == 0x10DE && 4342 fsaa >= 8) 4343 { 4344 tryCSAA = true; 4345 } 4346 4347 while (!ok) 4348 { 4349 // Deal with special cases 4350 if (tryCSAA) 4351 { 4352 // see http://developer.nvidia.com/object/coverage-sampled-aa.html 4353 switch(fsaa) 4354 { 4355 case 8: 4356 if (qualityHint) 4357 { 4358 *outMultisampleType = D3DMULTISAMPLE_8_SAMPLES; 4359 *outMultisampleQuality = 0; 4360 } 4361 else 4362 { 4363 *outMultisampleType = D3DMULTISAMPLE_4_SAMPLES; 4364 *outMultisampleQuality = 2; 4365 } 4366 break; 4367 case 16: 4368 if (qualityHint) 4369 { 4370 *outMultisampleType = D3DMULTISAMPLE_8_SAMPLES; 4371 *outMultisampleQuality = 2; 4372 } 4373 else 4374 { 4375 *outMultisampleType = D3DMULTISAMPLE_4_SAMPLES; 4376 *outMultisampleQuality = 4; 4377 } 4378 break; 4379 } 4380 } 4381 else // !CSAA 4382 { 4383 *outMultisampleType = (D3DMULTISAMPLE_TYPE)fsaa; 4384 *outMultisampleQuality = 0; 4385 } 4386 4387 4388 HRESULT hr; 4389 DWORD outQuality; 4390 hr = mD3D->CheckDeviceMultiSampleType( 4391 deviceDriver->getAdapterNumber(), 4392 D3DDEVTYPE_HAL, 4393 d3dPixelFormat, 4394 fullScreen, 4395 *outMultisampleType, 4396 &outQuality); 4397 4398 if (SUCCEEDED(hr) && 4399 (!tryCSAA || outQuality > *outMultisampleQuality)) 4400 { 4401 ok = true; 4402 } 4403 else 4404 { 4405 // downgrade 4406 if (tryCSAA && fsaa == 8) 4407 { 4408 // for CSAA, we'll try downgrading with quality mode at all samples. 4409 // then try without quality, then drop CSAA 4410 if (qualityHint) 4411 { 4412 // drop quality first 4413 qualityHint = false; 4414 } 4415 else 4416 { 4417 // drop CSAA entirely 4418 tryCSAA = false; 4419 } 4420 // return to original requested samples 4421 fsaa = origFSAA; 4422 } 4423 else 4424 { 4425 // drop samples 4426 --fsaa; 4427 4428 OgreAssert(fsaa > 0, "FSAA underflow: infinite loop (this should never happen)"); 4429 4430 if (fsaa <= 1) 4431 { 4432 // ran out of options, no FSAA 4433 fsaa = 0; 4434 ok = true; 4435 4436 *outMultisampleType = D3DMULTISAMPLE_NONE; 4437 *outMultisampleQuality = 0; 4438 } 4439 } 4440 } 4441 4442 } // while !ok 4443 } 4444 4445 //--------------------------------------------------------------------- fireDeviceEvent(D3D9Device * device,const String & name)4446 void D3D9RenderSystem::fireDeviceEvent( D3D9Device* device, const String & name ) 4447 { 4448 NameValuePairList params; 4449 params["D3DDEVICE"] = StringConverter::toString((size_t)device->getD3D9Device()); 4450 params["DEVICE_ADAPTER_NUMBER"] = StringConverter::toString(device->getAdapterNumber()); 4451 4452 fireEvent(name, ¶ms); 4453 } 4454 } 4455