CmD3D9RenderSystem.cpp 95 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968
  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. Copyright (c) 2000-2011 Torus Knot Software Ltd
  7. Permission is hereby granted, free of charge, to any person obtaining a copy
  8. of this software and associated documentation files (the "Software"), to deal
  9. in the Software without restriction, including without limitation the rights
  10. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. copies of the Software, and to permit persons to whom the Software is
  12. furnished to do so, subject to the following conditions:
  13. The above copyright notice and this permission notice shall be included in
  14. all copies or substantial portions of the Software.
  15. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. THE SOFTWARE.
  22. -----------------------------------------------------------------------------
  23. */
  24. #include "CmD3D9RenderSystem.h"
  25. #include "CmD3D9Prerequisites.h"
  26. #include "CmD3D9DriverList.h"
  27. #include "CmD3D9Driver.h"
  28. #include "CmD3D9VideoModeList.h"
  29. #include "CmD3D9VideoMode.h"
  30. #include "CmD3D9RenderWindow.h"
  31. #include "CmD3D9TextureManager.h"
  32. #include "CmD3D9Texture.h"
  33. #include "CmMath.h"
  34. #include "CmCamera.h"
  35. #include "CmD3D9HardwareBufferManager.h"
  36. #include "CmD3D9HardwareIndexBuffer.h"
  37. #include "CmD3D9HardwareVertexBuffer.h"
  38. #include "CmD3D9VertexDeclaration.h"
  39. #include "CmD3D9GpuProgram.h"
  40. #include "CmD3D9GpuProgramManager.h"
  41. #include "CmD3D9HLSLProgramFactory.h"
  42. #include "CmD3D9HardwareOcclusionQuery.h"
  43. #include "CmD3D9MultiRenderTarget.h"
  44. #include "CmD3D9DeviceManager.h"
  45. #include "CmD3D9ResourceManager.h"
  46. #include "CmHighLevelGpuProgramManager.h"
  47. #include "CmAsyncOp.h"
  48. #include "CmBlendState.h"
  49. #include "CmRasterizerState.h"
  50. #include "CmDepthStencilState.h"
  51. #if CM_DEBUG_MODE
  52. #define THROW_IF_NOT_RENDER_THREAD throwIfNotRenderThread();
  53. #define THROW_IF_NOT_RENDER_THREAD_STATIC msD3D9RenderSystem->throwIfNotRenderThread();
  54. #else
  55. #define THROW_IF_NOT_RENDER_THREAD
  56. #define THROW_IF_NOT_RENDER_THREAD_STATIC
  57. #endif
  58. #define FLOAT2DWORD(f) *((DWORD*)&f)
  59. // Formats to try, in decreasing order of preference
  60. D3DFORMAT ddDepthStencilFormats[]={
  61. D3DFMT_D24FS8,
  62. D3DFMT_D24S8,
  63. D3DFMT_D24X4S4,
  64. D3DFMT_D24X8,
  65. D3DFMT_D15S1,
  66. D3DFMT_D16,
  67. D3DFMT_D32
  68. };
  69. #define NDSFORMATS (sizeof(ddDepthStencilFormats)/sizeof(D3DFORMAT))
  70. namespace CamelotEngine
  71. {
  72. D3D9RenderSystem* D3D9RenderSystem::msD3D9RenderSystem = NULL;
  73. /************************************************************************/
  74. /* PUBLIC INTERFACE */
  75. /************************************************************************/
  76. //---------------------------------------------------------------------
  77. D3D9RenderSystem::D3D9RenderSystem( HINSTANCE hInstance )
  78. {
  79. // update singleton access pointer.
  80. msD3D9RenderSystem = this;
  81. // set the instance being passed
  82. mhInstance = hInstance;
  83. // set pointers to NULL
  84. mpD3D = NULL;
  85. mDriverList = NULL;
  86. mActiveD3DDriver = NULL;
  87. mUseNVPerfHUD = false;
  88. mHLSLProgramFactory = NULL;
  89. mCgProgramFactory = NULL;
  90. mDeviceManager = NULL;
  91. mResourceManager = nullptr;
  92. mScissorRect.left = 0;
  93. mScissorRect.right = 1280;
  94. mScissorRect.top = 0;
  95. mScissorRect.bottom = 720;
  96. }
  97. //---------------------------------------------------------------------
  98. D3D9RenderSystem::~D3D9RenderSystem()
  99. {
  100. shutdown_internal();
  101. // Deleting the HLSL program factory
  102. if (mHLSLProgramFactory)
  103. {
  104. HighLevelGpuProgramManager::instance().removeFactory(mHLSLProgramFactory);
  105. delete mHLSLProgramFactory;
  106. mHLSLProgramFactory = 0;
  107. }
  108. if(mCgProgramFactory)
  109. {
  110. HighLevelGpuProgramManager::instance().removeFactory(mCgProgramFactory);
  111. delete mCgProgramFactory;
  112. mCgProgramFactory = 0;
  113. }
  114. SAFE_RELEASE( mpD3D );
  115. SAFE_DELETE ( mResourceManager );
  116. msD3D9RenderSystem = NULL;
  117. }
  118. //---------------------------------------------------------------------
  119. const String& D3D9RenderSystem::getName() const
  120. {
  121. static String strName( "D3D9RenderSystem");
  122. return strName;
  123. }
  124. void D3D9RenderSystem::startUp_internal()
  125. {
  126. THROW_IF_NOT_RENDER_THREAD;
  127. // Create the resource manager.
  128. mResourceManager = new D3D9ResourceManager();
  129. // Create our Direct3D object
  130. if( NULL == (mpD3D = Direct3DCreate9(D3D_SDK_VERSION)) )
  131. CM_EXCEPT(InternalErrorException, "Failed to create Direct3D9 object");
  132. // set config options defaults
  133. initConfigOptions();
  134. // fsaa options
  135. mFSAAHint = "";
  136. mFSAASamples = 0;
  137. // set stages desc. to defaults
  138. for (size_t n = 0; n < CM_MAX_TEXTURE_LAYERS; n++)
  139. {
  140. mTexStageDesc[n].coordIndex = 0;
  141. mTexStageDesc[n].texType = D3D9Mappings::D3D_TEX_TYPE_NORMAL;
  142. mTexStageDesc[n].pTex = 0;
  143. mTexStageDesc[n].pVertexTex = 0;
  144. }
  145. mLastVertexSourceCount = 0;
  146. mCurrentLights.clear();
  147. RenderWindow* autoWindow = NULL;
  148. // Init using current settings
  149. mActiveD3DDriver = NULL;
  150. ConfigOptionMap::iterator opt = mOptions.find( "Rendering Device" );
  151. for( UINT32 j=0; j < getDirect3DDrivers()->count(); j++ )
  152. {
  153. if( getDirect3DDrivers()->item(j)->DriverDescription() == opt->second.currentValue )
  154. {
  155. mActiveD3DDriver = getDirect3DDrivers()->item(j);
  156. break;
  157. }
  158. }
  159. if( !mActiveD3DDriver )
  160. CM_EXCEPT(InvalidParametersException, "Problems finding requested Direct3D driver!" );
  161. // get driver version
  162. mDriverVersion.major = HIWORD(mActiveD3DDriver->getAdapterIdentifier().DriverVersion.HighPart);
  163. mDriverVersion.minor = LOWORD(mActiveD3DDriver->getAdapterIdentifier().DriverVersion.HighPart);
  164. mDriverVersion.release = HIWORD(mActiveD3DDriver->getAdapterIdentifier().DriverVersion.LowPart);
  165. mDriverVersion.build = LOWORD(mActiveD3DDriver->getAdapterIdentifier().DriverVersion.LowPart);
  166. // Create the device manager.
  167. mDeviceManager = new D3D9DeviceManager();
  168. // Create the texture manager for use by others
  169. TextureManager::startUp(new D3D9TextureManager());
  170. // Also create hardware buffer manager
  171. HardwareBufferManager::startUp(new D3D9HardwareBufferManager());
  172. // Create the GPU program manager
  173. GpuProgramManager::startUp(new D3D9GpuProgramManager());
  174. // Create & register HLSL factory
  175. mHLSLProgramFactory = new D3D9HLSLProgramFactory();
  176. // Create & register Cg factory
  177. mCgProgramFactory = new CgProgramFactory();
  178. // call superclass method
  179. RenderSystem::startUp_internal();
  180. }
  181. //---------------------------------------------------------------------
  182. void D3D9RenderSystem::shutdown_internal()
  183. {
  184. RenderSystem::shutdown_internal();
  185. SAFE_DELETE( mDeviceManager );
  186. SAFE_DELETE( mDriverList );
  187. mActiveD3DDriver = NULL;
  188. TextureManager::shutDown();
  189. HardwareBufferManager::shutDown();
  190. GpuProgramManager::shutDown();
  191. }
  192. //--------------------------------------------------------------------
  193. void D3D9RenderSystem::createRenderWindow_internal(const String &name,
  194. unsigned int width, unsigned int height, bool fullScreen,
  195. const NameValuePairList& miscParams, AsyncOp& asyncOp)
  196. {
  197. THROW_IF_NOT_RENDER_THREAD;
  198. String msg;
  199. D3D9RenderWindow* renderWindow = new D3D9RenderWindow(mhInstance);
  200. renderWindow->create(name, width, height, fullScreen, &miscParams);
  201. mResourceManager->lockDeviceAccess();
  202. try
  203. {
  204. mDeviceManager->linkRenderWindow(renderWindow);
  205. }
  206. catch (const CamelotEngine::RenderingAPIException&)
  207. {
  208. // after catching the exception, clean up
  209. mResourceManager->unlockDeviceAccess();
  210. renderWindow->destroy();
  211. // re-throw
  212. throw;
  213. }
  214. mResourceManager->unlockDeviceAccess();
  215. mRenderWindows.push_back(renderWindow);
  216. updateRenderSystemCapabilities(renderWindow);
  217. attachRenderTarget( *renderWindow );
  218. asyncOp.completeOperation(static_cast<RenderWindow*>(renderWindow));
  219. }
  220. void D3D9RenderSystem::bindGpuProgram(GpuProgramHandle prg)
  221. {
  222. THROW_IF_NOT_RENDER_THREAD;
  223. GpuProgram* bindingPrg = prg->getBindingDelegate_internal();
  224. HRESULT hr;
  225. switch (bindingPrg->getType())
  226. {
  227. case GPT_VERTEX_PROGRAM:
  228. hr = getActiveD3D9Device()->SetVertexShader(
  229. static_cast<D3D9GpuVertexProgram*>(bindingPrg)->getVertexShader());
  230. if (FAILED(hr))
  231. {
  232. CM_EXCEPT(RenderingAPIException, "Error calling SetVertexShader");
  233. }
  234. break;
  235. case GPT_FRAGMENT_PROGRAM:
  236. hr = getActiveD3D9Device()->SetPixelShader(
  237. static_cast<D3D9GpuFragmentProgram*>(bindingPrg)->getPixelShader());
  238. if (FAILED(hr))
  239. {
  240. CM_EXCEPT(RenderingAPIException, "Error calling SetPixelShader");
  241. }
  242. break;
  243. };
  244. // Make sure texcoord index is equal to stage value, As SDK Doc suggests:
  245. // "When rendering using vertex shaders, each stage's texture coordinate index must be set to its default value."
  246. // This solves such an errors when working with the Debug runtime -
  247. // "Direct3D9: (ERROR) :Stage 1 - Texture coordinate index in the stage must be equal to the stage index when programmable vertex pipeline is used".
  248. for (unsigned int nStage=0; nStage < 8; ++nStage)
  249. __SetTextureStageState(nStage, D3DTSS_TEXCOORDINDEX, nStage);
  250. RenderSystem::bindGpuProgram(prg);
  251. }
  252. void D3D9RenderSystem::unbindGpuProgram(GpuProgramType gptype)
  253. {
  254. THROW_IF_NOT_RENDER_THREAD;
  255. HRESULT hr;
  256. switch(gptype)
  257. {
  258. case GPT_VERTEX_PROGRAM:
  259. mActiveVertexGpuProgramParameters = nullptr;
  260. hr = getActiveD3D9Device()->SetVertexShader(NULL);
  261. if (FAILED(hr))
  262. {
  263. CM_EXCEPT(RenderingAPIException, "Error resetting SetVertexShader to NULL");
  264. }
  265. break;
  266. case GPT_FRAGMENT_PROGRAM:
  267. mActiveFragmentGpuProgramParameters = nullptr;
  268. hr = getActiveD3D9Device()->SetPixelShader(NULL);
  269. if (FAILED(hr))
  270. {
  271. CM_EXCEPT(RenderingAPIException, "Error resetting SetPixelShader to NULL");
  272. }
  273. break;
  274. };
  275. RenderSystem::unbindGpuProgram(gptype);
  276. }
  277. void D3D9RenderSystem::bindGpuProgramParameters(GpuProgramType gptype,
  278. GpuProgramParametersSharedPtr params, UINT16 variability)
  279. {
  280. THROW_IF_NOT_RENDER_THREAD;
  281. HRESULT hr;
  282. GpuLogicalBufferStructPtr floatLogical = params->getFloatLogicalBufferStruct();
  283. GpuLogicalBufferStructPtr intLogical = params->getIntLogicalBufferStruct();
  284. GpuLogicalBufferStructPtr samplerLogical = params->getSamplerLogicalBufferStruct();
  285. GpuLogicalBufferStructPtr textureLogical = params->getTextureLogicalBufferStruct();
  286. // Set texture & sampler
  287. {
  288. for (GpuLogicalIndexUseMap::const_iterator i = samplerLogical->map.begin(); i != samplerLogical->map.end(); ++i)
  289. {
  290. if (i->second.variability & variability)
  291. {
  292. UINT32 logicalIndex = i->first;
  293. SamplerStatePtr samplerState = params->getSamplerState(i->second.physicalIndex);
  294. if(samplerState == nullptr)
  295. setSamplerState(logicalIndex, SamplerState::getDefault());
  296. else
  297. setSamplerState(logicalIndex, *samplerState);
  298. }
  299. }
  300. for (GpuLogicalIndexUseMap::const_iterator i = textureLogical->map.begin(); i != textureLogical->map.end(); ++i)
  301. {
  302. if (i->second.variability & variability)
  303. {
  304. UINT32 logicalIndex = i->first;
  305. TextureHandle texture = params->getTexture(i->second.physicalIndex);
  306. if(!texture.isLoaded())
  307. continue;
  308. setTexture(logicalIndex, true, texture.getInternalPtr());
  309. }
  310. }
  311. }
  312. switch(gptype)
  313. {
  314. case GPT_VERTEX_PROGRAM:
  315. mActiveVertexGpuProgramParameters = params;
  316. {
  317. for (GpuLogicalIndexUseMap::const_iterator i = floatLogical->map.begin();
  318. i != floatLogical->map.end(); ++i)
  319. {
  320. if (i->second.variability & variability)
  321. {
  322. UINT32 logicalIndex = i->first;
  323. const float* pFloat = params->getFloatPointer(i->second.physicalIndex);
  324. UINT32 slotCount = i->second.currentSize / 4;
  325. assert (i->second.currentSize % 4 == 0 && "Should not have any "
  326. "elements less than 4 wide for D3D9");
  327. if (FAILED(hr = getActiveD3D9Device()->SetVertexShaderConstantF( // TODO Low priority. Binding parameters 1 by 1 is slow. It would be better to keep them in a sequential
  328. (UINT)logicalIndex, pFloat, (UINT)slotCount))) // buffer and then only call this method once
  329. {
  330. CM_EXCEPT(RenderingAPIException, "Unable to upload vertex shader float parameters");
  331. }
  332. }
  333. }
  334. }
  335. // bind ints
  336. {
  337. for (GpuLogicalIndexUseMap::const_iterator i = intLogical->map.begin();
  338. i != intLogical->map.end(); ++i)
  339. {
  340. if (i->second.variability & variability)
  341. {
  342. UINT32 logicalIndex = i->first;
  343. const int* pInt = params->getIntPointer(i->second.physicalIndex);
  344. UINT32 slotCount = i->second.currentSize / 4;
  345. assert (i->second.currentSize % 4 == 0 && "Should not have any "
  346. "elements less than 4 wide for D3D9");
  347. if (FAILED(hr = getActiveD3D9Device()->SetVertexShaderConstantI(
  348. static_cast<UINT>(logicalIndex), pInt, static_cast<UINT>(slotCount))))
  349. {
  350. CM_EXCEPT(RenderingAPIException, "Unable to upload vertex shader int parameters");
  351. }
  352. }
  353. }
  354. }
  355. break;
  356. case GPT_FRAGMENT_PROGRAM:
  357. mActiveFragmentGpuProgramParameters = params;
  358. {
  359. for (GpuLogicalIndexUseMap::const_iterator i = floatLogical->map.begin();
  360. i != floatLogical->map.end(); ++i)
  361. {
  362. if (i->second.variability & variability)
  363. {
  364. UINT32 logicalIndex = i->first;
  365. const float* pFloat = params->getFloatPointer(i->second.physicalIndex);
  366. UINT32 slotCount = i->second.currentSize / 4;
  367. assert (i->second.currentSize % 4 == 0 && "Should not have any "
  368. "elements less than 4 wide for D3D9");
  369. if (FAILED(hr = getActiveD3D9Device()->SetPixelShaderConstantF(
  370. static_cast<UINT>(logicalIndex), pFloat, static_cast<UINT>(slotCount))))
  371. {
  372. CM_EXCEPT(RenderingAPIException, "Unable to upload pixel shader float parameters");
  373. }
  374. }
  375. }
  376. }
  377. // bind ints
  378. {
  379. for (GpuLogicalIndexUseMap::const_iterator i = intLogical->map.begin();
  380. i != intLogical->map.end(); ++i)
  381. {
  382. if (i->second.variability & variability)
  383. {
  384. UINT32 logicalIndex = i->first;
  385. const int* pInt = params->getIntPointer(i->second.physicalIndex);
  386. UINT32 slotCount = i->second.currentSize / 4;
  387. assert (i->second.currentSize % 4 == 0 && "Should not have any "
  388. "elements less than 4 wide for D3D9");
  389. if (FAILED(hr = getActiveD3D9Device()->SetPixelShaderConstantI(
  390. static_cast<UINT>(logicalIndex), pInt, static_cast<UINT>(slotCount))))
  391. {
  392. CM_EXCEPT(RenderingAPIException, "Unable to upload pixel shader int parameters");
  393. }
  394. }
  395. }
  396. }
  397. break;
  398. };
  399. }
  400. //---------------------------------------------------------------------
  401. void D3D9RenderSystem::destroyRenderTarget(RenderTarget* renderTarget)
  402. {
  403. THROW_IF_NOT_RENDER_THREAD;
  404. D3D9RenderWindow* renderWindow = NULL;
  405. // Check render windows
  406. D3D9RenderWindowList::iterator sw;
  407. for (sw = mRenderWindows.begin(); sw != mRenderWindows.end(); ++sw)
  408. {
  409. if ((*sw) == renderTarget)
  410. {
  411. renderWindow = (*sw);
  412. mRenderWindows.erase(sw);
  413. break;
  414. }
  415. }
  416. // Do the real removal
  417. RenderSystem::destroyRenderTarget(renderTarget);
  418. }
  419. //---------------------------------------------------------------------
  420. void D3D9RenderSystem::setTexture( UINT16 stage, bool enabled, const TexturePtr& tex )
  421. {
  422. THROW_IF_NOT_RENDER_THREAD;
  423. HRESULT hr;
  424. D3D9TexturePtr dt = std::static_pointer_cast<D3D9Texture>(tex);
  425. if (enabled && (dt != nullptr))
  426. {
  427. IDirect3DBaseTexture9 *pTex = dt->getTexture_internal();
  428. if (mTexStageDesc[stage].pTex != pTex)
  429. {
  430. hr = getActiveD3D9Device()->SetTexture(static_cast<DWORD>(stage), pTex);
  431. if( hr != S_OK )
  432. {
  433. String str = "Unable to set texture in D3D9";
  434. CM_EXCEPT(RenderingAPIException, str);
  435. }
  436. // set stage desc.
  437. mTexStageDesc[stage].pTex = pTex;
  438. mTexStageDesc[stage].texType = D3D9Mappings::get(dt->getTextureType());
  439. // Set gamma now too
  440. if (dt->isHardwareGammaReadToBeUsed())
  441. {
  442. __SetSamplerState(static_cast<DWORD>(stage), D3DSAMP_SRGBTEXTURE, TRUE);
  443. }
  444. else
  445. {
  446. __SetSamplerState(static_cast<DWORD>(stage), D3DSAMP_SRGBTEXTURE, FALSE);
  447. }
  448. }
  449. }
  450. else
  451. {
  452. if (mTexStageDesc[stage].pTex != 0)
  453. {
  454. hr = getActiveD3D9Device()->SetTexture(static_cast<DWORD>(stage), 0);
  455. if( hr != S_OK )
  456. {
  457. String str = "Unable to disable texture '" + toString(stage) + "' in D3D9";
  458. CM_EXCEPT(RenderingAPIException, str);
  459. }
  460. }
  461. hr = __SetTextureStageState(static_cast<DWORD>(stage), D3DTSS_COLOROP, D3DTOP_DISABLE);
  462. if( hr != S_OK )
  463. {
  464. String str = "Unable to disable texture '" + toString(stage) + "' in D3D9";
  465. CM_EXCEPT(RenderingAPIException, str);
  466. }
  467. // set stage desc. to defaults
  468. mTexStageDesc[stage].pTex = 0;
  469. mTexStageDesc[stage].coordIndex = 0;
  470. mTexStageDesc[stage].texType = D3D9Mappings::D3D_TEX_TYPE_NORMAL;
  471. }
  472. }
  473. //---------------------------------------------------------------------
  474. void D3D9RenderSystem::disableTextureUnit(UINT16 texUnit)
  475. {
  476. THROW_IF_NOT_RENDER_THREAD;
  477. RenderSystem::disableTextureUnit(texUnit);
  478. }
  479. //-----------------------------------------------------------------------
  480. void D3D9RenderSystem::setSamplerState(UINT16 unit, const SamplerState& state)
  481. {
  482. THROW_IF_NOT_RENDER_THREAD;
  483. // Set texture layer filtering
  484. setTextureFiltering(unit, FT_MIN, state.getTextureFiltering(FT_MIN));
  485. setTextureFiltering(unit, FT_MAG, state.getTextureFiltering(FT_MAG));
  486. setTextureFiltering(unit, FT_MIP, state.getTextureFiltering(FT_MIP));
  487. // Set texture layer filtering
  488. setTextureAnisotropy(unit, state.getTextureAnisotropy());
  489. // Set mipmap biasing
  490. setTextureMipmapBias(unit, state.getTextureMipmapBias());
  491. // Texture addressing mode
  492. const UVWAddressingMode& uvw = state.getTextureAddressingMode();
  493. setTextureAddressingMode(unit, uvw);
  494. // Set border color
  495. setTextureBorderColor(unit, state.getBorderColor(0));
  496. }
  497. //-----------------------------------------------------------------------
  498. void D3D9RenderSystem::setBlendState(const BlendState& blendState)
  499. {
  500. THROW_IF_NOT_RENDER_THREAD;
  501. // Alpha to coverage
  502. setAlphaToCoverage(blendState.getAlphaToCoverageEnabled());
  503. // Blend states
  504. // DirectX 9 doesn't allow us to specify blend state per render target, so we just use the first one.
  505. if(blendState.getBlendEnabled(0))
  506. {
  507. setSceneBlending(blendState.getSrcBlend(0), blendState.getDstBlend(0), blendState.getAlphaSrcBlend(0), blendState.getAlphaDstBlend(0)
  508. , blendState.getBlendOperation(0), blendState.getAlphaBlendOperation(0));
  509. }
  510. else
  511. {
  512. setSceneBlending(SBF_ONE, SBF_ZERO, SBO_ADD);
  513. }
  514. // Color write mask
  515. UINT8 writeMask = blendState.getRenderTargetWriteMask(0);
  516. setColorBufferWriteEnabled((writeMask & 0x1) != 0, (writeMask & 0x2) != 0, (writeMask & 0x4) != 0, (writeMask & 0x8) != 0);
  517. }
  518. //----------------------------------------------------------------------
  519. void D3D9RenderSystem::setRasterizerState(const RasterizerState& rasterizerState)
  520. {
  521. THROW_IF_NOT_RENDER_THREAD;
  522. setDepthBias((float)rasterizerState.getDepthBias(), rasterizerState.getSlopeScaledDepthBias());
  523. setCullingMode(rasterizerState.getCullMode());
  524. setPolygonMode(rasterizerState.getPolygonMode());
  525. setScissorTestEnable(rasterizerState.getScissorEnable());
  526. }
  527. //----------------------------------------------------------------------
  528. void D3D9RenderSystem::setDepthStencilState(const DepthStencilState& depthStencilState)
  529. {
  530. THROW_IF_NOT_RENDER_THREAD;
  531. // Set stencil buffer options
  532. setStencilCheckEnabled(depthStencilState.getStencilEnable());
  533. setStencilBufferOperations(depthStencilState.getStencilFrontFailOp(), depthStencilState.getStencilFrontZFailOp(), depthStencilState.getStencilFrontPassOp(), true);
  534. setStencilBufferFunc(depthStencilState.getStencilFrontCompFunc(), true);
  535. setStencilBufferOperations(depthStencilState.getStencilBackFailOp(), depthStencilState.getStencilBackZFailOp(), depthStencilState.getStencilBackPassOp(), false);
  536. setStencilBufferFunc(depthStencilState.getStencilBackCompFunc(), false);
  537. setStencilBufferReadMask(depthStencilState.getStencilReadMask());
  538. setStencilBufferWriteMask(depthStencilState.getStencilWriteMask());
  539. // Set depth buffer options
  540. setDepthBufferCheckEnabled(depthStencilState.getDepthReadEnable());
  541. setDepthBufferWriteEnabled(depthStencilState.getDepthWriteEnable());
  542. setDepthBufferFunction(depthStencilState.getDepthComparisonFunc());
  543. }
  544. //----------------------------------------------------------------------
  545. void D3D9RenderSystem::setStencilRefValue(UINT32 refValue)
  546. {
  547. THROW_IF_NOT_RENDER_THREAD;
  548. HRESULT hr = __SetRenderState(D3DRS_STENCILREF, refValue);
  549. if (FAILED(hr))
  550. CM_EXCEPT(RenderingAPIException, "Error setting stencil buffer reference value.");
  551. }
  552. //---------------------------------------------------------------------
  553. void D3D9RenderSystem::setTextureMipmapBias(UINT16 unit, float bias)
  554. {
  555. THROW_IF_NOT_RENDER_THREAD;
  556. if (mCurrentCapabilities->hasCapability(RSC_MIPMAP_LOD_BIAS))
  557. {
  558. // ugh - have to pass float data through DWORD with no conversion
  559. HRESULT hr = __SetSamplerState(static_cast<DWORD>(unit), D3DSAMP_MIPMAPLODBIAS,
  560. *(DWORD*)&bias);
  561. if(FAILED(hr))
  562. CM_EXCEPT(RenderingAPIException, "Unable to set texture mipmap bias");
  563. }
  564. }
  565. //---------------------------------------------------------------------
  566. void D3D9RenderSystem::setTextureAddressingMode( UINT16 stage,
  567. const UVWAddressingMode& uvw )
  568. {
  569. THROW_IF_NOT_RENDER_THREAD;
  570. HRESULT hr;
  571. if( FAILED( hr = __SetSamplerState( static_cast<DWORD>(stage), D3DSAMP_ADDRESSU, D3D9Mappings::get(uvw.u, mDeviceManager->getActiveDevice()->getD3D9DeviceCaps()) ) ) )
  572. CM_EXCEPT(RenderingAPIException, "Failed to set texture addressing mode for U" );
  573. if( FAILED( hr = __SetSamplerState( static_cast<DWORD>(stage), D3DSAMP_ADDRESSV, D3D9Mappings::get(uvw.v, mDeviceManager->getActiveDevice()->getD3D9DeviceCaps()) ) ) )
  574. CM_EXCEPT(RenderingAPIException, "Failed to set texture addressing mode for V");
  575. if( FAILED( hr = __SetSamplerState( static_cast<DWORD>(stage), D3DSAMP_ADDRESSW, D3D9Mappings::get(uvw.w, mDeviceManager->getActiveDevice()->getD3D9DeviceCaps()) ) ) )
  576. CM_EXCEPT(RenderingAPIException, "Failed to set texture addressing mode for W");
  577. }
  578. //-----------------------------------------------------------------------------
  579. void D3D9RenderSystem::setTextureBorderColor(UINT16 stage,
  580. const Color& colour)
  581. {
  582. THROW_IF_NOT_RENDER_THREAD;
  583. HRESULT hr;
  584. if( FAILED( hr = __SetSamplerState( static_cast<DWORD>(stage), D3DSAMP_BORDERCOLOR, colour.getAsARGB()) ) )
  585. CM_EXCEPT(RenderingAPIException, "Failed to set texture border colour");
  586. }
  587. //---------------------------------------------------------------------
  588. void D3D9RenderSystem::setSceneBlending( SceneBlendFactor sourceFactor, SceneBlendFactor destFactor, SceneBlendOperation op )
  589. {
  590. THROW_IF_NOT_RENDER_THREAD;
  591. HRESULT hr;
  592. if( sourceFactor == SBF_ONE && destFactor == SBF_ZERO)
  593. {
  594. if (FAILED(hr = __SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE)))
  595. CM_EXCEPT(RenderingAPIException, "Failed to set alpha blending option");
  596. }
  597. else
  598. {
  599. if (FAILED(hr = __SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE)))
  600. CM_EXCEPT(RenderingAPIException, "Failed to set alpha blending option");
  601. if (FAILED(hr = __SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE)))
  602. CM_EXCEPT(RenderingAPIException, "Failed to set separate alpha blending option");
  603. if( FAILED( hr = __SetRenderState( D3DRS_SRCBLEND, D3D9Mappings::get(sourceFactor) ) ) )
  604. CM_EXCEPT(RenderingAPIException, "Failed to set source blend");
  605. if( FAILED( hr = __SetRenderState( D3DRS_DESTBLEND, D3D9Mappings::get(destFactor) ) ) )
  606. CM_EXCEPT(RenderingAPIException, "Failed to set destination blend");
  607. }
  608. if (FAILED(hr = __SetRenderState(D3DRS_BLENDOP, D3D9Mappings::get(op))))
  609. CM_EXCEPT(RenderingAPIException, "Failed to set scene blending operation option");
  610. if (FAILED(hr = __SetRenderState(D3DRS_BLENDOPALPHA, D3D9Mappings::get(op))))
  611. CM_EXCEPT(RenderingAPIException, "Failed to set scene blending operation option");
  612. }
  613. //---------------------------------------------------------------------
  614. void D3D9RenderSystem::setSceneBlending( SceneBlendFactor sourceFactor, SceneBlendFactor destFactor, SceneBlendFactor sourceFactorAlpha,
  615. SceneBlendFactor destFactorAlpha, SceneBlendOperation op, SceneBlendOperation alphaOp )
  616. {
  617. THROW_IF_NOT_RENDER_THREAD;
  618. HRESULT hr;
  619. if( sourceFactor == SBF_ONE && destFactor == SBF_ZERO &&
  620. sourceFactorAlpha == SBF_ONE && destFactorAlpha == SBF_ZERO)
  621. {
  622. if (FAILED(hr = __SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE)))
  623. CM_EXCEPT(RenderingAPIException, "Failed to set alpha blending option");
  624. }
  625. else
  626. {
  627. if (FAILED(hr = __SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE)))
  628. CM_EXCEPT(RenderingAPIException, "Failed to set alpha blending option");
  629. if (FAILED(hr = __SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE)))
  630. CM_EXCEPT(RenderingAPIException, "Failed to set separate alpha blending option");
  631. if( FAILED( hr = __SetRenderState( D3DRS_SRCBLEND, D3D9Mappings::get(sourceFactor) ) ) )
  632. CM_EXCEPT(RenderingAPIException, "Failed to set source blend");
  633. if( FAILED( hr = __SetRenderState( D3DRS_DESTBLEND, D3D9Mappings::get(destFactor) ) ) )
  634. CM_EXCEPT(RenderingAPIException, "Failed to set destination blend");
  635. if( FAILED( hr = __SetRenderState( D3DRS_SRCBLENDALPHA, D3D9Mappings::get(sourceFactorAlpha) ) ) )
  636. CM_EXCEPT(RenderingAPIException, "Failed to set alpha source blend");
  637. if( FAILED( hr = __SetRenderState( D3DRS_DESTBLENDALPHA, D3D9Mappings::get(destFactorAlpha) ) ) )
  638. CM_EXCEPT(RenderingAPIException, "Failed to set alpha destination blend");
  639. }
  640. if (FAILED(hr = __SetRenderState(D3DRS_BLENDOP, D3D9Mappings::get(op))))
  641. CM_EXCEPT(RenderingAPIException, "Failed to set scene blending operation option");
  642. if (FAILED(hr = __SetRenderState(D3DRS_BLENDOPALPHA, D3D9Mappings::get(alphaOp))))
  643. CM_EXCEPT(RenderingAPIException, "Failed to set alpha scene blending operation option");
  644. }
  645. //---------------------------------------------------------------------
  646. void D3D9RenderSystem::setAlphaTest(CompareFunction func, unsigned char value)
  647. {
  648. THROW_IF_NOT_RENDER_THREAD;
  649. HRESULT hr;
  650. if (func != CMPF_ALWAYS_PASS)
  651. {
  652. if( FAILED( hr = __SetRenderState( D3DRS_ALPHATESTENABLE, TRUE ) ) )
  653. CM_EXCEPT(RenderingAPIException, "Failed to enable alpha testing");
  654. }
  655. else
  656. {
  657. if( FAILED( hr = __SetRenderState( D3DRS_ALPHATESTENABLE, FALSE ) ) )
  658. CM_EXCEPT(RenderingAPIException, "Failed to disable alpha testing");
  659. }
  660. // Set always just be sure
  661. if( FAILED( hr = __SetRenderState( D3DRS_ALPHAFUNC, D3D9Mappings::get(func) ) ) )
  662. CM_EXCEPT(RenderingAPIException, "Failed to set alpha reject function");
  663. if( FAILED( hr = __SetRenderState( D3DRS_ALPHAREF, value ) ) )
  664. CM_EXCEPT(RenderingAPIException, "Failed to set render state D3DRS_ALPHAREF");
  665. }
  666. //---------------------------------------------------------------------
  667. void D3D9RenderSystem::setAlphaToCoverage(bool enable)
  668. {
  669. THROW_IF_NOT_RENDER_THREAD;
  670. HRESULT hr;
  671. static bool lasta2c = false;
  672. // Alpha to coverage
  673. if (getCapabilities()->hasCapability(RSC_ALPHA_TO_COVERAGE))
  674. {
  675. // Vendor-specific hacks on renderstate, gotta love 'em
  676. if (getCapabilities()->getVendor() == GPU_NVIDIA)
  677. {
  678. if (enable)
  679. {
  680. if( FAILED( hr = __SetRenderState( D3DRS_ADAPTIVETESS_Y, (D3DFORMAT)MAKEFOURCC('A', 'T', 'O', 'C') ) ) )
  681. CM_EXCEPT(RenderingAPIException, "Failed to set alpha to coverage option");
  682. }
  683. else
  684. {
  685. if( FAILED( hr = __SetRenderState( D3DRS_ADAPTIVETESS_Y, D3DFMT_UNKNOWN ) ) )
  686. CM_EXCEPT(RenderingAPIException, "Failed to set alpha to coverage option");
  687. }
  688. }
  689. else if ((getCapabilities()->getVendor() == GPU_ATI))
  690. {
  691. if (enable)
  692. {
  693. if( FAILED( hr = __SetRenderState( D3DRS_POINTSIZE, MAKEFOURCC('A','2','M','1') ) ) )
  694. CM_EXCEPT(RenderingAPIException, "Failed to set alpha to coverage option");
  695. }
  696. else
  697. {
  698. // discovered this through trial and error, seems to work
  699. if( FAILED( hr = __SetRenderState( D3DRS_POINTSIZE, MAKEFOURCC('A','2','M','0') ) ) )
  700. CM_EXCEPT(RenderingAPIException, "Failed to set alpha to coverage option");
  701. }
  702. }
  703. lasta2c = enable;
  704. }
  705. }
  706. //---------------------------------------------------------------------
  707. void D3D9RenderSystem::setCullingMode( CullingMode mode )
  708. {
  709. THROW_IF_NOT_RENDER_THREAD;
  710. mCullingMode = mode;
  711. HRESULT hr;
  712. bool flip = ((mActiveRenderTarget->requiresTextureFlipping() && !mInvertVertexWinding) ||
  713. (!mActiveRenderTarget->requiresTextureFlipping() && mInvertVertexWinding));
  714. if( FAILED (hr = __SetRenderState(D3DRS_CULLMODE,
  715. D3D9Mappings::get(mode, flip))) )
  716. CM_EXCEPT(RenderingAPIException, "Failed to set culling mode");
  717. }
  718. //---------------------------------------------------------------------
  719. void D3D9RenderSystem::setDepthBufferParams( bool depthTest, bool depthWrite, CompareFunction depthFunction )
  720. {
  721. THROW_IF_NOT_RENDER_THREAD;
  722. setDepthBufferCheckEnabled( depthTest );
  723. setDepthBufferWriteEnabled( depthWrite );
  724. setDepthBufferFunction( depthFunction );
  725. }
  726. //---------------------------------------------------------------------
  727. void D3D9RenderSystem::setDepthBufferCheckEnabled( bool enabled )
  728. {
  729. THROW_IF_NOT_RENDER_THREAD;
  730. HRESULT hr;
  731. if( enabled )
  732. hr = __SetRenderState( D3DRS_ZENABLE, D3DZB_TRUE );
  733. else
  734. hr = __SetRenderState( D3DRS_ZENABLE, D3DZB_FALSE );
  735. if( FAILED( hr ) )
  736. CM_EXCEPT(RenderingAPIException, "Error setting depth buffer test state");
  737. }
  738. //---------------------------------------------------------------------
  739. void D3D9RenderSystem::setDepthBufferWriteEnabled( bool enabled )
  740. {
  741. THROW_IF_NOT_RENDER_THREAD;
  742. HRESULT hr;
  743. if( FAILED( hr = __SetRenderState( D3DRS_ZWRITEENABLE, enabled ) ) )
  744. CM_EXCEPT(RenderingAPIException, "Error setting depth buffer write state");
  745. }
  746. //---------------------------------------------------------------------
  747. void D3D9RenderSystem::setDepthBufferFunction( CompareFunction func )
  748. {
  749. THROW_IF_NOT_RENDER_THREAD;
  750. HRESULT hr;
  751. if( FAILED( hr = __SetRenderState( D3DRS_ZFUNC, D3D9Mappings::get(func) ) ) )
  752. CM_EXCEPT(RenderingAPIException, "Error setting depth buffer test function");
  753. }
  754. //---------------------------------------------------------------------
  755. void D3D9RenderSystem::setDepthBias(float constantBias, float slopeScaleBias)
  756. {
  757. THROW_IF_NOT_RENDER_THREAD;
  758. if ((mDeviceManager->getActiveDevice()->getD3D9DeviceCaps().RasterCaps & D3DPRASTERCAPS_DEPTHBIAS) != 0)
  759. {
  760. // Negate bias since D3D is backward
  761. // D3D also expresses the constant bias as an absolute value, rather than
  762. // relative to minimum depth unit, so scale to fit
  763. constantBias = -constantBias / 250000.0f;
  764. HRESULT hr = __SetRenderState(D3DRS_DEPTHBIAS, FLOAT2DWORD(constantBias));
  765. if (FAILED(hr))
  766. CM_EXCEPT(RenderingAPIException, "Error setting constant depth bias");
  767. }
  768. if ((mDeviceManager->getActiveDevice()->getD3D9DeviceCaps().RasterCaps & D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS) != 0)
  769. {
  770. // Negate bias since D3D is backward
  771. slopeScaleBias = -slopeScaleBias;
  772. HRESULT hr = __SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, FLOAT2DWORD(slopeScaleBias));
  773. if (FAILED(hr))
  774. CM_EXCEPT(RenderingAPIException, "Error setting slope scale depth bias");
  775. }
  776. }
  777. //---------------------------------------------------------------------
  778. void D3D9RenderSystem::setColorBufferWriteEnabled(bool red, bool green,
  779. bool blue, bool alpha)
  780. {
  781. THROW_IF_NOT_RENDER_THREAD;
  782. DWORD val = 0;
  783. if (red)
  784. val |= D3DCOLORWRITEENABLE_RED;
  785. if (green)
  786. val |= D3DCOLORWRITEENABLE_GREEN;
  787. if (blue)
  788. val |= D3DCOLORWRITEENABLE_BLUE;
  789. if (alpha)
  790. val |= D3DCOLORWRITEENABLE_ALPHA;
  791. HRESULT hr = __SetRenderState(D3DRS_COLORWRITEENABLE, val);
  792. if (FAILED(hr))
  793. CM_EXCEPT(RenderingAPIException, "Error setting colour write enable flags");
  794. }
  795. //---------------------------------------------------------------------
  796. void D3D9RenderSystem::setPolygonMode(PolygonMode level)
  797. {
  798. THROW_IF_NOT_RENDER_THREAD;
  799. HRESULT hr = __SetRenderState(D3DRS_FILLMODE, D3D9Mappings::get(level));
  800. if (FAILED(hr))
  801. CM_EXCEPT(RenderingAPIException, "Error setting polygon mode.");
  802. }
  803. //---------------------------------------------------------------------
  804. void D3D9RenderSystem::setStencilCheckEnabled(bool enabled)
  805. {
  806. THROW_IF_NOT_RENDER_THREAD;
  807. // Allow stencilling
  808. HRESULT hr = __SetRenderState(D3DRS_STENCILENABLE, enabled);
  809. if (FAILED(hr))
  810. CM_EXCEPT(RenderingAPIException, "Error enabling / disabling stencilling.");
  811. if (mCurrentCapabilities->hasCapability(RSC_TWO_SIDED_STENCIL))
  812. {
  813. hr = __SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE);
  814. if (FAILED(hr))
  815. CM_EXCEPT(RenderingAPIException, "Error setting 2-sided stencil mode.");
  816. }
  817. else
  818. {
  819. hr = __SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
  820. if (FAILED(hr))
  821. CM_EXCEPT(RenderingAPIException, "Error setting 1-sided stencil mode.");
  822. }
  823. }
  824. //---------------------------------------------------------------------
  825. void D3D9RenderSystem::setStencilBufferOperations(StencilOperation stencilFailOp, StencilOperation depthFailOp, StencilOperation passOp, bool ccw)
  826. {
  827. THROW_IF_NOT_RENDER_THREAD;
  828. HRESULT hr;
  829. // 2-sided operation
  830. if (ccw)
  831. {
  832. // fail op
  833. hr = __SetRenderState(D3DRS_CCW_STENCILFAIL, D3D9Mappings::get(stencilFailOp, mInvertVertexWinding));
  834. if (FAILED(hr))
  835. CM_EXCEPT(RenderingAPIException, "Error setting stencil fail operation (ccw).");
  836. // depth fail op
  837. hr = __SetRenderState(D3DRS_CCW_STENCILZFAIL, D3D9Mappings::get(depthFailOp, mInvertVertexWinding));
  838. if (FAILED(hr))
  839. CM_EXCEPT(RenderingAPIException, "Error setting stencil depth fail operation (ccw).");
  840. // pass op
  841. hr = __SetRenderState(D3DRS_CCW_STENCILPASS, D3D9Mappings::get(passOp, mInvertVertexWinding));
  842. if (FAILED(hr))
  843. CM_EXCEPT(RenderingAPIException, "Error setting stencil pass operation (ccw).");
  844. }
  845. else
  846. {
  847. // fail op
  848. hr = __SetRenderState(D3DRS_STENCILFAIL, D3D9Mappings::get(stencilFailOp, !mInvertVertexWinding));
  849. if (FAILED(hr))
  850. CM_EXCEPT(RenderingAPIException, "Error setting stencil fail operation (cw).");
  851. // depth fail op
  852. hr = __SetRenderState(D3DRS_STENCILZFAIL, D3D9Mappings::get(depthFailOp, !mInvertVertexWinding));
  853. if (FAILED(hr))
  854. CM_EXCEPT(RenderingAPIException, "Error setting stencil depth fail operation (cw).");
  855. // pass op
  856. hr = __SetRenderState(D3DRS_STENCILPASS, D3D9Mappings::get(passOp, !mInvertVertexWinding));
  857. if (FAILED(hr))
  858. CM_EXCEPT(RenderingAPIException, "Error setting stencil pass operation (cw).");
  859. }
  860. }
  861. //---------------------------------------------------------------------
  862. void D3D9RenderSystem::setStencilBufferFunc(CompareFunction func, bool ccw)
  863. {
  864. HRESULT hr;
  865. if(ccw)
  866. hr = __SetRenderState(D3DRS_CCW_STENCILFUNC, D3D9Mappings::get(func));
  867. else
  868. hr = __SetRenderState(D3DRS_STENCILFUNC, D3D9Mappings::get(func));
  869. if (FAILED(hr))
  870. CM_EXCEPT(RenderingAPIException, "Error setting stencil buffer test function.");
  871. }
  872. //---------------------------------------------------------------------
  873. void D3D9RenderSystem::setStencilBufferReadMask(UINT32 mask)
  874. {
  875. HRESULT hr = __SetRenderState(D3DRS_STENCILMASK, mask);
  876. if (FAILED(hr))
  877. CM_EXCEPT(RenderingAPIException, "Error setting stencil buffer mask.");
  878. }
  879. //--------------------------------------------------------------------
  880. void D3D9RenderSystem::setStencilBufferWriteMask(UINT32 mask)
  881. {
  882. HRESULT hr = __SetRenderState(D3DRS_STENCILWRITEMASK, mask);
  883. if (FAILED(hr))
  884. CM_EXCEPT(RenderingAPIException, "Error setting stencil buffer write mask.");
  885. }
  886. //---------------------------------------------------------------------
  887. void D3D9RenderSystem::setTextureFiltering(UINT16 unit, FilterType ftype,
  888. FilterOptions filter)
  889. {
  890. THROW_IF_NOT_RENDER_THREAD;
  891. HRESULT hr;
  892. D3D9Mappings::eD3DTexType texType = mTexStageDesc[unit].texType;
  893. hr = __SetSamplerState( static_cast<DWORD>(unit), D3D9Mappings::get(ftype),
  894. D3D9Mappings::get(ftype, filter, mDeviceManager->getActiveDevice()->getD3D9DeviceCaps(), texType));
  895. if (FAILED(hr))
  896. CM_EXCEPT(RenderingAPIException, "Failed to set texture filter ");
  897. }
  898. //---------------------------------------------------------------------
  899. void D3D9RenderSystem::setTextureAnisotropy(UINT16 unit, unsigned int maxAnisotropy)
  900. {
  901. THROW_IF_NOT_RENDER_THREAD;
  902. if (static_cast<DWORD>(maxAnisotropy) > mDeviceManager->getActiveDevice()->getD3D9DeviceCaps().MaxAnisotropy)
  903. maxAnisotropy = mDeviceManager->getActiveDevice()->getD3D9DeviceCaps().MaxAnisotropy;
  904. if (_getCurrentAnisotropy(unit) != maxAnisotropy)
  905. __SetSamplerState( static_cast<DWORD>(unit), D3DSAMP_MAXANISOTROPY, maxAnisotropy );
  906. }
  907. //---------------------------------------------------------------------
  908. void D3D9RenderSystem::setRenderTarget(RenderTarget *target)
  909. {
  910. THROW_IF_NOT_RENDER_THREAD;
  911. mActiveRenderTarget = target;
  912. HRESULT hr;
  913. // If this is called without going through RenderWindow::update, then
  914. // the device will not have been set. Calling it twice is safe, the
  915. // implementation ensures nothing happens if the same device is set twice
  916. if (std::find(mRenderWindows.begin(), mRenderWindows.end(), target) != mRenderWindows.end())
  917. {
  918. D3D9RenderWindow *window = static_cast<D3D9RenderWindow*>(target);
  919. mDeviceManager->setActiveRenderTargetDevice(window->getDevice());
  920. // also make sure we validate the device; if this never went
  921. // through update() it won't be set
  922. window->_validateDevice();
  923. }
  924. // Retrieve render surfaces (up to CM_MAX_MULTIPLE_RENDER_TARGETS)
  925. IDirect3DSurface9* pBack[CM_MAX_MULTIPLE_RENDER_TARGETS];
  926. memset(pBack, 0, sizeof(pBack));
  927. target->getCustomAttribute_internal( "DDBACKBUFFER", &pBack );
  928. if (!pBack[0])
  929. return;
  930. IDirect3DSurface9* pDepth = NULL;
  931. //Check if we saved a depth buffer for this target
  932. TargetDepthStencilMap::iterator savedTexture = mCheckedOutTextures.find(target);
  933. if (savedTexture != mCheckedOutTextures.end())
  934. {
  935. pDepth = savedTexture->second.surface;
  936. }
  937. if (!pDepth)
  938. target->getCustomAttribute_internal( "D3DZBUFFER", &pDepth );
  939. if (!pDepth)
  940. {
  941. /// No depth buffer provided, use our own
  942. /// Request a depth stencil that is compatible with the format, multisample type and
  943. /// dimensions of the render target.
  944. D3DSURFACE_DESC srfDesc;
  945. if(FAILED(pBack[0]->GetDesc(&srfDesc)))
  946. return; // ?
  947. pDepth = getDepthStencilFor(srfDesc.Format, srfDesc.MultiSampleType, srfDesc.MultiSampleQuality, srfDesc.Width, srfDesc.Height);
  948. }
  949. // Bind render targets
  950. UINT32 count = mCurrentCapabilities->getNumMultiRenderTargets();
  951. for(UINT32 x=0; x<count; ++x)
  952. {
  953. hr = getActiveD3D9Device()->SetRenderTarget(x, pBack[x]);
  954. if (FAILED(hr))
  955. {
  956. String msg = DXGetErrorDescription(hr);
  957. CM_EXCEPT(RenderingAPIException, "Failed to setRenderTarget : " + msg);
  958. }
  959. }
  960. hr = getActiveD3D9Device()->SetDepthStencilSurface(pDepth);
  961. if (FAILED(hr))
  962. {
  963. String msg = DXGetErrorDescription(hr);
  964. CM_EXCEPT(RenderingAPIException, "Failed to setDepthStencil : " + msg);
  965. }
  966. }
  967. //---------------------------------------------------------------------
  968. void D3D9RenderSystem::setViewport(const Viewport& vp)
  969. {
  970. THROW_IF_NOT_RENDER_THREAD;
  971. mActiveViewport = vp;
  972. // ok, it's different, time to set render target and viewport params
  973. D3DVIEWPORT9 d3dvp;
  974. HRESULT hr;
  975. // Set render target
  976. RenderTarget* target = vp.getTarget();
  977. setRenderTarget(target);
  978. setCullingMode( mCullingMode );
  979. // set viewport dimensions
  980. d3dvp.X = vp.getActualLeft();
  981. d3dvp.Y = vp.getActualTop();
  982. d3dvp.Width = vp.getActualWidth();
  983. d3dvp.Height = vp.getActualHeight();
  984. if (target->requiresTextureFlipping())
  985. {
  986. // Convert "top-left" to "bottom-left"
  987. d3dvp.Y = target->getHeight() - d3dvp.Height - d3dvp.Y;
  988. }
  989. // Z-values from 0.0 to 1.0 (TODO: standardise with OpenGL)
  990. d3dvp.MinZ = 0.0f;
  991. d3dvp.MaxZ = 1.0f;
  992. if( FAILED( hr = getActiveD3D9Device()->SetViewport( &d3dvp ) ) )
  993. CM_EXCEPT(RenderingAPIException, "Failed to set viewport.");
  994. // Set sRGB write mode
  995. __SetRenderState(D3DRS_SRGBWRITEENABLE, target->isHardwareGammaEnabled());
  996. }
  997. //---------------------------------------------------------------------
  998. void D3D9RenderSystem::beginFrame()
  999. {
  1000. THROW_IF_NOT_RENDER_THREAD;
  1001. HRESULT hr;
  1002. if( FAILED( hr = getActiveD3D9Device()->BeginScene() ) )
  1003. {
  1004. String msg = DXGetErrorDescription(hr);
  1005. CM_EXCEPT(RenderingAPIException, "Error beginning frame :" + msg);
  1006. }
  1007. mLastVertexSourceCount = 0;
  1008. // Clear left overs of previous viewport.
  1009. // I.E: Viewport A can use 3 different textures and light states
  1010. // When trying to render viewport B these settings should be cleared, otherwise
  1011. // graphical artifacts might occur.
  1012. mDeviceManager->getActiveDevice()->clearDeviceStreams();
  1013. }
  1014. //---------------------------------------------------------------------
  1015. void D3D9RenderSystem::endFrame()
  1016. {
  1017. THROW_IF_NOT_RENDER_THREAD;
  1018. HRESULT hr;
  1019. if( FAILED( hr = getActiveD3D9Device()->EndScene() ) )
  1020. CM_EXCEPT(RenderingAPIException, "Error ending frame");
  1021. mDeviceManager->destroyInactiveRenderDevices();
  1022. }
  1023. //---------------------------------------------------------------------
  1024. void D3D9RenderSystem::setVertexDeclaration(VertexDeclarationPtr decl)
  1025. {
  1026. THROW_IF_NOT_RENDER_THREAD;
  1027. HRESULT hr;
  1028. std::shared_ptr<D3D9VertexDeclaration> d3ddecl =
  1029. std::static_pointer_cast<D3D9VertexDeclaration>(decl);
  1030. if (FAILED(hr = getActiveD3D9Device()->SetVertexDeclaration(d3ddecl->getD3DVertexDeclaration())))
  1031. {
  1032. CM_EXCEPT(RenderingAPIException, "Unable to set D3D9 vertex declaration");
  1033. }
  1034. }
  1035. //---------------------------------------------------------------------
  1036. void D3D9RenderSystem::setVertexBufferBinding(VertexBufferBinding* binding)
  1037. {
  1038. THROW_IF_NOT_RENDER_THREAD;
  1039. HRESULT hr;
  1040. // TODO: attempt to detect duplicates
  1041. const VertexBufferBinding::VertexBufferBindingMap& binds = binding->getBindings();
  1042. VertexBufferBinding::VertexBufferBindingMap::const_iterator i, iend;
  1043. size_t source = 0;
  1044. iend = binds.end();
  1045. for (i = binds.begin(); i != iend; ++i, ++source)
  1046. {
  1047. // Unbind gap sources
  1048. for ( ; source < i->first; ++source)
  1049. {
  1050. hr = getActiveD3D9Device()->SetStreamSource(static_cast<UINT>(source), NULL, 0, 0);
  1051. if (FAILED(hr))
  1052. {
  1053. CM_EXCEPT(RenderingAPIException, "Unable to reset unused D3D9 stream source");
  1054. }
  1055. }
  1056. D3D9HardwareVertexBuffer* d3d9buf =
  1057. static_cast<D3D9HardwareVertexBuffer*>(i->second.get());
  1058. hr = getActiveD3D9Device()->SetStreamSource(
  1059. static_cast<UINT>(source),
  1060. d3d9buf->getD3D9VertexBuffer(),
  1061. 0, // no stream offset, this is handled in _render instead
  1062. static_cast<UINT>(d3d9buf->getVertexSize()) // stride
  1063. );
  1064. if (FAILED(hr))
  1065. {
  1066. CM_EXCEPT(RenderingAPIException, "Unable to set D3D9 stream source for buffer binding");
  1067. }
  1068. }
  1069. // Unbind any unused sources
  1070. for (size_t unused = source; unused < mLastVertexSourceCount; ++unused)
  1071. {
  1072. hr = getActiveD3D9Device()->SetStreamSource(static_cast<UINT>(unused), NULL, 0, 0);
  1073. if (FAILED(hr))
  1074. {
  1075. CM_EXCEPT(RenderingAPIException, "Unable to reset unused D3D9 stream source");
  1076. }
  1077. }
  1078. mLastVertexSourceCount = source;
  1079. }
  1080. //---------------------------------------------------------------------
  1081. void D3D9RenderSystem::render(const RenderOperation& op)
  1082. {
  1083. THROW_IF_NOT_RENDER_THREAD;
  1084. // Exit immediately if there is nothing to render
  1085. // This caused a problem on FireGL 8800
  1086. if (op.vertexData->vertexCount == 0)
  1087. return;
  1088. // Call super class
  1089. RenderSystem::render(op);
  1090. // To think about: possibly remove setVertexDeclaration and
  1091. // setVertexBufferBinding from RenderSystem since the sequence is
  1092. // a bit too D3D9-specific?
  1093. setVertexDeclaration(op.vertexData->vertexDeclaration);
  1094. setVertexBufferBinding(op.vertexData->vertexBufferBinding);
  1095. // Determine rendering operation
  1096. D3DPRIMITIVETYPE primType = D3DPT_TRIANGLELIST;
  1097. DWORD primCount = 0;
  1098. switch( op.operationType )
  1099. {
  1100. case RenderOperation::OT_POINT_LIST:
  1101. primType = D3DPT_POINTLIST;
  1102. primCount = static_cast<DWORD>(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount);
  1103. break;
  1104. case RenderOperation::OT_LINE_LIST:
  1105. primType = D3DPT_LINELIST;
  1106. primCount = static_cast<DWORD>(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) / 2;
  1107. break;
  1108. case RenderOperation::OT_LINE_STRIP:
  1109. primType = D3DPT_LINESTRIP;
  1110. primCount = static_cast<DWORD>(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) - 1;
  1111. break;
  1112. case RenderOperation::OT_TRIANGLE_LIST:
  1113. primType = D3DPT_TRIANGLELIST;
  1114. primCount = static_cast<DWORD>(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) / 3;
  1115. break;
  1116. case RenderOperation::OT_TRIANGLE_STRIP:
  1117. primType = D3DPT_TRIANGLESTRIP;
  1118. primCount = static_cast<DWORD>(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) - 2;
  1119. break;
  1120. case RenderOperation::OT_TRIANGLE_FAN:
  1121. primType = D3DPT_TRIANGLEFAN;
  1122. primCount = static_cast<DWORD>(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) - 2;
  1123. break;
  1124. }
  1125. if (!primCount)
  1126. return;
  1127. // Issue the op
  1128. HRESULT hr;
  1129. if( op.useIndexes )
  1130. {
  1131. D3D9HardwareIndexBuffer* d3dIdxBuf =
  1132. static_cast<D3D9HardwareIndexBuffer*>(op.indexData->indexBuffer.get());
  1133. hr = getActiveD3D9Device()->SetIndices( d3dIdxBuf->getD3DIndexBuffer() );
  1134. if (FAILED(hr))
  1135. {
  1136. CM_EXCEPT(RenderingAPIException, "Failed to set index buffer");
  1137. }
  1138. // do indexed draw operation
  1139. hr = getActiveD3D9Device()->DrawIndexedPrimitive(
  1140. primType,
  1141. static_cast<INT>(op.vertexData->vertexStart),
  1142. 0, // Min vertex index - assume we can go right down to 0
  1143. static_cast<UINT>(op.vertexData->vertexCount),
  1144. static_cast<UINT>(op.indexData->indexStart),
  1145. static_cast<UINT>(primCount)
  1146. );
  1147. }
  1148. else
  1149. {
  1150. // Unindexed, a little simpler!
  1151. hr = getActiveD3D9Device()->DrawPrimitive(
  1152. primType,
  1153. static_cast<UINT>(op.vertexData->vertexStart),
  1154. static_cast<UINT>(primCount)
  1155. );
  1156. }
  1157. if( FAILED( hr ) )
  1158. {
  1159. String msg = DXGetErrorDescription(hr);
  1160. CM_EXCEPT(RenderingAPIException, "Failed to DrawPrimitive : " + msg);
  1161. }
  1162. }
  1163. //---------------------------------------------------------------------
  1164. void D3D9RenderSystem::setScissorRect(UINT32 left, UINT32 top, UINT32 right, UINT32 bottom)
  1165. {
  1166. THROW_IF_NOT_RENDER_THREAD;
  1167. mScissorRect.left = static_cast<LONG>(left);
  1168. mScissorRect.top = static_cast<LONG>(top);
  1169. mScissorRect.bottom = static_cast<LONG>(bottom);
  1170. mScissorRect.right = static_cast<LONG>(right);
  1171. }
  1172. //--------------------------------------------------------------------
  1173. void D3D9RenderSystem::setScissorTestEnable(bool enable)
  1174. {
  1175. THROW_IF_NOT_RENDER_THREAD;
  1176. HRESULT hr;
  1177. if (enable)
  1178. {
  1179. if (FAILED(hr = __SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE)))
  1180. {
  1181. CM_EXCEPT(RenderingAPIException, "Unable to enable scissor rendering state; " + getErrorDescription(hr));
  1182. }
  1183. if (FAILED(hr = getActiveD3D9Device()->SetScissorRect(&mScissorRect)))
  1184. {
  1185. CM_EXCEPT(RenderingAPIException, "Unable to set scissor rectangle; " + getErrorDescription(hr));
  1186. }
  1187. }
  1188. else
  1189. {
  1190. if (FAILED(hr = __SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE)))
  1191. {
  1192. CM_EXCEPT(RenderingAPIException, "Unable to disable scissor rendering state; " + getErrorDescription(hr));
  1193. }
  1194. }
  1195. }
  1196. //---------------------------------------------------------------------
  1197. void D3D9RenderSystem::clearFrameBuffer(unsigned int buffers,
  1198. const Color& colour, float depth, unsigned short stencil)
  1199. {
  1200. THROW_IF_NOT_RENDER_THREAD;
  1201. DWORD flags = 0;
  1202. if (buffers & FBT_COLOUR)
  1203. {
  1204. flags |= D3DCLEAR_TARGET;
  1205. }
  1206. if (buffers & FBT_DEPTH)
  1207. {
  1208. flags |= D3DCLEAR_ZBUFFER;
  1209. }
  1210. // Only try to clear the stencil buffer if supported
  1211. if (buffers & FBT_STENCIL && mCurrentCapabilities->hasCapability(RSC_HWSTENCIL))
  1212. {
  1213. flags |= D3DCLEAR_STENCIL;
  1214. }
  1215. HRESULT hr;
  1216. if( FAILED( hr = getActiveD3D9Device()->Clear(
  1217. 0,
  1218. NULL,
  1219. flags,
  1220. colour.getAsARGB(),
  1221. depth,
  1222. stencil ) ) )
  1223. {
  1224. String msg = DXGetErrorDescription(hr);
  1225. CM_EXCEPT(RenderingAPIException, "Error clearing frame buffer : " + msg);
  1226. }
  1227. }
  1228. //---------------------------------------------------------------------
  1229. IDirect3D9* D3D9RenderSystem::getDirect3D9()
  1230. {
  1231. THROW_IF_NOT_RENDER_THREAD_STATIC;
  1232. IDirect3D9* pDirect3D9 = msD3D9RenderSystem->mpD3D;
  1233. if (pDirect3D9 == NULL)
  1234. {
  1235. CM_EXCEPT(InvalidParametersException, "Direct3D9 interface is NULL !!!");
  1236. }
  1237. return pDirect3D9;
  1238. }
  1239. //---------------------------------------------------------------------
  1240. UINT D3D9RenderSystem::getResourceCreationDeviceCount()
  1241. {
  1242. THROW_IF_NOT_RENDER_THREAD_STATIC;
  1243. D3D9ResourceCreationPolicy creationPolicy = msD3D9RenderSystem->mResourceManager->getCreationPolicy();
  1244. if (creationPolicy == RCP_CREATE_ON_ACTIVE_DEVICE)
  1245. {
  1246. return 1;
  1247. }
  1248. else if (creationPolicy == RCP_CREATE_ON_ALL_DEVICES)
  1249. {
  1250. return msD3D9RenderSystem->mDeviceManager->getDeviceCount();
  1251. }
  1252. CM_EXCEPT(InvalidParametersException, "Invalid resource creation policy !!!" );
  1253. return 0;
  1254. }
  1255. //---------------------------------------------------------------------
  1256. IDirect3DDevice9* D3D9RenderSystem::getResourceCreationDevice(UINT index)
  1257. {
  1258. THROW_IF_NOT_RENDER_THREAD_STATIC;
  1259. D3D9ResourceCreationPolicy creationPolicy = msD3D9RenderSystem->mResourceManager->getCreationPolicy();
  1260. IDirect3DDevice9* d3d9Device = NULL;
  1261. if (creationPolicy == RCP_CREATE_ON_ACTIVE_DEVICE)
  1262. {
  1263. d3d9Device = msD3D9RenderSystem->getActiveD3D9Device();
  1264. }
  1265. else if (creationPolicy == RCP_CREATE_ON_ALL_DEVICES)
  1266. {
  1267. d3d9Device = msD3D9RenderSystem->mDeviceManager->getDevice(index)->getD3D9Device();
  1268. }
  1269. else
  1270. {
  1271. CM_EXCEPT(InvalidParametersException, "Invalid resource creation policy !!!" );
  1272. }
  1273. return d3d9Device;
  1274. }
  1275. //---------------------------------------------------------------------
  1276. IDirect3DDevice9* D3D9RenderSystem::getActiveD3D9Device()
  1277. {
  1278. THROW_IF_NOT_RENDER_THREAD_STATIC;
  1279. D3D9Device* activeDevice = msD3D9RenderSystem->mDeviceManager->getActiveDevice();
  1280. IDirect3DDevice9* d3d9Device;
  1281. d3d9Device = activeDevice->getD3D9Device();
  1282. if (d3d9Device == NULL)
  1283. {
  1284. CM_EXCEPT(InvalidParametersException, "Current d3d9 device is NULL !!!" );
  1285. }
  1286. return d3d9Device;
  1287. }
  1288. //---------------------------------------------------------------------
  1289. D3D9ResourceManager* D3D9RenderSystem::getResourceManager()
  1290. {
  1291. // No need to check if we're on render thread as this is synced up internally
  1292. return msD3D9RenderSystem->mResourceManager;
  1293. }
  1294. //---------------------------------------------------------------------
  1295. D3D9DeviceManager* D3D9RenderSystem::getDeviceManager()
  1296. {
  1297. THROW_IF_NOT_RENDER_THREAD_STATIC;
  1298. return msD3D9RenderSystem->mDeviceManager;
  1299. }
  1300. /************************************************************************/
  1301. /* UTILITY METHODS */
  1302. /************************************************************************/
  1303. //---------------------------------------------------------------------
  1304. float D3D9RenderSystem::getHorizontalTexelOffset()
  1305. {
  1306. // D3D considers the origin to be in the center of a pixel
  1307. return -0.5f;
  1308. }
  1309. //---------------------------------------------------------------------
  1310. float D3D9RenderSystem::getVerticalTexelOffset()
  1311. {
  1312. // D3D considers the origin to be in the center of a pixel
  1313. return -0.5f;
  1314. }
  1315. //---------------------------------------------------------------------
  1316. float D3D9RenderSystem::getMinimumDepthInputValue()
  1317. {
  1318. // Range [0.0f, 1.0f]
  1319. return 0.0f;
  1320. }
  1321. //---------------------------------------------------------------------
  1322. float D3D9RenderSystem::getMaximumDepthInputValue()
  1323. {
  1324. // Range [0.0f, 1.0f]
  1325. // D3D inverts even identity view matrices, so maximum INPUT is -1.0
  1326. return -1.0f;
  1327. }
  1328. //---------------------------------------------------------------------
  1329. VertexElementType D3D9RenderSystem::getColorVertexElementType() const
  1330. {
  1331. return VET_COLOUR_ARGB;
  1332. }
  1333. //---------------------------------------------------------------------
  1334. void D3D9RenderSystem::convertProjectionMatrix(const Matrix4& matrix,
  1335. Matrix4& dest, bool forGpuProgram)
  1336. {
  1337. dest = matrix;
  1338. // Convert depth range from [-1,+1] to [0,1]
  1339. dest[2][0] = (dest[2][0] + dest[3][0]) / 2;
  1340. dest[2][1] = (dest[2][1] + dest[3][1]) / 2;
  1341. dest[2][2] = (dest[2][2] + dest[3][2]) / 2;
  1342. dest[2][3] = (dest[2][3] + dest[3][3]) / 2;
  1343. if (!forGpuProgram)
  1344. {
  1345. // Convert right-handed to left-handed
  1346. dest[0][2] = -dest[0][2];
  1347. dest[1][2] = -dest[1][2];
  1348. dest[2][2] = -dest[2][2];
  1349. dest[3][2] = -dest[3][2];
  1350. }
  1351. }
  1352. /************************************************************************/
  1353. /* PRIVATE */
  1354. /************************************************************************/
  1355. //---------------------------------------------------------------------
  1356. D3D9DriverList* D3D9RenderSystem::getDirect3DDrivers()
  1357. {
  1358. if( !mDriverList )
  1359. mDriverList = new D3D9DriverList();
  1360. return mDriverList;
  1361. }
  1362. //---------------------------------------------------------------------
  1363. bool D3D9RenderSystem::_checkMultiSampleQuality(D3DMULTISAMPLE_TYPE type, DWORD *outQuality, D3DFORMAT format, UINT adapterNum, D3DDEVTYPE deviceType, BOOL fullScreen)
  1364. {
  1365. HRESULT hr;
  1366. hr = mpD3D->CheckDeviceMultiSampleType(
  1367. adapterNum,
  1368. deviceType,
  1369. format,
  1370. fullScreen,
  1371. type,
  1372. outQuality);
  1373. if (SUCCEEDED(hr))
  1374. return true;
  1375. else
  1376. return false;
  1377. }
  1378. //---------------------------------------------------------------------
  1379. void D3D9RenderSystem::initConfigOptions()
  1380. {
  1381. D3D9DriverList* driverList;
  1382. D3D9Driver* driver;
  1383. ConfigOption optDevice;
  1384. ConfigOption optVideoMode;
  1385. ConfigOption optFullScreen;
  1386. ConfigOption optVSync;
  1387. ConfigOption optVSyncInterval;
  1388. ConfigOption optAA;
  1389. ConfigOption optFPUMode;
  1390. ConfigOption optNVPerfHUD;
  1391. ConfigOption optSRGB;
  1392. ConfigOption optResourceCeationPolicy;
  1393. driverList = this->getDirect3DDrivers();
  1394. optDevice.name = "Rendering Device";
  1395. optDevice.currentValue.clear();
  1396. optDevice.possibleValues.clear();
  1397. optDevice.immutable = false;
  1398. optVideoMode.name = "Video Mode";
  1399. optVideoMode.currentValue = "800 x 600 @ 32-bit colour";
  1400. optVideoMode.immutable = false;
  1401. optFullScreen.name = "Full Screen";
  1402. optFullScreen.possibleValues.push_back( "Yes" );
  1403. optFullScreen.possibleValues.push_back( "No" );
  1404. optFullScreen.currentValue = "Yes";
  1405. optFullScreen.immutable = false;
  1406. optResourceCeationPolicy.name = "Resource Creation Policy";
  1407. optResourceCeationPolicy.possibleValues.push_back( "Create on all devices" );
  1408. optResourceCeationPolicy.possibleValues.push_back( "Create on active device" );
  1409. if (mResourceManager->getCreationPolicy() == RCP_CREATE_ON_ACTIVE_DEVICE)
  1410. optResourceCeationPolicy.currentValue = "Create on active device";
  1411. else if (mResourceManager->getCreationPolicy() == RCP_CREATE_ON_ALL_DEVICES)
  1412. optResourceCeationPolicy.currentValue = "Create on all devices";
  1413. else
  1414. optResourceCeationPolicy.currentValue = "N/A";
  1415. optResourceCeationPolicy.immutable = false;
  1416. for( unsigned j=0; j < driverList->count(); j++ )
  1417. {
  1418. driver = driverList->item(j);
  1419. optDevice.possibleValues.push_back( driver->DriverDescription() );
  1420. // Make first one default
  1421. if( j==0 )
  1422. optDevice.currentValue = driver->DriverDescription();
  1423. }
  1424. optVSync.name = "VSync";
  1425. optVSync.immutable = false;
  1426. optVSync.possibleValues.push_back( "Yes" );
  1427. optVSync.possibleValues.push_back( "No" );
  1428. optVSync.currentValue = "No";
  1429. optVSyncInterval.name = "VSync Interval";
  1430. optVSyncInterval.immutable = false;
  1431. optVSyncInterval.possibleValues.push_back( "1" );
  1432. optVSyncInterval.possibleValues.push_back( "2" );
  1433. optVSyncInterval.possibleValues.push_back( "3" );
  1434. optVSyncInterval.possibleValues.push_back( "4" );
  1435. optVSyncInterval.currentValue = "1";
  1436. optAA.name = "FSAA";
  1437. optAA.immutable = false;
  1438. optAA.possibleValues.push_back( "None" );
  1439. optAA.currentValue = "None";
  1440. optFPUMode.name = "Floating-point mode";
  1441. #if OGRE_DOUBLE_PRECISION
  1442. optFPUMode.currentValue = "Consistent";
  1443. #else
  1444. optFPUMode.currentValue = "Fastest";
  1445. #endif
  1446. optFPUMode.possibleValues.clear();
  1447. optFPUMode.possibleValues.push_back("Fastest");
  1448. optFPUMode.possibleValues.push_back("Consistent");
  1449. optFPUMode.immutable = false;
  1450. optNVPerfHUD.currentValue = "No";
  1451. optNVPerfHUD.immutable = false;
  1452. optNVPerfHUD.name = "Allow NVPerfHUD";
  1453. optNVPerfHUD.possibleValues.push_back( "Yes" );
  1454. optNVPerfHUD.possibleValues.push_back( "No" );
  1455. // SRGB on auto window
  1456. optSRGB.name = "sRGB Gamma Conversion";
  1457. optSRGB.possibleValues.push_back("Yes");
  1458. optSRGB.possibleValues.push_back("No");
  1459. optSRGB.currentValue = "No";
  1460. optSRGB.immutable = false;
  1461. mOptions[optDevice.name] = optDevice;
  1462. mOptions[optVideoMode.name] = optVideoMode;
  1463. mOptions[optFullScreen.name] = optFullScreen;
  1464. mOptions[optVSync.name] = optVSync;
  1465. mOptions[optVSyncInterval.name] = optVSyncInterval;
  1466. mOptions[optAA.name] = optAA;
  1467. mOptions[optFPUMode.name] = optFPUMode;
  1468. mOptions[optNVPerfHUD.name] = optNVPerfHUD;
  1469. mOptions[optSRGB.name] = optSRGB;
  1470. mOptions[optResourceCeationPolicy.name] = optResourceCeationPolicy;
  1471. refreshD3DSettings();
  1472. }
  1473. //---------------------------------------------------------------------
  1474. void D3D9RenderSystem::refreshD3DSettings()
  1475. {
  1476. ConfigOption* optVideoMode;
  1477. D3D9Driver* driver = 0;
  1478. D3D9VideoMode* videoMode;
  1479. ConfigOptionMap::iterator opt = mOptions.find( "Rendering Device" );
  1480. if( opt != mOptions.end() )
  1481. {
  1482. for( unsigned j=0; j < getDirect3DDrivers()->count(); j++ )
  1483. {
  1484. D3D9Driver* curDriver = getDirect3DDrivers()->item(j);
  1485. if( curDriver->DriverDescription() == opt->second.currentValue )
  1486. {
  1487. driver = curDriver;
  1488. break;
  1489. }
  1490. }
  1491. if (driver)
  1492. {
  1493. opt = mOptions.find( "Video Mode" );
  1494. optVideoMode = &opt->second;
  1495. optVideoMode->possibleValues.clear();
  1496. // get vide modes for this device
  1497. for( unsigned k=0; k < driver->getVideoModeList()->count(); k++ )
  1498. {
  1499. videoMode = driver->getVideoModeList()->item( k );
  1500. optVideoMode->possibleValues.push_back( videoMode->getDescription() );
  1501. }
  1502. // Reset video mode to default if previous doesn't avail in new possible values
  1503. std::vector<CamelotEngine::String>::const_iterator itValue =
  1504. std::find(optVideoMode->possibleValues.begin(),
  1505. optVideoMode->possibleValues.end(),
  1506. optVideoMode->currentValue);
  1507. if (itValue == optVideoMode->possibleValues.end())
  1508. {
  1509. optVideoMode->currentValue = "800 x 600 @ 32-bit colour";
  1510. }
  1511. // Also refresh FSAA options
  1512. refreshFSAAOptions();
  1513. }
  1514. }
  1515. }
  1516. //---------------------------------------------------------------------
  1517. void D3D9RenderSystem::refreshFSAAOptions()
  1518. {
  1519. ConfigOptionMap::iterator it = mOptions.find( "FSAA" );
  1520. ConfigOption* optFSAA = &it->second;
  1521. optFSAA->possibleValues.clear();
  1522. optFSAA->possibleValues.push_back("0");
  1523. it = mOptions.find("Rendering Device");
  1524. D3D9Driver *driver = getDirect3DDrivers()->item(it->second.currentValue);
  1525. if (driver)
  1526. {
  1527. it = mOptions.find("Video Mode");
  1528. D3D9VideoMode *videoMode = driver->getVideoModeList()->item(it->second.currentValue);
  1529. if (videoMode)
  1530. {
  1531. DWORD numLevels = 0;
  1532. bool bOK;
  1533. for (unsigned int n = 2; n < 25; n++)
  1534. {
  1535. bOK = this->_checkMultiSampleQuality(
  1536. (D3DMULTISAMPLE_TYPE)n,
  1537. &numLevels,
  1538. videoMode->getFormat(),
  1539. driver->getAdapterNumber(),
  1540. D3DDEVTYPE_HAL,
  1541. TRUE);
  1542. if (bOK)
  1543. {
  1544. optFSAA->possibleValues.push_back(toString(n));
  1545. if (n >= 8)
  1546. optFSAA->possibleValues.push_back(toString(n) + " [Quality]");
  1547. }
  1548. }
  1549. }
  1550. }
  1551. // Reset FSAA to none if previous doesn't avail in new possible values
  1552. std::vector<CamelotEngine::String>::const_iterator itValue =
  1553. std::find(optFSAA->possibleValues.begin(),
  1554. optFSAA->possibleValues.end(),
  1555. optFSAA->currentValue);
  1556. if (itValue == optFSAA->possibleValues.end())
  1557. {
  1558. optFSAA->currentValue = "0";
  1559. }
  1560. }
  1561. //---------------------------------------------------------------------
  1562. RenderSystemCapabilities* D3D9RenderSystem::updateRenderSystemCapabilities(D3D9RenderWindow* renderWindow)
  1563. {
  1564. RenderSystemCapabilities* rsc = mCurrentCapabilities;
  1565. if (rsc == NULL)
  1566. rsc = new RenderSystemCapabilities();
  1567. rsc->setCategoryRelevant(CAPS_CATEGORY_D3D9, true);
  1568. rsc->setDriverVersion(mDriverVersion);
  1569. rsc->setDeviceName(mActiveD3DDriver->DriverDescription());
  1570. rsc->setRenderSystemName(getName());
  1571. // Supports fixed-function
  1572. rsc->setCapability(RSC_FIXED_FUNCTION);
  1573. // Init caps to maximum.
  1574. rsc->setNumTextureUnits(1024);
  1575. rsc->setCapability(RSC_ANISOTROPY);
  1576. rsc->setCapability(RSC_AUTOMIPMAP);
  1577. rsc->setCapability(RSC_DOT3);
  1578. rsc->setCapability(RSC_CUBEMAPPING);
  1579. rsc->setCapability(RSC_SCISSOR_TEST);
  1580. rsc->setCapability(RSC_TWO_SIDED_STENCIL);
  1581. rsc->setCapability(RSC_STENCIL_WRAP);
  1582. rsc->setCapability(RSC_HWOCCLUSION);
  1583. rsc->setCapability(RSC_USER_CLIP_PLANES);
  1584. rsc->setCapability(RSC_VERTEX_FORMAT_UBYTE4);
  1585. rsc->setCapability(RSC_TEXTURE_3D);
  1586. rsc->setCapability(RSC_NON_POWER_OF_2_TEXTURES);
  1587. rsc->setNonPOW2TexturesLimited(false);
  1588. rsc->setNumMultiRenderTargets(CM_MAX_MULTIPLE_RENDER_TARGETS);
  1589. rsc->setCapability(RSC_MRT_DIFFERENT_BIT_DEPTHS);
  1590. rsc->setCapability(RSC_POINT_SPRITES);
  1591. rsc->setCapability(RSC_POINT_EXTENDED_PARAMETERS);
  1592. rsc->setMaxPointSize(10.0);
  1593. rsc->setCapability(RSC_MIPMAP_LOD_BIAS);
  1594. rsc->setCapability(RSC_PERSTAGECONSTANT);
  1595. rsc->setCapability(RSC_HWSTENCIL);
  1596. rsc->setStencilBufferBitDepth(8);
  1597. rsc->setCapability(RSC_ADVANCED_BLEND_OPERATIONS);
  1598. for (UINT32 i=0; i < mDeviceManager->getDeviceCount(); ++i)
  1599. {
  1600. D3D9Device* device = mDeviceManager->getDevice(i);
  1601. IDirect3DDevice9* d3d9Device = device->getD3D9Device();
  1602. IDirect3DSurface9* pSurf;
  1603. // Check for hardware stencil support
  1604. d3d9Device->GetDepthStencilSurface(&pSurf);
  1605. if (pSurf != NULL)
  1606. {
  1607. D3DSURFACE_DESC surfDesc;
  1608. pSurf->GetDesc(&surfDesc);
  1609. pSurf->Release();
  1610. if (surfDesc.Format != D3DFMT_D15S1 &&
  1611. surfDesc.Format != D3DFMT_D24S8 &&
  1612. surfDesc.Format != D3DFMT_D24X4S4 &&
  1613. surfDesc.Format != D3DFMT_D24FS8)
  1614. rsc->unsetCapability(RSC_HWSTENCIL);
  1615. }
  1616. // Check for hardware occlusion support
  1617. HRESULT hr = d3d9Device->CreateQuery(D3DQUERYTYPE_OCCLUSION, NULL);
  1618. if (FAILED(hr))
  1619. rsc->unsetCapability(RSC_HWOCCLUSION);
  1620. }
  1621. // Update RS caps using the minimum value found in adapter list.
  1622. for (unsigned int i=0; i < mDriverList->count(); ++i)
  1623. {
  1624. D3D9Driver* pCurDriver = mDriverList->item(i);
  1625. const D3DCAPS9& rkCurCaps = pCurDriver->getD3D9DeviceCaps();
  1626. if (rkCurCaps.MaxSimultaneousTextures < rsc->getNumTextureUnits())
  1627. {
  1628. rsc->setNumTextureUnits(static_cast<UINT16>(rkCurCaps.MaxSimultaneousTextures));
  1629. }
  1630. // Check for Anisotropy.
  1631. if (rkCurCaps.MaxAnisotropy <= 1)
  1632. rsc->unsetCapability(RSC_ANISOTROPY);
  1633. // Check automatic mipmap generation.
  1634. if ((rkCurCaps.Caps2 & D3DCAPS2_CANAUTOGENMIPMAP) == 0)
  1635. rsc->unsetCapability(RSC_AUTOMIPMAP);
  1636. // Check Dot product 3.
  1637. if ((rkCurCaps.TextureOpCaps & D3DTEXOPCAPS_DOTPRODUCT3) == 0)
  1638. rsc->unsetCapability(RSC_DOT3);
  1639. // Scissor test
  1640. if ((rkCurCaps.RasterCaps & D3DPRASTERCAPS_SCISSORTEST) == 0)
  1641. rsc->unsetCapability(RSC_SCISSOR_TEST);
  1642. // Two-sided stencil
  1643. if ((rkCurCaps.StencilCaps & D3DSTENCILCAPS_TWOSIDED) == 0)
  1644. rsc->unsetCapability(RSC_TWO_SIDED_STENCIL);
  1645. // stencil wrap
  1646. if ((rkCurCaps.StencilCaps & D3DSTENCILCAPS_INCR) == 0 ||
  1647. (rkCurCaps.StencilCaps & D3DSTENCILCAPS_DECR) == 0)
  1648. rsc->unsetCapability(RSC_STENCIL_WRAP);
  1649. // User clip planes
  1650. if (rkCurCaps.MaxUserClipPlanes == 0)
  1651. rsc->unsetCapability(RSC_USER_CLIP_PLANES);
  1652. // UBYTE4 type?
  1653. if ((rkCurCaps.DeclTypes & D3DDTCAPS_UBYTE4) == 0)
  1654. rsc->unsetCapability(RSC_VERTEX_FORMAT_UBYTE4);
  1655. // Check cube map support.
  1656. if ((rkCurCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP) == 0)
  1657. rsc->unsetCapability(RSC_CUBEMAPPING);
  1658. // 3D textures?
  1659. if ((rkCurCaps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP) == 0)
  1660. rsc->unsetCapability(RSC_TEXTURE_3D);
  1661. if (rkCurCaps.TextureCaps & D3DPTEXTURECAPS_POW2)
  1662. {
  1663. // Conditional support for non POW2
  1664. if (rkCurCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL)
  1665. rsc->setNonPOW2TexturesLimited(true);
  1666. // Only power of 2 supported.
  1667. else
  1668. rsc->unsetCapability(RSC_NON_POWER_OF_2_TEXTURES);
  1669. }
  1670. // Number of render targets
  1671. if (rkCurCaps.NumSimultaneousRTs < rsc->getNumMultiRenderTargets())
  1672. {
  1673. rsc->setNumMultiRenderTargets(std::min((UINT16)rkCurCaps.NumSimultaneousRTs, (UINT16)CM_MAX_MULTIPLE_RENDER_TARGETS));
  1674. }
  1675. if((rkCurCaps.PrimitiveMiscCaps & D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS) == 0)
  1676. {
  1677. rsc->unsetCapability(RSC_MRT_DIFFERENT_BIT_DEPTHS);
  1678. }
  1679. // Point sprites
  1680. if (rkCurCaps.MaxPointSize <= 1.0f)
  1681. {
  1682. rsc->unsetCapability(RSC_POINT_SPRITES);
  1683. // sprites and extended parameters go together in D3D
  1684. rsc->unsetCapability(RSC_POINT_EXTENDED_PARAMETERS);
  1685. }
  1686. // Take the minimum point size.
  1687. if (rkCurCaps.MaxPointSize < rsc->getMaxPointSize())
  1688. rsc->setMaxPointSize(rkCurCaps.MaxPointSize);
  1689. // Mipmap LOD biasing?
  1690. if ((rkCurCaps.RasterCaps & D3DPRASTERCAPS_MIPMAPLODBIAS) == 0)
  1691. rsc->unsetCapability(RSC_MIPMAP_LOD_BIAS);
  1692. // Do we support per-stage src_manual constants?
  1693. // HACK - ATI drivers seem to be buggy and don't support per-stage constants properly?
  1694. // TODO: move this to RSC
  1695. if((rkCurCaps.PrimitiveMiscCaps & D3DPMISCCAPS_PERSTAGECONSTANT) == 0)
  1696. rsc->unsetCapability(RSC_PERSTAGECONSTANT);
  1697. // Advanced blend operations? min max subtract rev
  1698. if((rkCurCaps.PrimitiveMiscCaps & D3DPMISCCAPS_BLENDOP) == 0)
  1699. rsc->unsetCapability(RSC_ADVANCED_BLEND_OPERATIONS);
  1700. }
  1701. // Blending between stages supported
  1702. rsc->setCapability(RSC_BLENDING);
  1703. // We always support compression, D3DX will decompress if device does not support
  1704. rsc->setCapability(RSC_TEXTURE_COMPRESSION);
  1705. rsc->setCapability(RSC_TEXTURE_COMPRESSION_DXT);
  1706. // We always support VBOs
  1707. rsc->setCapability(RSC_VBO);
  1708. convertVertexShaderCaps(rsc);
  1709. convertPixelShaderCaps(rsc);
  1710. // Adapter details
  1711. const D3DADAPTER_IDENTIFIER9& adapterID = mActiveD3DDriver->getAdapterIdentifier();
  1712. // determine vendor
  1713. // Full list of vendors here: http://www.pcidatabase.com/vendors.php?sort=id
  1714. switch(adapterID.VendorId)
  1715. {
  1716. case 0x10DE:
  1717. rsc->setVendor(GPU_NVIDIA);
  1718. break;
  1719. case 0x1002:
  1720. rsc->setVendor(GPU_ATI);
  1721. break;
  1722. case 0x163C:
  1723. case 0x8086:
  1724. rsc->setVendor(GPU_INTEL);
  1725. break;
  1726. case 0x5333:
  1727. rsc->setVendor(GPU_S3);
  1728. break;
  1729. case 0x3D3D:
  1730. rsc->setVendor(GPU_3DLABS);
  1731. break;
  1732. case 0x102B:
  1733. rsc->setVendor(GPU_MATROX);
  1734. break;
  1735. case 0x1039:
  1736. rsc->setVendor(GPU_SIS);
  1737. break;
  1738. default:
  1739. rsc->setVendor(GPU_UNKNOWN);
  1740. break;
  1741. };
  1742. // Infinite projection?
  1743. // We have no capability for this, so we have to base this on our
  1744. // experience and reports from users
  1745. // Non-vertex program capable hardware does not appear to support it
  1746. if (rsc->hasCapability(RSC_VERTEX_PROGRAM))
  1747. {
  1748. // GeForce4 Ti (and presumably GeForce3) does not
  1749. // render infinite projection properly, even though it does in GL
  1750. // So exclude all cards prior to the FX range from doing infinite
  1751. if (rsc->getVendor() != GPU_NVIDIA || // not nVidia
  1752. !((adapterID.DeviceId >= 0x200 && adapterID.DeviceId <= 0x20F) || //gf3
  1753. (adapterID.DeviceId >= 0x250 && adapterID.DeviceId <= 0x25F) || //gf4ti
  1754. (adapterID.DeviceId >= 0x280 && adapterID.DeviceId <= 0x28F) || //gf4ti
  1755. (adapterID.DeviceId >= 0x170 && adapterID.DeviceId <= 0x18F) || //gf4 go
  1756. (adapterID.DeviceId >= 0x280 && adapterID.DeviceId <= 0x28F))) //gf4ti go
  1757. {
  1758. rsc->setCapability(RSC_INFINITE_FAR_PLANE);
  1759. }
  1760. }
  1761. // We always support rendertextures bigger than the frame buffer
  1762. rsc->setCapability(RSC_HWRENDER_TO_TEXTURE);
  1763. // Determine if any floating point texture format is supported
  1764. D3DFORMAT floatFormats[6] = {D3DFMT_R16F, D3DFMT_G16R16F,
  1765. D3DFMT_A16B16G16R16F, D3DFMT_R32F, D3DFMT_G32R32F,
  1766. D3DFMT_A32B32G32R32F};
  1767. IDirect3DSurface9* bbSurf;
  1768. renderWindow->getCustomAttribute_internal("DDBACKBUFFER", &bbSurf);
  1769. D3DSURFACE_DESC bbSurfDesc;
  1770. bbSurf->GetDesc(&bbSurfDesc);
  1771. for (int i = 0; i < 6; ++i)
  1772. {
  1773. if (SUCCEEDED(mpD3D->CheckDeviceFormat(mActiveD3DDriver->getAdapterNumber(),
  1774. D3DDEVTYPE_HAL, bbSurfDesc.Format,
  1775. 0, D3DRTYPE_TEXTURE, floatFormats[i])))
  1776. {
  1777. rsc->setCapability(RSC_TEXTURE_FLOAT);
  1778. break;
  1779. }
  1780. }
  1781. // TODO: make convertVertex/Fragment fill in rsc
  1782. // TODO: update the below line to use rsc
  1783. // Vertex textures
  1784. if (rsc->isShaderProfileSupported("vs_3_0"))
  1785. {
  1786. // Run through all the texture formats looking for any which support
  1787. // vertex texture fetching. Must have at least one!
  1788. // All ATI Radeon up to X1n00 say they support vs_3_0,
  1789. // but they support no texture formats for vertex texture fetch (cheaters!)
  1790. if (checkVertexTextureFormats(renderWindow))
  1791. {
  1792. rsc->setCapability(RSC_VERTEX_TEXTURE_FETCH);
  1793. // always 4 vertex texture units in vs_3_0, and never shared
  1794. rsc->setNumVertexTextureUnits(4);
  1795. rsc->setVertexTextureUnitsShared(false);
  1796. }
  1797. }
  1798. // Check alpha to coverage support
  1799. // this varies per vendor! But at least SM3 is required
  1800. if (rsc->isShaderProfileSupported("ps_3_0"))
  1801. {
  1802. // NVIDIA needs a separate check
  1803. if (rsc->getVendor() == GPU_NVIDIA)
  1804. {
  1805. if (mpD3D->CheckDeviceFormat(
  1806. D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, 0,D3DRTYPE_SURFACE,
  1807. (D3DFORMAT)MAKEFOURCC('A', 'T', 'O', 'C')) == S_OK)
  1808. {
  1809. rsc->setCapability(RSC_ALPHA_TO_COVERAGE);
  1810. }
  1811. }
  1812. else if (rsc->getVendor() == GPU_ATI)
  1813. {
  1814. // There is no check on ATI, we have to assume SM3 == support
  1815. rsc->setCapability(RSC_ALPHA_TO_COVERAGE);
  1816. }
  1817. // no other cards have Dx9 hacks for alpha to coverage, as far as I know
  1818. }
  1819. if (mCurrentCapabilities == NULL)
  1820. {
  1821. mCurrentCapabilities = rsc;
  1822. mCurrentCapabilities->addShaderProfile("hlsl");
  1823. mCurrentCapabilities->addShaderProfile("cg");
  1824. initialiseFromRenderSystemCapabilities(mCurrentCapabilities, renderWindow);
  1825. }
  1826. return rsc;
  1827. }
  1828. //---------------------------------------------------------------------
  1829. void D3D9RenderSystem::convertVertexShaderCaps(RenderSystemCapabilities* rsc) const
  1830. {
  1831. UINT16 major = 0xFF;
  1832. UINT16 minor = 0xFF;
  1833. D3DCAPS9 minVSCaps;
  1834. // Find the device with the lowest vertex shader caps.
  1835. for (unsigned int i=0; i < mDriverList->count(); ++i)
  1836. {
  1837. D3D9Driver* pCurDriver = mDriverList->item(i);
  1838. const D3DCAPS9& rkCurCaps = pCurDriver->getD3D9DeviceCaps();
  1839. UINT16 currMajor = static_cast<UINT16>((rkCurCaps.VertexShaderVersion & 0x0000FF00) >> 8);
  1840. UINT16 currMinor = static_cast<UINT16>(rkCurCaps.VertexShaderVersion & 0x000000FF);
  1841. if (currMajor < major)
  1842. {
  1843. major = currMajor;
  1844. minor = currMinor;
  1845. minVSCaps = rkCurCaps;
  1846. }
  1847. else if (currMajor == major && currMinor < minor)
  1848. {
  1849. minor = currMinor;
  1850. minVSCaps = rkCurCaps;
  1851. }
  1852. }
  1853. // In case we didn't found any vertex shader support
  1854. // try the IDirect3DDevice9 caps instead of the IDirect3D9
  1855. // software vertex processing is reported there
  1856. if (major == 0 && minor == 0)
  1857. {
  1858. IDirect3DDevice9* lpD3DDevice9 = getActiveD3D9Device();
  1859. D3DCAPS9 d3dDeviceCaps9;
  1860. lpD3DDevice9->GetDeviceCaps(&d3dDeviceCaps9);
  1861. major = static_cast<UINT16>((d3dDeviceCaps9.VertexShaderVersion & 0x0000FF00) >> 8);
  1862. minor = static_cast<UINT16>(d3dDeviceCaps9.VertexShaderVersion & 0x000000FF);
  1863. }
  1864. bool vs2x = false;
  1865. bool vs2a = false;
  1866. // Special case detection for vs_2_x/a support
  1867. if (major >= 2)
  1868. {
  1869. if ((minVSCaps.VS20Caps.Caps & D3DVS20CAPS_PREDICATION) &&
  1870. (minVSCaps.VS20Caps.DynamicFlowControlDepth > 0) &&
  1871. (minVSCaps.VS20Caps.NumTemps >= 12))
  1872. {
  1873. vs2x = true;
  1874. }
  1875. if ((minVSCaps.VS20Caps.Caps & D3DVS20CAPS_PREDICATION) &&
  1876. (minVSCaps.VS20Caps.DynamicFlowControlDepth > 0) &&
  1877. (minVSCaps.VS20Caps.NumTemps >= 13))
  1878. {
  1879. vs2a = true;
  1880. }
  1881. }
  1882. // Populate max param count
  1883. switch (major)
  1884. {
  1885. case 1:
  1886. // No boolean params allowed
  1887. rsc->setVertexProgramConstantBoolCount(0);
  1888. // No integer params allowed
  1889. rsc->setVertexProgramConstantIntCount(0);
  1890. // float params, always 4D
  1891. rsc->setVertexProgramConstantFloatCount(static_cast<UINT16>(minVSCaps.MaxVertexShaderConst));
  1892. break;
  1893. case 2:
  1894. // 16 boolean params allowed
  1895. rsc->setVertexProgramConstantBoolCount(16);
  1896. // 16 integer params allowed, 4D
  1897. rsc->setVertexProgramConstantIntCount(16);
  1898. // float params, always 4D
  1899. rsc->setVertexProgramConstantFloatCount(static_cast<UINT16>(minVSCaps.MaxVertexShaderConst));
  1900. break;
  1901. case 3:
  1902. // 16 boolean params allowed
  1903. rsc->setVertexProgramConstantBoolCount(16);
  1904. // 16 integer params allowed, 4D
  1905. rsc->setVertexProgramConstantIntCount(16);
  1906. // float params, always 4D
  1907. rsc->setVertexProgramConstantFloatCount(static_cast<UINT16>(minVSCaps.MaxVertexShaderConst));
  1908. break;
  1909. }
  1910. // populate syntax codes in program manager (no breaks in this one so it falls through)
  1911. switch(major)
  1912. {
  1913. case 3:
  1914. rsc->addShaderProfile("vs_3_0");
  1915. rsc->addGpuProgramProfile(GPP_VS_3_0, "vs_3_0");
  1916. case 2:
  1917. if (vs2x)
  1918. {
  1919. rsc->addShaderProfile("vs_2_x");
  1920. rsc->addGpuProgramProfile(GPP_VS_2_x, "vs_2_x");
  1921. }
  1922. if (vs2a)
  1923. {
  1924. rsc->addShaderProfile("vs_2_a");
  1925. rsc->addGpuProgramProfile(GPP_VS_2_a, "vs_2_a");
  1926. }
  1927. rsc->addShaderProfile("vs_2_0");
  1928. rsc->addGpuProgramProfile(GPP_VS_2_0, "vs_2_0");
  1929. case 1:
  1930. rsc->addShaderProfile("vs_1_1");
  1931. rsc->addGpuProgramProfile(GPP_VS_1_1, "vs_1_1");
  1932. rsc->setCapability(RSC_VERTEX_PROGRAM);
  1933. }
  1934. }
  1935. //---------------------------------------------------------------------
  1936. void D3D9RenderSystem::convertPixelShaderCaps(RenderSystemCapabilities* rsc) const
  1937. {
  1938. UINT16 major = 0xFF;
  1939. UINT16 minor = 0xFF;
  1940. D3DCAPS9 minPSCaps;
  1941. // Find the device with the lowest pixel shader caps.
  1942. for (unsigned int i=0; i < mDriverList->count(); ++i)
  1943. {
  1944. D3D9Driver* pCurDriver = mDriverList->item(i);
  1945. const D3DCAPS9& currCaps = pCurDriver->getD3D9DeviceCaps();
  1946. UINT16 currMajor = static_cast<UINT16>((currCaps.PixelShaderVersion & 0x0000FF00) >> 8);
  1947. UINT16 currMinor = static_cast<UINT16>(currCaps.PixelShaderVersion & 0x000000FF);
  1948. if (currMajor < major)
  1949. {
  1950. major = currMajor;
  1951. minor = currMinor;
  1952. minPSCaps = currCaps;
  1953. }
  1954. else if (currMajor == major && currMinor < minor)
  1955. {
  1956. minor = currMinor;
  1957. minPSCaps = currCaps;
  1958. }
  1959. }
  1960. bool ps2a = false;
  1961. bool ps2b = false;
  1962. bool ps2x = false;
  1963. // Special case detection for ps_2_x/a/b support
  1964. if (major >= 2)
  1965. {
  1966. if ((minPSCaps.PS20Caps.Caps & D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT) &&
  1967. (minPSCaps.PS20Caps.NumTemps >= 32))
  1968. {
  1969. ps2b = true;
  1970. }
  1971. if ((minPSCaps.PS20Caps.Caps & D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT) &&
  1972. (minPSCaps.PS20Caps.Caps & D3DPS20CAPS_NODEPENDENTREADLIMIT) &&
  1973. (minPSCaps.PS20Caps.Caps & D3DPS20CAPS_ARBITRARYSWIZZLE) &&
  1974. (minPSCaps.PS20Caps.Caps & D3DPS20CAPS_GRADIENTINSTRUCTIONS) &&
  1975. (minPSCaps.PS20Caps.Caps & D3DPS20CAPS_PREDICATION) &&
  1976. (minPSCaps.PS20Caps.NumTemps >= 22))
  1977. {
  1978. ps2a = true;
  1979. }
  1980. // Does this enough?
  1981. if (ps2a || ps2b)
  1982. {
  1983. ps2x = true;
  1984. }
  1985. }
  1986. switch (major)
  1987. {
  1988. case 1:
  1989. // no boolean params allowed
  1990. rsc->setFragmentProgramConstantBoolCount(0);
  1991. // no integer params allowed
  1992. rsc->setFragmentProgramConstantIntCount(0);
  1993. // float params, always 4D
  1994. // NB in ps_1_x these are actually stored as fixed point values,
  1995. // but they are entered as floats
  1996. rsc->setFragmentProgramConstantFloatCount(8);
  1997. break;
  1998. case 2:
  1999. // 16 boolean params allowed
  2000. rsc->setFragmentProgramConstantBoolCount(16);
  2001. // 16 integer params allowed, 4D
  2002. rsc->setFragmentProgramConstantIntCount(16);
  2003. // float params, always 4D
  2004. rsc->setFragmentProgramConstantFloatCount(32);
  2005. break;
  2006. case 3:
  2007. // 16 boolean params allowed
  2008. rsc->setFragmentProgramConstantBoolCount(16);
  2009. // 16 integer params allowed, 4D
  2010. rsc->setFragmentProgramConstantIntCount(16);
  2011. // float params, always 4D
  2012. rsc->setFragmentProgramConstantFloatCount(224);
  2013. break;
  2014. }
  2015. // populate syntax codes in program manager (no breaks in this one so it falls through)
  2016. switch(major)
  2017. {
  2018. case 3:
  2019. if (minor > 0)
  2020. {
  2021. rsc->addShaderProfile("ps_3_x");
  2022. rsc->addGpuProgramProfile(GPP_PS_3_x, "ps_3_x");
  2023. }
  2024. rsc->addShaderProfile("ps_3_0");
  2025. rsc->addGpuProgramProfile(GPP_PS_3_0, "ps_3_0");
  2026. case 2:
  2027. if (ps2x)
  2028. {
  2029. rsc->addShaderProfile("ps_2_x");
  2030. rsc->addGpuProgramProfile(GPP_PS_2_x, "ps_2_x");
  2031. }
  2032. if (ps2a)
  2033. {
  2034. rsc->addShaderProfile("ps_2_a");
  2035. rsc->addGpuProgramProfile(GPP_PS_2_a, "ps_2_a");
  2036. }
  2037. if (ps2b)
  2038. {
  2039. rsc->addShaderProfile("ps_2_b");
  2040. rsc->addGpuProgramProfile(GPP_PS_2_b, "ps_2_b");
  2041. }
  2042. rsc->addShaderProfile("ps_2_0");
  2043. rsc->addGpuProgramProfile(GPP_PS_2_0, "ps_2_0");
  2044. case 1:
  2045. if (major > 1 || minor >= 4)
  2046. {
  2047. rsc->addShaderProfile("ps_1_4");
  2048. rsc->addGpuProgramProfile(GPP_PS_1_4, "ps_1_4");
  2049. }
  2050. if (major > 1 || minor >= 3)
  2051. {
  2052. rsc->addShaderProfile("ps_1_3");
  2053. rsc->addGpuProgramProfile(GPP_PS_1_3, "ps_1_3");
  2054. }
  2055. if (major > 1 || minor >= 2)
  2056. {
  2057. rsc->addShaderProfile("ps_1_2");
  2058. rsc->addGpuProgramProfile(GPP_PS_1_2, "ps_1_2");
  2059. }
  2060. rsc->addShaderProfile("ps_1_1");
  2061. rsc->addGpuProgramProfile(GPP_PS_1_1, "ps_1_1");
  2062. rsc->setCapability(RSC_FRAGMENT_PROGRAM);
  2063. }
  2064. }
  2065. //-----------------------------------------------------------------------
  2066. bool D3D9RenderSystem::checkVertexTextureFormats(D3D9RenderWindow* renderWindow) const
  2067. {
  2068. bool anySupported = false;
  2069. IDirect3DSurface9* bbSurf;
  2070. renderWindow->getCustomAttribute_internal("DDBACKBUFFER", &bbSurf);
  2071. D3DSURFACE_DESC bbSurfDesc;
  2072. bbSurf->GetDesc(&bbSurfDesc);
  2073. for (UINT32 ipf = static_cast<UINT32>(PF_L8); ipf < static_cast<UINT32>(PF_COUNT); ++ipf)
  2074. {
  2075. PixelFormat pf = (PixelFormat)ipf;
  2076. D3DFORMAT fmt =
  2077. D3D9Mappings::_getPF(D3D9Mappings::_getClosestSupportedPF(pf));
  2078. if (SUCCEEDED(mpD3D->CheckDeviceFormat(
  2079. mActiveD3DDriver->getAdapterNumber(), D3DDEVTYPE_HAL, bbSurfDesc.Format,
  2080. D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, fmt)))
  2081. {
  2082. // cool, at least one supported
  2083. anySupported = true;
  2084. }
  2085. }
  2086. return anySupported;
  2087. }
  2088. //-----------------------------------------------------------------------
  2089. void D3D9RenderSystem::initialiseFromRenderSystemCapabilities(RenderSystemCapabilities* caps, RenderTarget* primary)
  2090. {
  2091. if (caps->getRenderSystemName() != getName())
  2092. {
  2093. CM_EXCEPT(InvalidParametersException,
  2094. "Trying to initialize D3D9RenderSystem from RenderSystemCapabilities that do not support Direct3D9");
  2095. }
  2096. if (caps->isShaderProfileSupported("hlsl"))
  2097. HighLevelGpuProgramManager::instance().addFactory(mHLSLProgramFactory);
  2098. if (caps->isShaderProfileSupported("cg"))
  2099. HighLevelGpuProgramManager::instance().addFactory(mCgProgramFactory);
  2100. }
  2101. //-----------------------------------------------------------------------
  2102. bool D3D9RenderSystem::checkTextureFilteringSupported(TextureType ttype, PixelFormat format, int usage)
  2103. {
  2104. // Gets D3D format
  2105. D3DFORMAT d3dPF = D3D9Mappings::_getPF(format);
  2106. if (d3dPF == D3DFMT_UNKNOWN)
  2107. return false;
  2108. for (UINT32 i = 0; i < mDeviceManager->getDeviceCount(); ++i)
  2109. {
  2110. D3D9Device* currDevice = mDeviceManager->getDevice(i);
  2111. D3D9RenderWindow* currDevicePrimaryWindow = currDevice->getPrimaryWindow();
  2112. IDirect3DSurface9* pSurface = currDevicePrimaryWindow->getRenderSurface();
  2113. D3DSURFACE_DESC srfDesc;
  2114. // Get surface desc
  2115. if (FAILED(pSurface->GetDesc(&srfDesc)))
  2116. return false;
  2117. // Calculate usage
  2118. DWORD d3dusage = D3DUSAGE_QUERY_FILTER;
  2119. if (usage & TU_RENDERTARGET)
  2120. d3dusage |= D3DUSAGE_RENDERTARGET;
  2121. if (usage & TU_DYNAMIC)
  2122. d3dusage |= D3DUSAGE_DYNAMIC;
  2123. // Detect resource type
  2124. D3DRESOURCETYPE rtype;
  2125. switch(ttype)
  2126. {
  2127. case TEX_TYPE_1D:
  2128. case TEX_TYPE_2D:
  2129. rtype = D3DRTYPE_TEXTURE;
  2130. break;
  2131. case TEX_TYPE_3D:
  2132. rtype = D3DRTYPE_VOLUMETEXTURE;
  2133. break;
  2134. case TEX_TYPE_CUBE_MAP:
  2135. rtype = D3DRTYPE_CUBETEXTURE;
  2136. break;
  2137. default:
  2138. return false;
  2139. }
  2140. HRESULT hr = mpD3D->CheckDeviceFormat(
  2141. currDevice->getAdapterNumber(),
  2142. currDevice->getDeviceType(),
  2143. srfDesc.Format,
  2144. d3dusage,
  2145. rtype,
  2146. d3dPF);
  2147. if (FAILED(hr))
  2148. return false;
  2149. }
  2150. return true;
  2151. }
  2152. //---------------------------------------------------------------------
  2153. String D3D9RenderSystem::getErrorDescription( long errorNumber ) const
  2154. {
  2155. const String errMsg = DXGetErrorDescription( errorNumber );
  2156. return errMsg;
  2157. }
  2158. // ------------------------------------------------------------------
  2159. void D3D9RenderSystem::setClipPlane (UINT16 index, float A, float B, float C, float D)
  2160. {
  2161. float plane[4] = { A, B, C, D };
  2162. getActiveD3D9Device()->SetClipPlane (index, plane);
  2163. }
  2164. // ------------------------------------------------------------------
  2165. void D3D9RenderSystem::enableClipPlane (UINT16 index, bool enable)
  2166. {
  2167. DWORD prev;
  2168. getActiveD3D9Device()->GetRenderState(D3DRS_CLIPPLANEENABLE, &prev);
  2169. __SetRenderState(D3DRS_CLIPPLANEENABLE, enable?
  2170. (prev | (1 << index)) : (prev & ~(1 << index)));
  2171. }
  2172. //-----------------------------------------------------------------------
  2173. MultiRenderTarget * D3D9RenderSystem::createMultiRenderTarget(const String & name)
  2174. {
  2175. THROW_IF_NOT_RENDER_THREAD;
  2176. MultiRenderTarget *retval;
  2177. retval = new D3D9MultiRenderTarget(name);
  2178. attachRenderTarget(*retval);
  2179. return retval;
  2180. }
  2181. //---------------------------------------------------------------------
  2182. void D3D9RenderSystem::notifyOnDeviceLost(D3D9Device* device)
  2183. {
  2184. }
  2185. //---------------------------------------------------------------------
  2186. void D3D9RenderSystem::notifyOnDeviceReset(D3D9Device* device)
  2187. {
  2188. // Reset state attributes.
  2189. mVertexProgramBound = false;
  2190. mFragmentProgramBound = false;
  2191. mLastVertexSourceCount = 0;
  2192. // Restore previous active device.
  2193. // Invalidate active view port.
  2194. mActiveViewport = Viewport();
  2195. // Reset the texture stages, they will need to be rebound
  2196. for (UINT16 i = 0; i < CM_MAX_TEXTURE_LAYERS; ++i)
  2197. setTexture(i, false, TexturePtr());
  2198. }
  2199. //---------------------------------------------------------------------
  2200. void D3D9RenderSystem::determineFSAASettings(IDirect3DDevice9* d3d9Device,
  2201. UINT32 fsaa, const String& fsaaHint, D3DFORMAT d3dPixelFormat,
  2202. bool fullScreen, D3DMULTISAMPLE_TYPE *outMultisampleType, DWORD *outMultisampleQuality)
  2203. {
  2204. bool ok = false;
  2205. bool qualityHint = fsaaHint.find("Quality") != String::npos;
  2206. UINT32 origFSAA = fsaa;
  2207. D3D9DriverList* driverList = getDirect3DDrivers();
  2208. D3D9Driver* deviceDriver = mActiveD3DDriver;
  2209. D3D9Device* device = mDeviceManager->getDeviceFromD3D9Device(d3d9Device);
  2210. for (UINT32 i = 0; i < driverList->count(); ++i)
  2211. {
  2212. D3D9Driver* currDriver = driverList->item(i);
  2213. if (currDriver->getAdapterNumber() == device->getAdapterNumber())
  2214. {
  2215. deviceDriver = currDriver;
  2216. break;
  2217. }
  2218. }
  2219. bool tryCSAA = false;
  2220. // NVIDIA, prefer CSAA if available for 8+
  2221. // it would be tempting to use getCapabilities()->getVendor() == GPU_NVIDIA but
  2222. // if this is the first window, caps will not be initialised yet
  2223. if (deviceDriver->getAdapterIdentifier().VendorId == 0x10DE &&
  2224. fsaa >= 8)
  2225. {
  2226. tryCSAA = true;
  2227. }
  2228. while (!ok)
  2229. {
  2230. // Deal with special cases
  2231. if (tryCSAA)
  2232. {
  2233. // see http://developer.nvidia.com/object/coverage-sampled-aa.html
  2234. switch(fsaa)
  2235. {
  2236. case 8:
  2237. if (qualityHint)
  2238. {
  2239. *outMultisampleType = D3DMULTISAMPLE_8_SAMPLES;
  2240. *outMultisampleQuality = 0;
  2241. }
  2242. else
  2243. {
  2244. *outMultisampleType = D3DMULTISAMPLE_4_SAMPLES;
  2245. *outMultisampleQuality = 2;
  2246. }
  2247. break;
  2248. case 16:
  2249. if (qualityHint)
  2250. {
  2251. *outMultisampleType = D3DMULTISAMPLE_8_SAMPLES;
  2252. *outMultisampleQuality = 2;
  2253. }
  2254. else
  2255. {
  2256. *outMultisampleType = D3DMULTISAMPLE_4_SAMPLES;
  2257. *outMultisampleQuality = 4;
  2258. }
  2259. break;
  2260. }
  2261. }
  2262. else // !CSAA
  2263. {
  2264. *outMultisampleType = (D3DMULTISAMPLE_TYPE)fsaa;
  2265. *outMultisampleQuality = 0;
  2266. }
  2267. HRESULT hr;
  2268. DWORD outQuality;
  2269. hr = mpD3D->CheckDeviceMultiSampleType(
  2270. deviceDriver->getAdapterNumber(),
  2271. D3DDEVTYPE_HAL,
  2272. d3dPixelFormat,
  2273. fullScreen,
  2274. *outMultisampleType,
  2275. &outQuality);
  2276. if (SUCCEEDED(hr) &&
  2277. (!tryCSAA || outQuality > *outMultisampleQuality))
  2278. {
  2279. ok = true;
  2280. }
  2281. else
  2282. {
  2283. // downgrade
  2284. if (tryCSAA && fsaa == 8)
  2285. {
  2286. // for CSAA, we'll try downgrading with quality mode at all samples.
  2287. // then try without quality, then drop CSAA
  2288. if (qualityHint)
  2289. {
  2290. // drop quality first
  2291. qualityHint = false;
  2292. }
  2293. else
  2294. {
  2295. // drop CSAA entirely
  2296. tryCSAA = false;
  2297. }
  2298. // return to original requested samples
  2299. fsaa = origFSAA;
  2300. }
  2301. else
  2302. {
  2303. // drop samples
  2304. --fsaa;
  2305. if (fsaa == 1)
  2306. {
  2307. // ran out of options, no FSAA
  2308. fsaa = 0;
  2309. ok = true;
  2310. }
  2311. }
  2312. }
  2313. } // while !ok
  2314. }
  2315. //---------------------------------------------------------------------
  2316. RenderSystemCapabilities* D3D9RenderSystem::createRenderSystemCapabilities() const
  2317. {
  2318. return mCurrentCapabilities;
  2319. }
  2320. //---------------------------------------------------------------------
  2321. D3DFORMAT D3D9RenderSystem::getDepthStencilFormatFor(D3DFORMAT fmt)
  2322. {
  2323. /// Check if result is cached
  2324. DepthStencilHash::iterator i = mDepthStencilHash.find((unsigned int)fmt);
  2325. if(i != mDepthStencilHash.end())
  2326. return i->second;
  2327. /// If not, probe with CheckDepthStencilMatch
  2328. D3DFORMAT dsfmt = D3DFMT_UNKNOWN;
  2329. /// Get description of primary render target
  2330. D3D9Device* activeDevice = mDeviceManager->getActiveDevice();
  2331. IDirect3DSurface9* mSurface = activeDevice->getPrimaryWindow()->getRenderSurface();
  2332. D3DSURFACE_DESC srfDesc;
  2333. if(!FAILED(mSurface->GetDesc(&srfDesc)))
  2334. {
  2335. /// Probe all depth stencil formats
  2336. /// Break on first one that matches
  2337. for(size_t x=0; x<NDSFORMATS; ++x)
  2338. {
  2339. // Verify that the depth format exists
  2340. if (mpD3D->CheckDeviceFormat(
  2341. activeDevice->getAdapterNumber(),
  2342. activeDevice->getDeviceType(),
  2343. srfDesc.Format,
  2344. D3DUSAGE_DEPTHSTENCIL,
  2345. D3DRTYPE_SURFACE,
  2346. ddDepthStencilFormats[x]) != D3D_OK)
  2347. {
  2348. continue;
  2349. }
  2350. // Verify that the depth format is compatible
  2351. if(mpD3D->CheckDepthStencilMatch(
  2352. activeDevice->getAdapterNumber(),
  2353. activeDevice->getDeviceType(),
  2354. srfDesc.Format,
  2355. fmt, ddDepthStencilFormats[x]) == D3D_OK)
  2356. {
  2357. dsfmt = ddDepthStencilFormats[x];
  2358. break;
  2359. }
  2360. }
  2361. }
  2362. /// Cache result
  2363. mDepthStencilHash[(unsigned int)fmt] = dsfmt;
  2364. return dsfmt;
  2365. }
  2366. IDirect3DSurface9* D3D9RenderSystem::getDepthStencilFor(D3DFORMAT fmt,
  2367. D3DMULTISAMPLE_TYPE multisample, DWORD multisample_quality, UINT32 width, UINT32 height)
  2368. {
  2369. D3DFORMAT dsfmt = getDepthStencilFormatFor(fmt);
  2370. if(dsfmt == D3DFMT_UNKNOWN)
  2371. return 0;
  2372. IDirect3DSurface9 *surface = 0;
  2373. /// Check if result is cached
  2374. ZBufferIdentifier zBufferIdentifer;
  2375. zBufferIdentifer.format = dsfmt;
  2376. zBufferIdentifer.multisampleType = multisample;
  2377. zBufferIdentifer.device = getActiveD3D9Device();
  2378. ZBufferRefQueue& zBuffers = mZBufferHash[zBufferIdentifer];
  2379. if(!zBuffers.empty())
  2380. {
  2381. const ZBufferRef& zBuffer = zBuffers.front();
  2382. /// Check if size is larger or equal
  2383. if(zBuffer.width >= width && zBuffer.height >= height)
  2384. {
  2385. surface = zBuffer.surface;
  2386. }
  2387. else
  2388. {
  2389. /// If not, destroy current buffer
  2390. zBuffer.surface->Release();
  2391. zBuffers.pop_front();
  2392. }
  2393. }
  2394. if(!surface)
  2395. {
  2396. /// If not, create the depthstencil surface
  2397. HRESULT hr = getActiveD3D9Device()->CreateDepthStencilSurface(
  2398. static_cast<UINT>(width),
  2399. static_cast<UINT>(height),
  2400. dsfmt,
  2401. multisample,
  2402. multisample_quality,
  2403. TRUE, // discard true or false?
  2404. &surface,
  2405. NULL);
  2406. if(FAILED(hr))
  2407. {
  2408. String msg = DXGetErrorDescription(hr);
  2409. CM_EXCEPT(InvalidParametersException, "Error CreateDepthStencilSurface : " + msg);
  2410. }
  2411. /// And cache it
  2412. ZBufferRef zb;
  2413. zb.surface = surface;
  2414. zb.width = width;
  2415. zb.height = height;
  2416. zBuffers.push_front(zb);
  2417. }
  2418. return surface;
  2419. }
  2420. //---------------------------------------------------------------------
  2421. void D3D9RenderSystem::cleanupDepthStencils(IDirect3DDevice9* d3d9Device)
  2422. {
  2423. for(ZBufferHash::iterator i = mZBufferHash.begin(); i != mZBufferHash.end();)
  2424. {
  2425. /// Release buffer
  2426. if (i->first.device == d3d9Device)
  2427. {
  2428. while (!i->second.empty())
  2429. {
  2430. IDirect3DSurface9* surface = i->second.front().surface;
  2431. surface->Release();
  2432. i->second.pop_front();
  2433. }
  2434. ZBufferHash::iterator deadi = i++;
  2435. mZBufferHash.erase(deadi);
  2436. }
  2437. else
  2438. {
  2439. ++i;
  2440. }
  2441. }
  2442. }
  2443. //---------------------------------------------------------------------
  2444. void D3D9RenderSystem::setClipPlanesImpl(const PlaneList& clipPlanes)
  2445. {
  2446. size_t i;
  2447. size_t numClipPlanes;
  2448. D3DXPLANE dx9ClipPlane;
  2449. DWORD mask = 0;
  2450. HRESULT hr;
  2451. numClipPlanes = clipPlanes.size();
  2452. for (i = 0; i < numClipPlanes; ++i)
  2453. {
  2454. const Plane& plane = clipPlanes[i];
  2455. dx9ClipPlane.a = plane.normal.x;
  2456. dx9ClipPlane.b = plane.normal.y;
  2457. dx9ClipPlane.c = plane.normal.z;
  2458. dx9ClipPlane.d = plane.d;
  2459. if (mVertexProgramBound)
  2460. {
  2461. // programmable clips in clip space (ugh)
  2462. // must transform worldspace planes by view/proj
  2463. D3DXMATRIX xform;
  2464. D3DXMatrixMultiply(&xform, &mDxViewMat, &mDxProjMat);
  2465. D3DXMatrixInverse(&xform, NULL, &xform);
  2466. D3DXMatrixTranspose(&xform, &xform);
  2467. D3DXPlaneTransform(&dx9ClipPlane, &dx9ClipPlane, &xform);
  2468. }
  2469. hr = getActiveD3D9Device()->SetClipPlane(static_cast<DWORD>(i), dx9ClipPlane);
  2470. if (FAILED(hr))
  2471. {
  2472. CM_EXCEPT(RenderingAPIException, "Unable to set clip plane");
  2473. }
  2474. mask |= (1 << i);
  2475. }
  2476. hr = __SetRenderState(D3DRS_CLIPPLANEENABLE, mask);
  2477. if (FAILED(hr))
  2478. {
  2479. CM_EXCEPT(RenderingAPIException, "Unable to set render state for clip planes");
  2480. }
  2481. }
  2482. //---------------------------------------------------------------------
  2483. D3D9RenderSystem::ZBufferIdentifier D3D9RenderSystem::getZBufferIdentifier(RenderTarget* rt)
  2484. {
  2485. // Retrieve render surfaces (up to CM_MAX_MULTIPLE_RENDER_TARGETS)
  2486. IDirect3DSurface9* pBack[CM_MAX_MULTIPLE_RENDER_TARGETS];
  2487. memset(pBack, 0, sizeof(pBack));
  2488. rt->getCustomAttribute_internal( "DDBACKBUFFER", &pBack );
  2489. assert(pBack[0]);
  2490. /// Request a depth stencil that is compatible with the format, multisample type and
  2491. /// dimensions of the render target.
  2492. D3DSURFACE_DESC srfDesc;
  2493. HRESULT hr = pBack[0]->GetDesc(&srfDesc);
  2494. assert(!(FAILED(hr)));
  2495. D3DFORMAT dsfmt = getDepthStencilFormatFor(srfDesc.Format);
  2496. assert(dsfmt != D3DFMT_UNKNOWN);
  2497. /// Build identifier and return
  2498. ZBufferIdentifier zBufferIdentifier;
  2499. zBufferIdentifier.format = dsfmt;
  2500. zBufferIdentifier.multisampleType = srfDesc.MultiSampleType;
  2501. zBufferIdentifier.device = getActiveD3D9Device();
  2502. return zBufferIdentifier;
  2503. }
  2504. //---------------------------------------------------------------------
  2505. HRESULT D3D9RenderSystem::__SetRenderState(D3DRENDERSTATETYPE state, DWORD value)
  2506. {
  2507. HRESULT hr;
  2508. DWORD oldVal;
  2509. if ( FAILED( hr = getActiveD3D9Device()->GetRenderState(state, &oldVal) ) )
  2510. return hr;
  2511. if ( oldVal == value )
  2512. return D3D_OK;
  2513. else
  2514. return getActiveD3D9Device()->SetRenderState(state, value);
  2515. }
  2516. //---------------------------------------------------------------------
  2517. HRESULT D3D9RenderSystem::__SetSamplerState(DWORD sampler, D3DSAMPLERSTATETYPE type, DWORD value)
  2518. {
  2519. HRESULT hr;
  2520. DWORD oldVal;
  2521. if ( FAILED( hr = getActiveD3D9Device()->GetSamplerState(sampler, type, &oldVal) ) )
  2522. return hr;
  2523. if ( oldVal == value )
  2524. return D3D_OK;
  2525. else
  2526. return getActiveD3D9Device()->SetSamplerState(sampler, type, value);
  2527. }
  2528. //---------------------------------------------------------------------
  2529. HRESULT D3D9RenderSystem::__SetTextureStageState(DWORD stage, D3DTEXTURESTAGESTATETYPE type, DWORD value)
  2530. {
  2531. HRESULT hr;
  2532. DWORD oldVal;
  2533. // can only set fixed-function texture stage state
  2534. if (stage < 8)
  2535. {
  2536. if ( FAILED( hr = getActiveD3D9Device()->GetTextureStageState(stage, type, &oldVal) ) )
  2537. return hr;
  2538. if ( oldVal == value )
  2539. return D3D_OK;
  2540. else
  2541. return getActiveD3D9Device()->SetTextureStageState(stage, type, value);
  2542. }
  2543. else
  2544. {
  2545. return D3D_OK;
  2546. }
  2547. }
  2548. //---------------------------------------------------------------------
  2549. DWORD D3D9RenderSystem::_getCurrentAnisotropy(UINT32 unit)
  2550. {
  2551. DWORD oldVal;
  2552. getActiveD3D9Device()->GetSamplerState(static_cast<DWORD>(unit), D3DSAMP_MAXANISOTROPY, &oldVal);
  2553. return oldVal;
  2554. }
  2555. //---------------------------------------------------------------------
  2556. bool D3D9RenderSystem::ZBufferIdentifierComparator::operator()( const ZBufferIdentifier& z0, const ZBufferIdentifier& z1 ) const
  2557. {
  2558. if (z0.device < z1.device)
  2559. return true;
  2560. if (z0.device == z1.device)
  2561. {
  2562. if (z0.format < z1.format)
  2563. return true;
  2564. if (z0.format == z1.format)
  2565. {
  2566. if (z0.multisampleType < z1.multisampleType)
  2567. return true;
  2568. }
  2569. }
  2570. return false;
  2571. }
  2572. }
  2573. #undef THROW_IF_NOT_RENDER_THREAD
  2574. #undef THROW_IF_NOT_RENDER_THREAD_STATIC