gfxInit.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "gfx/gfxInit.h"
  24. #include "gfx/gfxTextureManager.h"
  25. #include "gfx/gfxAPI.h"
  26. #include "console/console.h"
  27. #include "windowManager/platformWindowMgr.h"
  28. #include "core/module.h"
  29. Vector<GFXAdapter*> GFXInit::smAdapters( __FILE__, __LINE__ );
  30. GFXInit::RegisterDeviceSignal* GFXInit::smRegisterDeviceSignal;
  31. MODULE_BEGIN( GFX )
  32. MODULE_INIT
  33. {
  34. GFXInit::init();
  35. if( engineAPI::gUseConsoleInterop )
  36. GFXDevice::initConsole();
  37. GFXTextureManager::init();
  38. }
  39. MODULE_SHUTDOWN
  40. {
  41. GFXDevice::destroy();
  42. GFXInit::cleanup();
  43. }
  44. MODULE_END;
  45. IMPLEMENT_STATIC_CLASS( GFXInit, GFXAPI,
  46. "Functions for tracking GFX adapters and initializing them into devices."
  47. );
  48. ConsoleDoc(
  49. "@class GFXInit\n"
  50. "@ingroup GFX\n"
  51. "@brief Functions for tracking GFX adapters and initializing them into devices.\n"
  52. );
  53. inline static void _GFXInitReportAdapters(Vector<GFXAdapter*> &adapters)
  54. {
  55. for (U32 i = 0; i < adapters.size(); i++)
  56. {
  57. switch (adapters[i]->mType)
  58. {
  59. case Direct3D9:
  60. Con::printf(" Direct 3D (version 9.x) device found");
  61. break;
  62. case OpenGL:
  63. Con::printf(" OpenGL device found");
  64. break;
  65. case NullDevice:
  66. Con::printf(" Null device found");
  67. break;
  68. case Direct3D11:
  69. Con::printf(" Direct 3D (version 11.x) device found");
  70. break;
  71. default :
  72. Con::printf(" Unknown device found");
  73. break;
  74. }
  75. }
  76. }
  77. inline static void _GFXInitGetInitialRes(GFXVideoMode &vm, const Point2I &initialSize)
  78. {
  79. const U32 kDefaultWindowSizeX = 800;
  80. const U32 kDefaultWindowSizeY = 600;
  81. const bool kDefaultFullscreen = false;
  82. const U32 kDefaultBitDepth = 32;
  83. const U32 kDefaultRefreshRate = 60;
  84. // cache the desktop size of the main screen
  85. GFXVideoMode desktopVm = GFXInit::getDesktopResolution();
  86. // load pref variables, properly choose windowed / fullscreen
  87. const String resString = Con::getVariable("$pref::Video::mode");
  88. // Set defaults into the video mode, then have it parse the user string.
  89. vm.resolution.x = kDefaultWindowSizeX;
  90. vm.resolution.y = kDefaultWindowSizeY;
  91. vm.fullScreen = kDefaultFullscreen;
  92. vm.bitDepth = kDefaultBitDepth;
  93. vm.refreshRate = kDefaultRefreshRate;
  94. vm.wideScreen = false;
  95. vm.parseFromString(resString);
  96. }
  97. GFXInit::RegisterDeviceSignal& GFXInit::getRegisterDeviceSignal()
  98. {
  99. if (smRegisterDeviceSignal)
  100. return *smRegisterDeviceSignal;
  101. smRegisterDeviceSignal = new RegisterDeviceSignal();
  102. return *smRegisterDeviceSignal;
  103. }
  104. void GFXInit::init()
  105. {
  106. // init only once.
  107. static bool doneOnce = false;
  108. if(doneOnce)
  109. return;
  110. doneOnce = true;
  111. Con::printf( "GFX Init:" );
  112. //find our adapters
  113. Vector<GFXAdapter*> adapters( __FILE__, __LINE__ );
  114. GFXInit::enumerateAdapters();
  115. GFXInit::getAdapters(&adapters);
  116. if(!adapters.size())
  117. Con::errorf("Could not find a display adapter");
  118. //loop through and tell the user what kind of adapters we found
  119. _GFXInitReportAdapters(adapters);
  120. Con::printf( "" );
  121. }
  122. void GFXInit::cleanup()
  123. {
  124. while( smAdapters.size() )
  125. {
  126. GFXAdapter* adapter = smAdapters.last();
  127. smAdapters.decrement();
  128. delete adapter;
  129. }
  130. if( smRegisterDeviceSignal )
  131. SAFE_DELETE( smRegisterDeviceSignal );
  132. }
  133. bool GFXInit::compareAdapterOutputDevice(const GFXAdapter* adapter, const char* outputDevice)
  134. {
  135. // If the adapter doesn't have an output display device, then it supports all of them
  136. if(!adapter->mOutputName[0])
  137. return true;
  138. // Try and match the first part of the output device display name. For example,
  139. // an adapter->mOutputName of "\\.\DISPLAY1" might correspond to a display name
  140. // of "\\.\DISPLAY1\Monitor0". If two monitors are set up in duplicate mode then
  141. // they will have the same 'display' part in their display name.
  142. return (dStrstr(outputDevice, adapter->mOutputName) == outputDevice);
  143. }
  144. GFXAdapter* GFXInit::getAdapterOfType( GFXAdapterType type, const char* outputDevice )
  145. {
  146. bool testOutputDevice = false;
  147. if(outputDevice && outputDevice[0])
  148. testOutputDevice = true;
  149. for( U32 i = 0; i < smAdapters.size(); i++ )
  150. {
  151. if( smAdapters[i]->mType == type )
  152. {
  153. if(testOutputDevice)
  154. {
  155. // Check if the output display device also matches
  156. if(compareAdapterOutputDevice(smAdapters[i], outputDevice))
  157. {
  158. return smAdapters[i];
  159. }
  160. }
  161. else
  162. {
  163. // No need to also test the output display device, so return
  164. return smAdapters[i];
  165. }
  166. }
  167. }
  168. return NULL;
  169. }
  170. GFXAdapter* GFXInit::getAdapterOfType(GFXAdapterType type, S32 outputDeviceIndex)
  171. {
  172. for (U32 i = 0; i < smAdapters.size(); i++)
  173. {
  174. if (smAdapters[i]->mType == type)
  175. {
  176. if (smAdapters[i]->mIndex == outputDeviceIndex)
  177. {
  178. return smAdapters[i];
  179. }
  180. }
  181. }
  182. return NULL;
  183. }
  184. GFXAdapter* GFXInit::chooseAdapter( GFXAdapterType type, const char* outputDevice)
  185. {
  186. GFXAdapter* adapter = GFXInit::getAdapterOfType(type, outputDevice);
  187. if(!adapter && type != OpenGL)
  188. {
  189. Con::errorf("The requested renderer, %s, doesn't seem to be available."
  190. " Trying the default, OpenGL.", getAdapterNameFromType(type));
  191. adapter = GFXInit::getAdapterOfType(OpenGL, outputDevice);
  192. }
  193. if(!adapter)
  194. {
  195. Con::errorf("The OpenGL renderer doesn't seem to be available. Trying the GFXNulDevice.");
  196. adapter = GFXInit::getAdapterOfType(NullDevice, "");
  197. }
  198. AssertFatal( adapter, "There is no rendering device available whatsoever.");
  199. return adapter;
  200. }
  201. GFXAdapter* GFXInit::chooseAdapter(GFXAdapterType type, S32 outputDeviceIndex)
  202. {
  203. GFXAdapter* adapter = GFXInit::getAdapterOfType(type, outputDeviceIndex);
  204. if (!adapter && type != OpenGL)
  205. {
  206. Con::errorf("The requested renderer, %s, doesn't seem to be available."
  207. " Trying the default, OpenGL.", getAdapterNameFromType(type));
  208. adapter = GFXInit::getAdapterOfType(OpenGL, outputDeviceIndex);
  209. }
  210. if (!adapter)
  211. {
  212. Con::errorf("The OpenGL renderer doesn't seem to be available. Trying the GFXNulDevice.");
  213. adapter = GFXInit::getAdapterOfType(NullDevice, 0);
  214. }
  215. AssertFatal(adapter, "There is no rendering device available whatsoever.");
  216. return adapter;
  217. }
  218. const char* GFXInit::getAdapterNameFromType(GFXAdapterType type)
  219. {
  220. // must match GFXAdapterType order
  221. static const char* _names[] = { "OpenGL", "D3D11", "D3D9", "NullDevice", "Xenon" };
  222. if( type < 0 || type >= GFXAdapterType_Count )
  223. {
  224. Con::errorf( "GFXInit::getAdapterNameFromType - Invalid renderer type, defaulting to OpenGL" );
  225. return _names[OpenGL];
  226. }
  227. return _names[type];
  228. }
  229. GFXAdapterType GFXInit::getAdapterTypeFromName(const char* name)
  230. {
  231. S32 ret = -1;
  232. for(S32 i = 0; i < GFXAdapterType_Count; i++)
  233. {
  234. if( !dStricmp( getAdapterNameFromType((GFXAdapterType)i), name ) )
  235. ret = i;
  236. }
  237. if( ret == -1 )
  238. {
  239. Con::errorf( "GFXInit::getAdapterTypeFromName - Invalid renderer name, defaulting to D3D9" );
  240. ret = Direct3D9;
  241. }
  242. return (GFXAdapterType)ret;
  243. }
  244. GFXAdapter *GFXInit::getBestAdapterChoice()
  245. {
  246. // Get the user's preference for device...
  247. const String renderer = Con::getVariable("$pref::Video::displayDevice");
  248. const String outputDevice = Con::getVariable("$pref::Video::displayOutputDevice");
  249. const String adapterDevice = Con::getVariable("$Video::forceDisplayAdapter");
  250. GFXAdapterType adapterType = getAdapterTypeFromName(renderer.c_str());;
  251. GFXAdapter *adapter = NULL;
  252. if (adapterDevice.isEmpty())
  253. {
  254. adapter = chooseAdapter(adapterType, outputDevice.c_str());
  255. }
  256. else
  257. {
  258. S32 adapterIdx = dAtoi(adapterDevice.c_str());
  259. if (adapterIdx == -1)
  260. adapter = chooseAdapter(adapterType, outputDevice.c_str());
  261. else
  262. adapter = chooseAdapter(adapterType, adapterIdx);
  263. }
  264. // Did they have one? Return it.
  265. if(adapter)
  266. return adapter;
  267. // Didn't have one. So make it up. Find the highest SM available. Prefer
  268. // D3D to GL because if we have a D3D device at all we're on windows,
  269. // and in an unknown situation on Windows D3D is probably the safest bet.
  270. //
  271. // If D3D is unavailable, we're not on windows, so GL is de facto the
  272. // best choice!
  273. F32 highestSMDX = 0.f, highestSMGL = 0.f;
  274. GFXAdapter *foundAdapter9 = NULL, *foundAdapterGL = NULL, *foundAdapter11 = NULL;
  275. for (S32 i = 0; i<smAdapters.size(); i++)
  276. {
  277. GFXAdapter *currAdapter = smAdapters[i];
  278. switch (currAdapter->mType)
  279. {
  280. case Direct3D11:
  281. if (currAdapter->mShaderModel > highestSMDX)
  282. {
  283. highestSMDX = currAdapter->mShaderModel;
  284. foundAdapter11 = currAdapter;
  285. }
  286. break;
  287. case Direct3D9:
  288. if (currAdapter->mShaderModel > highestSMDX)
  289. {
  290. highestSMDX = currAdapter->mShaderModel;
  291. foundAdapter9 = currAdapter;
  292. }
  293. break;
  294. case OpenGL:
  295. if (currAdapter->mShaderModel > highestSMGL)
  296. {
  297. highestSMGL = currAdapter->mShaderModel;
  298. foundAdapterGL = currAdapter;
  299. }
  300. break;
  301. default:
  302. break;
  303. }
  304. }
  305. // Return best found in order DX11,DX9, GL
  306. if (foundAdapter11)
  307. return foundAdapter11;
  308. if (foundAdapter9)
  309. return foundAdapter9;
  310. if (foundAdapterGL)
  311. return foundAdapterGL;
  312. // Uh oh - we didn't find anything. Grab whatever we can that's not Null...
  313. for(S32 i=0; i<smAdapters.size(); i++)
  314. if(smAdapters[i]->mType != NullDevice)
  315. return smAdapters[i];
  316. // Dare we return a null device? No. Just return NULL.
  317. return NULL;
  318. }
  319. GFXVideoMode GFXInit::getInitialVideoMode()
  320. {
  321. GFXVideoMode vm;
  322. _GFXInitGetInitialRes(vm, Point2I(800,600));
  323. return vm;
  324. }
  325. S32 GFXInit::getAdapterCount()
  326. {
  327. return smAdapters.size();
  328. }
  329. void GFXInit::getAdapters(Vector<GFXAdapter*> *adapters)
  330. {
  331. adapters->clear();
  332. for (U32 k = 0; k < smAdapters.size(); k++)
  333. adapters->push_back(smAdapters[k]);
  334. }
  335. GFXVideoMode GFXInit::getDesktopResolution()
  336. {
  337. GFXVideoMode resVm;
  338. // Retrieve Resolution Information.
  339. resVm.bitDepth = WindowManager->getDesktopBitDepth();
  340. resVm.resolution = WindowManager->getDesktopResolution();
  341. resVm.fullScreen = false;
  342. resVm.refreshRate = 60;
  343. // Return results
  344. return resVm;
  345. }
  346. void GFXInit::enumerateAdapters()
  347. {
  348. // Call each device class and have it report any adapters it supports.
  349. if(smAdapters.size())
  350. {
  351. // CodeReview Seems like this is ok to just ignore? [bjg, 5/19/07]
  352. //Con::warnf("GFXInit::enumerateAdapters - already have a populated adapter list, aborting re-analysis.");
  353. return;
  354. }
  355. getRegisterDeviceSignal().trigger(GFXInit::smAdapters);
  356. }
  357. GFXDevice *GFXInit::createDevice( GFXAdapter *adapter )
  358. {
  359. Con::printf("Attempting to create GFX device: %s [%s]", adapter->getName(), adapter->getOutputName());
  360. GFXDevice* temp = adapter->mCreateDeviceInstanceDelegate(adapter->mIndex);
  361. if (temp)
  362. {
  363. Con::printf("Device created, setting adapter and enumerating modes");
  364. temp->setAdapter(*adapter);
  365. temp->enumerateVideoModes();
  366. temp->getVideoModeList();
  367. }
  368. else
  369. Con::errorf("Failed to create GFX device");
  370. GFXDevice::getDeviceEventSignal().trigger(GFXDevice::deCreate);
  371. return temp;
  372. }
  373. DefineEngineFunction( getDesktopResolution, Point3F, (),,
  374. "Returns the width, height, and bitdepth of the screen/desktop.\n\n@ingroup GFX" )
  375. {
  376. GFXVideoMode res = GFXInit::getDesktopResolution();
  377. return Point3F( res.resolution.x, res.resolution.y, res.bitDepth );
  378. }
  379. DefineEngineStaticMethod( GFXInit, getAdapterCount, S32, (),,
  380. "Return the number of graphics adapters available. @ingroup GFX")
  381. {
  382. return GFXInit::getAdapterCount();
  383. }
  384. DefineEngineStaticMethod( GFXInit, getAdapterName, String, ( S32 index ),,
  385. "Returns the name of the graphics adapter.\n"
  386. "@param index The index of the adapter." )
  387. {
  388. Vector<GFXAdapter*> adapters( __FILE__, __LINE__ );
  389. GFXInit::getAdapters(&adapters);
  390. if(index >= 0 && index < adapters.size())
  391. return adapters[index]->mName;
  392. Con::errorf( "GFXInit::getAdapterName - Out of range adapter index." );
  393. return String::EmptyString;
  394. }
  395. DefineEngineStaticMethod( GFXInit, getAdapterOutputName, String, ( S32 index ),,
  396. "Returns the name of the graphics adapter's output display device.\n"
  397. "@param index The index of the adapter." )
  398. {
  399. Vector<GFXAdapter*> adapters( __FILE__, __LINE__ );
  400. GFXInit::getAdapters(&adapters);
  401. if(index >= 0 && index < adapters.size())
  402. return adapters[index]->mOutputName;
  403. Con::errorf( "GFXInit::getAdapterOutputName - Out of range adapter index." );
  404. return String::EmptyString;
  405. }
  406. DefineEngineStaticMethod( GFXInit, getAdapterType, GFXAdapterType, ( S32 index ),,
  407. "Returns the type (D3D9, D3D8, GL, Null) of a graphics adapter.\n"
  408. "@param index The index of the adapter." )
  409. {
  410. Vector<GFXAdapter*> adapters( __FILE__, __LINE__ );
  411. GFXInit::getAdapters(&adapters);
  412. if( index >= 0 && index < adapters.size())
  413. return adapters[index]->mType;
  414. Con::errorf( "GFXInit::getAdapterType - Out of range adapter index." );
  415. return GFXAdapterType_Count;
  416. }
  417. DefineEngineStaticMethod( GFXInit, getAdapterShaderModel, F32, ( S32 index ),,
  418. "Returns the supported shader model of the graphics adapter or -1 if the index is bad.\n"
  419. "@param index The index of the adapter." )
  420. {
  421. Vector<GFXAdapter*> adapters( __FILE__, __LINE__ );
  422. GFXInit::getAdapters(&adapters);
  423. if(index < 0 || index >= adapters.size())
  424. {
  425. Con::errorf("GFXInit::getAdapterShaderModel - Out of range adapter index.");
  426. return -1.0f;
  427. }
  428. return adapters[index]->mShaderModel;
  429. }
  430. DefineEngineStaticMethod( GFXInit, getDefaultAdapterIndex, S32, (),,
  431. "Returns the index of the default graphics adapter. This is the graphics device "
  432. "which will be used to initialize the engine." )
  433. {
  434. GFXAdapter *a = GFXInit::getBestAdapterChoice();
  435. // We have to find the index of the adapter in the list to
  436. // return an index that makes sense to the script.
  437. Vector<GFXAdapter*> adapters( __FILE__, __LINE__ );
  438. GFXInit::getAdapters(&adapters);
  439. for(S32 i=0; i<adapters.size(); i++)
  440. if ( adapters[i]->mIndex == a->mIndex &&
  441. adapters[i]->mType == a->mType )
  442. return i;
  443. Con::warnf( "GFXInit::getDefaultAdapterIndex - Didn't find the adapter in the list!" );
  444. return -1;
  445. }
  446. DefineEngineStaticMethod( GFXInit, getAdapterModeCount, S32, ( S32 index ),,
  447. "Gets the number of modes available on the specified adapter.\n\n"
  448. "@param index Index of the adapter to get modes from.\n"
  449. "@return The number of video modes supported by the adapter or -1 if the given adapter was not found." )
  450. {
  451. Vector<GFXAdapter*> adapters( __FILE__, __LINE__ );
  452. GFXInit::getAdapters(&adapters);
  453. if( index < 0 || index >= adapters.size())
  454. {
  455. Con::warnf( "GFXInit::getAdapterModeCount - The index was out of range." );
  456. return -1;
  457. }
  458. return adapters[index]->mAvailableModes.size();
  459. }
  460. DefineConsoleStaticMethod( GFXInit, getAdapterMode, String, ( S32 index, S32 modeIndex ),,
  461. "Gets the details of the specified adapter mode.\n\n"
  462. "@param index Index of the adapter to query.\n"
  463. "@param modeIndex Index of the mode to get data from.\n"
  464. "@return A video mode string in the format 'width height fullscreen bitDepth refreshRate aaLevel'.\n"
  465. "@see GuiCanvas::getVideoMode()" )
  466. {
  467. Vector<GFXAdapter*> adapters( __FILE__, __LINE__ );
  468. GFXInit::getAdapters(&adapters);
  469. if ( index < 0 || index >= adapters.size() )
  470. {
  471. Con::warnf( "GFXInit::getAdapterMode - The adapter index was out of range." );
  472. return String::EmptyString;
  473. }
  474. if ( modeIndex < 0 || modeIndex >= adapters[index]->mAvailableModes.size() )
  475. {
  476. Con::warnf( "GFXInit::getAdapterMode - The mode index was out of range." );
  477. return String::EmptyString;
  478. }
  479. const GFXVideoMode &vm = adapters[index]->mAvailableModes[modeIndex];
  480. return vm.toString();
  481. }
  482. DefineEngineStaticMethod( GFXInit, createNullDevice, void, (),,
  483. "Create the NULL graphics device used for testing or headless operation." )
  484. {
  485. // Enumerate things for GFX before we have an active device.
  486. GFXInit::enumerateAdapters();
  487. // Create a device.
  488. GFXAdapter *a = GFXInit::chooseAdapter(NullDevice, "");
  489. GFXDevice *newDevice = GFX;
  490. // Do we have a global device already? (This is the site if you want
  491. // to start rendering to multiple devices simultaneously)
  492. if(newDevice == NULL)
  493. newDevice = GFXInit::createDevice(a);
  494. newDevice->setAllowRender( false );
  495. }