Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1506 lines
48 KiB

  1. /*==========================================================================;
  2. *
  3. * Copyright (C) 1998 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: d3ddev.cpp
  6. * Content: Direct3D device implementation
  7. *@@BEGIN_MSINTERNAL
  8. *
  9. * $Id: device.c,v 1.26 1995/12/04 11:29:47 sjl Exp $
  10. *
  11. *@@END_MSINTERNAL
  12. *
  13. ***************************************************************************/
  14. #include "pch.cpp"
  15. #pragma hdrstop
  16. /*
  17. * Create an api for the Direct3DDevice object
  18. */
  19. extern "C" {
  20. #define this _this
  21. #include "ddrawpr.h"
  22. #undef this
  23. }
  24. #include "drawprim.hpp"
  25. #include "fe.h"
  26. #include "enum.hpp"
  27. //#define APIPROF
  28. #ifdef APIPROF
  29. #include "apiprof.cpp"
  30. #endif //APIPROF
  31. #if defined(PROFILE4)
  32. #include <icecap.h>
  33. #elif defined(PROFILE)
  34. #include <icapexp.h>
  35. #endif
  36. // Remove DDraw's type unsafe definition and replace with our C++ friendly def
  37. #ifdef VALIDEX_CODE_PTR
  38. #undef VALIDEX_CODE_PTR
  39. #endif
  40. #define VALIDEX_CODE_PTR( ptr ) \
  41. (!IsBadCodePtr( (FARPROC) ptr ) )
  42. #undef DPF_MODNAME
  43. #define DPF_MODNAME "Direct3DDevice"
  44. extern void setIdentity(D3DMATRIXI * m);
  45. #ifndef PROFILE4
  46. #ifdef _X86_
  47. extern HRESULT D3DAPI katmai_FEContextCreate(DWORD dwFlags, LPD3DFE_PVFUNCS *lpLeafFuncs);
  48. extern HRESULT D3DAPI wlmt_FEContextCreate(DWORD dwFlags, LPD3DFE_PVFUNCS *lpLeafFuncs);
  49. extern HRESULT D3DAPI x3DContextCreate(DWORD dwFlags, LPD3DFE_PVFUNCS *lpLeafFuncs);
  50. #endif
  51. #endif
  52. #ifdef _X86_
  53. extern BOOL IsWin95();
  54. #endif
  55. extern HINSTANCE hMsGeometryDLL;
  56. // This is a list of all rstates that UpdateInternalState does some
  57. // work other than updating this->rstates[] array. This is used to
  58. // do a quick bitwise check to see if this rstate is trivial or not.
  59. const D3DRENDERSTATETYPE rsList[] = {
  60. // renderstates that either need runtime attention or that cannot be sent
  61. // to legacy drivers
  62. D3DRENDERSTATE_FOGENABLE,
  63. D3DRENDERSTATE_SPECULARENABLE,
  64. D3DRENDERSTATE_RANGEFOGENABLE,
  65. D3DRENDERSTATE_FOGDENSITY,
  66. D3DRENDERSTATE_FOGSTART,
  67. D3DRENDERSTATE_FOGEND,
  68. D3DRENDERSTATE_WRAP0,
  69. D3DRENDERSTATE_WRAP1,
  70. D3DRENDERSTATE_WRAP2,
  71. D3DRENDERSTATE_WRAP3,
  72. D3DRENDERSTATE_WRAP4,
  73. D3DRENDERSTATE_WRAP5,
  74. D3DRENDERSTATE_WRAP6,
  75. D3DRENDERSTATE_WRAP7,
  76. D3DRENDERSTATE_CLIPPING,
  77. D3DRENDERSTATE_LIGHTING,
  78. D3DRENDERSTATE_AMBIENT,
  79. D3DRENDERSTATE_FOGVERTEXMODE,
  80. D3DRENDERSTATE_COLORVERTEX,
  81. D3DRENDERSTATE_LOCALVIEWER,
  82. D3DRENDERSTATE_NORMALIZENORMALS,
  83. D3DRENDERSTATE_COLORKEYBLENDENABLE,
  84. D3DRENDERSTATE_DIFFUSEMATERIALSOURCE,
  85. D3DRENDERSTATE_SPECULARMATERIALSOURCE,
  86. D3DRENDERSTATE_AMBIENTMATERIALSOURCE,
  87. D3DRENDERSTATE_EMISSIVEMATERIALSOURCE,
  88. D3DRENDERSTATE_VERTEXBLEND,
  89. D3DRENDERSTATE_CLIPPLANEENABLE,
  90. D3DRENDERSTATE_SHADEMODE,
  91. D3DRS_SOFTWAREVERTEXPROCESSING,
  92. D3DRS_POINTSIZE,
  93. D3DRS_POINTSIZE_MIN,
  94. D3DRS_POINTSPRITEENABLE,
  95. D3DRS_POINTSCALEENABLE,
  96. D3DRS_POINTSCALE_A,
  97. D3DRS_POINTSCALE_B,
  98. D3DRS_POINTSCALE_C,
  99. D3DRS_MULTISAMPLEANTIALIAS,
  100. D3DRS_MULTISAMPLEMASK,
  101. D3DRS_PATCHEDGESTYLE,
  102. D3DRS_PATCHSEGMENTS,
  103. D3DRS_DEBUGMONITORTOKEN,
  104. D3DRS_POINTSIZE_MAX,
  105. D3DRS_INDEXEDVERTEXBLENDENABLE,
  106. D3DRS_COLORWRITEENABLE,
  107. D3DRS_TWEENFACTOR,
  108. D3DRS_DEBUGMONITORTOKEN,
  109. D3DRS_BLENDOP,
  110. D3DRS_PATCHSEGMENTS,
  111. // Retired renderstates to be filtered with DPF error and INVALID return
  112. // NOTE: everything listed here is also assumed to appear in rsListRetired
  113. D3DRENDERSTATE_TEXTUREHANDLE,
  114. D3DRENDERSTATE_TEXTUREADDRESS,
  115. D3DRENDERSTATE_WRAPU,
  116. D3DRENDERSTATE_WRAPV,
  117. D3DRENDERSTATE_MONOENABLE,
  118. D3DRENDERSTATE_ROP2,
  119. D3DRENDERSTATE_PLANEMASK,
  120. D3DRENDERSTATE_TEXTUREMAG,
  121. D3DRENDERSTATE_TEXTUREMIN,
  122. D3DRENDERSTATE_TEXTUREMAPBLEND,
  123. D3DRENDERSTATE_SUBPIXEL,
  124. D3DRENDERSTATE_SUBPIXELX,
  125. D3DRENDERSTATE_STIPPLEENABLE,
  126. D3DRENDERSTATE_BORDERCOLOR,
  127. D3DRENDERSTATE_TEXTUREADDRESSU,
  128. D3DRENDERSTATE_TEXTUREADDRESSV,
  129. D3DRENDERSTATE_MIPMAPLODBIAS,
  130. D3DRENDERSTATE_ANISOTROPY,
  131. D3DRENDERSTATE_TRANSLUCENTSORTINDEPENDENT,
  132. D3DRENDERSTATE_STIPPLEPATTERN00,
  133. D3DRENDERSTATE_STIPPLEPATTERN01,
  134. D3DRENDERSTATE_STIPPLEPATTERN02,
  135. D3DRENDERSTATE_STIPPLEPATTERN03,
  136. D3DRENDERSTATE_STIPPLEPATTERN04,
  137. D3DRENDERSTATE_STIPPLEPATTERN05,
  138. D3DRENDERSTATE_STIPPLEPATTERN06,
  139. D3DRENDERSTATE_STIPPLEPATTERN07,
  140. D3DRENDERSTATE_STIPPLEPATTERN08,
  141. D3DRENDERSTATE_STIPPLEPATTERN09,
  142. D3DRENDERSTATE_STIPPLEPATTERN10,
  143. D3DRENDERSTATE_STIPPLEPATTERN11,
  144. D3DRENDERSTATE_STIPPLEPATTERN12,
  145. D3DRENDERSTATE_STIPPLEPATTERN13,
  146. D3DRENDERSTATE_STIPPLEPATTERN14,
  147. D3DRENDERSTATE_STIPPLEPATTERN15,
  148. D3DRENDERSTATE_STIPPLEPATTERN16,
  149. D3DRENDERSTATE_STIPPLEPATTERN17,
  150. D3DRENDERSTATE_STIPPLEPATTERN18,
  151. D3DRENDERSTATE_STIPPLEPATTERN19,
  152. D3DRENDERSTATE_STIPPLEPATTERN20,
  153. D3DRENDERSTATE_STIPPLEPATTERN21,
  154. D3DRENDERSTATE_STIPPLEPATTERN22,
  155. D3DRENDERSTATE_STIPPLEPATTERN23,
  156. D3DRENDERSTATE_STIPPLEPATTERN24,
  157. D3DRENDERSTATE_STIPPLEPATTERN25,
  158. D3DRENDERSTATE_STIPPLEPATTERN26,
  159. D3DRENDERSTATE_STIPPLEPATTERN27,
  160. D3DRENDERSTATE_STIPPLEPATTERN28,
  161. D3DRENDERSTATE_STIPPLEPATTERN29,
  162. D3DRENDERSTATE_STIPPLEPATTERN30,
  163. D3DRENDERSTATE_STIPPLEPATTERN31,
  164. // newly retired for DX8
  165. D3DRENDERSTATE_ANTIALIAS,
  166. D3DRENDERSTATE_TEXTUREPERSPECTIVE,
  167. D3DRENDERSTATE_COLORKEYENABLE,
  168. D3DRENDERSTATE_COLORKEYBLENDENABLE,
  169. D3DRENDERSTATE_STIPPLEDALPHA,
  170. };
  171. // list of retired renderstates - need to make sure these are
  172. // filtered and never get from app directly to driver
  173. const D3DRENDERSTATETYPE rsListRetired[] = {
  174. D3DRENDERSTATE_TEXTUREHANDLE,
  175. D3DRENDERSTATE_TEXTUREADDRESS,
  176. D3DRENDERSTATE_WRAPU,
  177. D3DRENDERSTATE_WRAPV,
  178. D3DRENDERSTATE_MONOENABLE,
  179. D3DRENDERSTATE_ROP2,
  180. D3DRENDERSTATE_PLANEMASK,
  181. D3DRENDERSTATE_TEXTUREMAG,
  182. D3DRENDERSTATE_TEXTUREMIN,
  183. D3DRENDERSTATE_TEXTUREMAPBLEND,
  184. D3DRENDERSTATE_SUBPIXEL,
  185. D3DRENDERSTATE_SUBPIXELX,
  186. D3DRENDERSTATE_STIPPLEENABLE,
  187. D3DRENDERSTATE_BORDERCOLOR,
  188. D3DRENDERSTATE_TEXTUREADDRESSU,
  189. D3DRENDERSTATE_TEXTUREADDRESSV,
  190. D3DRENDERSTATE_MIPMAPLODBIAS,
  191. D3DRENDERSTATE_ANISOTROPY,
  192. D3DRENDERSTATE_TRANSLUCENTSORTINDEPENDENT,
  193. D3DRENDERSTATE_STIPPLEPATTERN00,
  194. D3DRENDERSTATE_STIPPLEPATTERN01,
  195. D3DRENDERSTATE_STIPPLEPATTERN02,
  196. D3DRENDERSTATE_STIPPLEPATTERN03,
  197. D3DRENDERSTATE_STIPPLEPATTERN04,
  198. D3DRENDERSTATE_STIPPLEPATTERN05,
  199. D3DRENDERSTATE_STIPPLEPATTERN06,
  200. D3DRENDERSTATE_STIPPLEPATTERN07,
  201. D3DRENDERSTATE_STIPPLEPATTERN08,
  202. D3DRENDERSTATE_STIPPLEPATTERN09,
  203. D3DRENDERSTATE_STIPPLEPATTERN10,
  204. D3DRENDERSTATE_STIPPLEPATTERN11,
  205. D3DRENDERSTATE_STIPPLEPATTERN12,
  206. D3DRENDERSTATE_STIPPLEPATTERN13,
  207. D3DRENDERSTATE_STIPPLEPATTERN14,
  208. D3DRENDERSTATE_STIPPLEPATTERN15,
  209. D3DRENDERSTATE_STIPPLEPATTERN16,
  210. D3DRENDERSTATE_STIPPLEPATTERN17,
  211. D3DRENDERSTATE_STIPPLEPATTERN18,
  212. D3DRENDERSTATE_STIPPLEPATTERN19,
  213. D3DRENDERSTATE_STIPPLEPATTERN20,
  214. D3DRENDERSTATE_STIPPLEPATTERN21,
  215. D3DRENDERSTATE_STIPPLEPATTERN22,
  216. D3DRENDERSTATE_STIPPLEPATTERN23,
  217. D3DRENDERSTATE_STIPPLEPATTERN24,
  218. D3DRENDERSTATE_STIPPLEPATTERN25,
  219. D3DRENDERSTATE_STIPPLEPATTERN26,
  220. D3DRENDERSTATE_STIPPLEPATTERN27,
  221. D3DRENDERSTATE_STIPPLEPATTERN28,
  222. D3DRENDERSTATE_STIPPLEPATTERN29,
  223. D3DRENDERSTATE_STIPPLEPATTERN30,
  224. D3DRENDERSTATE_STIPPLEPATTERN31,
  225. // newly retired for DX8
  226. D3DRENDERSTATE_ANTIALIAS,
  227. D3DRENDERSTATE_TEXTUREPERSPECTIVE,
  228. D3DRENDERSTATE_COLORKEYENABLE,
  229. D3DRENDERSTATE_COLORKEYBLENDENABLE,
  230. D3DRENDERSTATE_STIPPLEDALPHA,
  231. };
  232. /////////////////////////////////////////////////////////////////////////////
  233. // //
  234. // CD3DHal //
  235. // //
  236. /////////////////////////////////////////////////////////////////////////////
  237. //---------------------------------------------------------------------
  238. CD3DHal::CD3DHal()
  239. {
  240. //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  241. // DO NOT PUT INITIALIZATION IN THE CONSTRUCTOR.
  242. // Put it in Init() instead. This is because the device can be
  243. // "Destroy()ed" and "Init()ed" anytime via Reset. In this
  244. // situation, the constructor is never called. (snene 01/00)
  245. //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  246. }
  247. //---------------------------------------------------------------------
  248. #undef DPF_MODNAME
  249. #define DPF_MODNAME "CD3DHal::StateInitialize"
  250. void CD3DHal::StateInitialize(BOOL bZEnable)
  251. {
  252. DWORD i,j;
  253. // Initialize the bit array indicating the rstates needing non-trivial
  254. // work.
  255. for (i=0; i < sizeof(rsList) / sizeof(D3DRENDERSTATETYPE); ++i)
  256. rsVec.SetBit(rsList[i]);
  257. // Initialize the bit array indicating the retired rstates
  258. for (i=0; i < sizeof(rsListRetired) / sizeof(D3DRENDERSTATETYPE); ++i)
  259. rsVecRetired.SetBit(rsListRetired[i]);
  260. // Initialize the bit array indicating the vertex processing only rstates
  261. for (i=0; i < sizeof(rsVertexProcessingList) / sizeof(D3DRENDERSTATETYPE); ++i)
  262. rsVertexProcessingOnly.SetBit(rsVertexProcessingList[i]);
  263. // Obviate Set(Render;TextureStage)State filtering 'redundant' device state settings
  264. // since this is the init step.
  265. // memset( this->rstates, 0xff, sizeof(DWORD)*D3D_MAXRENDERSTATES);
  266. for (i=0; i<D3D_MAXRENDERSTATES; i++)
  267. this->rstates[i] = 0xbaadcafe;
  268. // memset( this->tsstates, 0xff, sizeof(DWORD)*D3DHAL_TSS_MAXSTAGES*D3DHAL_TSS_STATESPERSTAGE );
  269. for (j=0; j<D3DHAL_TSS_MAXSTAGES; j++)
  270. for (i=0; i<D3DHAL_TSS_STATESPERSTAGE; i++)
  271. this->tsstates[j][i] = 0xbaadcafe;
  272. CD3DBase::StateInitialize(bZEnable);
  273. if (GetDDIType() < D3DDDITYPE_DX8)
  274. {
  275. SetRenderStateInternal(D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE);
  276. SetRenderStateInternal(D3DRENDERSTATE_COLORKEYENABLE, FALSE);
  277. SetRenderStateInternal(D3DRENDERSTATE_COLORKEYBLENDENABLE, FALSE);
  278. SetRenderStateInternal(D3DRENDERSTATE_STIPPLEDALPHA, FALSE);
  279. }
  280. if (GetDDIType() < D3DDDITYPE_DX7)
  281. {
  282. // send retired renderstate init's to pre-DX7 HALs only
  283. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEENABLE, FALSE);
  284. SetRenderStateInternal( D3DRENDERSTATE_MONOENABLE, FALSE);
  285. SetRenderStateInternal( D3DRENDERSTATE_ROP2, R2_COPYPEN);
  286. SetRenderStateInternal( D3DRENDERSTATE_PLANEMASK, (DWORD)~0);
  287. SetRenderStateInternal( D3DRENDERSTATE_WRAPU, FALSE);
  288. SetRenderStateInternal( D3DRENDERSTATE_WRAPV, FALSE);
  289. SetRenderStateInternal( D3DRENDERSTATE_ANTIALIAS, FALSE);
  290. SetRenderStateInternal( D3DRENDERSTATE_SUBPIXEL, FALSE); /* 30 */
  291. SetRenderStateInternal( D3DRENDERSTATE_SUBPIXELX, FALSE);
  292. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN00, 0);
  293. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN01, 0); /* 40 */
  294. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN02, 0);
  295. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN03, 0);
  296. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN04, 0);
  297. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN05, 0);
  298. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN06, 0);
  299. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN07, 0);
  300. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN08, 0);
  301. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN09, 0);
  302. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN10, 0);
  303. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN11, 0); /* 50 */
  304. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN12, 0);
  305. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN13, 0);
  306. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN14, 0);
  307. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN15, 0);
  308. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN16, 0);
  309. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN17, 0);
  310. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN18, 0);
  311. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN19, 0);
  312. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN20, 0);
  313. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN21, 0); /* 60 */
  314. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN22, 0);
  315. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN23, 0);
  316. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN24, 0);
  317. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN25, 0);
  318. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN26, 0);
  319. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN27, 0);
  320. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN28, 0);
  321. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN29, 0);
  322. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN30, 0);
  323. SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN31, 0); /* 70 */
  324. }
  325. if( BehaviorFlags() & D3DCREATE_SOFTWARE_VERTEXPROCESSING )
  326. {
  327. SwitchVertexProcessingMode(TRUE);
  328. rstates[D3DRS_SOFTWAREVERTEXPROCESSING] = TRUE;
  329. }
  330. else if( BehaviorFlags() & D3DCREATE_HARDWARE_VERTEXPROCESSING )
  331. {
  332. SwitchVertexProcessingMode(FALSE);
  333. rstates[D3DRS_SOFTWAREVERTEXPROCESSING] = FALSE;
  334. }
  335. else if( BehaviorFlags() & D3DCREATE_MIXED_VERTEXPROCESSING )
  336. {
  337. SetRenderStateInternal( D3DRS_SOFTWAREVERTEXPROCESSING, 0);
  338. }
  339. else
  340. {
  341. D3D_INFO( 0, "No Vertex Processing behavior specified, assuming software" );
  342. SwitchVertexProcessingMode(TRUE);
  343. rstates[D3DRS_SOFTWAREVERTEXPROCESSING] = TRUE;
  344. }
  345. }
  346. /*
  347. * Initialisation - class part and device part
  348. */
  349. //---------------------------------------------------------------------
  350. HRESULT CD3DHal::D3DFE_Create()
  351. {
  352. DDSURFACEDESC ddsd;
  353. HRESULT hr;
  354. const D3DCAPS8 *pCaps = GetD3DCaps();
  355. if (m_pDDI->GetDDIType() < D3DDDITYPE_DX7)
  356. {
  357. m_dwRuntimeFlags |= D3DRT_ONLY2FLOATSPERTEXTURE;
  358. }
  359. else
  360. if (m_pDDI->GetDDIType() < D3DDDITYPE_DX8)
  361. {
  362. // Some drivers (G200, G400) cannot handle more than 2 floats in
  363. // texture coordinates, even they are supposed to. We set the
  364. // runtime bit to mark such drivers and compute output FVF for vertex
  365. // shaders accordingly
  366. if (!(pCaps->TextureCaps & D3DPTEXTURECAPS_PROJECTED ||
  367. pCaps->TextureCaps & D3DPTEXTURECAPS_CUBEMAP))
  368. {
  369. m_dwRuntimeFlags |= D3DRT_ONLY2FLOATSPERTEXTURE;
  370. }
  371. }
  372. if (!(pCaps->TextureCaps & D3DPTEXTURECAPS_PROJECTED))
  373. m_dwRuntimeFlags |= D3DRT_EMULATEPROJECTEDTEXTURE;
  374. if (pCaps && pCaps->FVFCaps)
  375. {
  376. this->m_pv->dwMaxTextureIndices =
  377. pCaps->FVFCaps & D3DFVFCAPS_TEXCOORDCOUNTMASK;
  378. if (pCaps->FVFCaps & D3DFVFCAPS_DONOTSTRIPELEMENTS)
  379. this->m_pv->dwDeviceFlags |= D3DDEV_DONOTSTRIPELEMENTS;
  380. DWORD value;
  381. if ((GetD3DRegValue(REG_DWORD, "DisableStripFVF", &value, 4) &&
  382. value != 0))
  383. {
  384. this->m_pv->dwDeviceFlags |= D3DDEV_DONOTSTRIPELEMENTS;
  385. }
  386. }
  387. else
  388. {
  389. this->m_pv->dwMaxTextureIndices = 1;
  390. }
  391. this->dwFEFlags |= D3DFE_FRONTEND_DIRTY;
  392. #if DBG
  393. this->dwCaller=0;
  394. memset(this->dwPrimitiveType,0,sizeof(this->dwPrimitiveType));
  395. memset(this->dwVertexType1,0,sizeof(this->dwVertexType1));
  396. memset(this->dwVertexType2,0,sizeof(this->dwVertexType2));
  397. #endif
  398. // True for software rendering
  399. m_dwNumStreams = __NUMSTREAMS;
  400. m_dwMaxUserClipPlanes = __MAXUSERCLIPPLANES;
  401. this->m_pv->dwClipMaskOffScreen = 0xFFFFFFFF;
  402. if (pCaps != NULL)
  403. {
  404. if (pCaps->GuardBandLeft != 0.0f ||
  405. pCaps->GuardBandRight != 0.0f ||
  406. pCaps->GuardBandTop != 0.0f ||
  407. pCaps->GuardBandBottom != 0.0f)
  408. {
  409. this->m_pv->dwDeviceFlags |= D3DDEV_GUARDBAND;
  410. this->m_pv->dwClipMaskOffScreen = ~__D3DCS_INGUARDBAND;
  411. DWORD v;
  412. if (GetD3DRegValue(REG_DWORD, "DisableGB", &v, 4) &&
  413. v != 0)
  414. {
  415. this->m_pv->dwDeviceFlags &= ~D3DDEV_GUARDBAND;
  416. this->m_pv->dwClipMaskOffScreen = 0xFFFFFFFF;
  417. }
  418. #if DBG
  419. // Try to get test values for the guard band
  420. char value[80];
  421. if (GetD3DRegValue(REG_SZ, "GuardBandLeft", &value, 80) &&
  422. value[0] != 0)
  423. sscanf(value, "%f", &pCaps->GuardBandLeft);
  424. if (GetD3DRegValue(REG_SZ, "GuardBandRight", &value, 80) &&
  425. value[0] != 0)
  426. sscanf(value, "%f", &pCaps->GuardBandRight);
  427. if (GetD3DRegValue(REG_SZ, "GuardBandTop", &value, 80) &&
  428. value[0] != 0)
  429. sscanf(value, "%f", &pCaps->GuardBandTop);
  430. if (GetD3DRegValue(REG_SZ, "GuardBandBottom", &value, 80) &&
  431. value[0] != 0)
  432. sscanf(value, "%f", &pCaps->GuardBandBottom);
  433. #endif // DBG
  434. }
  435. }
  436. LIST_INITIALIZE(&this->specular_tables);
  437. this->specular_table = NULL;
  438. this->lightVertexFuncTable = &lightVertexTable;
  439. m_pv->lighting.activeLights = NULL;
  440. this->m_ClipStatus.ClipUnion = 0;
  441. this->m_ClipStatus.ClipIntersection = ~0;
  442. m_pv->pDDI = m_pDDI;
  443. #if DBG
  444. m_pv->pDbgMon = m_pDbgMon;
  445. #endif
  446. return S_OK;
  447. }
  448. void CD3DHal::D3DFE_Destroy()
  449. {
  450. // Destroy lighting data
  451. SpecularTable *spec;
  452. SpecularTable *spec_next;
  453. for (spec = LIST_FIRST(&this->specular_tables); spec; spec = spec_next)
  454. {
  455. spec_next = LIST_NEXT(spec,list);
  456. D3DFree(spec);
  457. }
  458. LIST_INITIALIZE(&specular_tables);
  459. delete m_pLightArray;
  460. m_pLightArray = NULL;
  461. delete m_pv;
  462. m_pv = NULL;
  463. delete m_pConvObj;
  464. m_pConvObj = NULL;
  465. if (m_clrRects)
  466. {
  467. D3DFree(m_clrRects);
  468. m_clrRects = NULL;
  469. }
  470. }
  471. /*
  472. * Generic device part destroy
  473. */
  474. CD3DHal::~CD3DHal()
  475. {
  476. Destroy();
  477. }
  478. void
  479. CD3DHal::Destroy()
  480. {
  481. try // Since Destroy() can be called directly by fw
  482. {
  483. //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  484. // MUST CLEANUP AND RELEASE CURRENTLY SET TEXTURES BEFORE
  485. // DOING ANY OTHER WORK, else we will get into situations
  486. // where we are calling FlushStates or batching DDI tokens.
  487. CleanupTextures();
  488. //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  489. /* Clear flags that could prohibit cleanup */
  490. m_dwHintFlags &= ~(D3DDEVBOOL_HINTFLAGS_INSCENE);
  491. // Destroy vertex shaders. We need to delete vertex shaders completely
  492. // to preserve behavior for DX8.0 apps. For DX8.1 apps we delete only
  493. // PSGP part of a vertex shader. The rest will be used to re-create
  494. // the shader during Reset()
  495. if (m_pVShaderArray != NULL)
  496. {
  497. UINT size = m_pVShaderArray->GetSize();
  498. for (UINT i=0; i < size; i++)
  499. {
  500. UINT Handle = m_pVShaderArray->HandleFromIndex(i);
  501. CVShader* pShader = (CVShader*)m_pVShaderArray->GetObject(Handle);
  502. if (pShader)
  503. {
  504. if (Enum()->GetAppSdkVersion() == D3D_SDK_VERSION_DX8)
  505. {
  506. m_pVShaderArray->ReleaseHandle(Handle, TRUE);
  507. }
  508. else
  509. {
  510. // We need to delete PSGP shader object before deleting
  511. // D3DFE_PROCESSVERTICES object, because AMD has keeps a
  512. // pointer to it inside the code object
  513. if (pShader->m_dwFlags & CVShader::SOFTWARE)
  514. {
  515. delete pShader->m_pCode;
  516. pShader->m_pCode = NULL;
  517. }
  518. }
  519. }
  520. }
  521. }
  522. // Destroy pixel shaders for DX8.0 apps to preserve trhe original behavior
  523. if (m_pPShaderArray != NULL)
  524. {
  525. UINT size = m_pPShaderArray->GetSize();
  526. for (UINT i=0; i < size; i++)
  527. {
  528. UINT Handle = m_pPShaderArray->HandleFromIndex(i);
  529. CPShader* pShader = (CPShader*)m_pPShaderArray->GetObject(Handle);
  530. if (pShader)
  531. {
  532. if (Enum()->GetAppSdkVersion() == D3D_SDK_VERSION_DX8)
  533. {
  534. m_pPShaderArray->ReleaseHandle(Handle, TRUE);
  535. }
  536. }
  537. }
  538. }
  539. if (m_pv)
  540. {
  541. if ( 0 != m_pv->pGeometryFuncs &&
  542. (LPVOID)m_pv->pGeometryFuncs != (LPVOID)GeometryFuncsGuaranteed)
  543. {
  544. delete m_pv->pGeometryFuncs;
  545. m_pv->pGeometryFuncs = 0;
  546. }
  547. if ( 0 != GeometryFuncsGuaranteed)
  548. {
  549. delete GeometryFuncsGuaranteed;
  550. GeometryFuncsGuaranteed = 0;
  551. m_pv->pGeometryFuncs = 0;
  552. }
  553. }
  554. this->D3DFE_Destroy();
  555. if ( 0 != rstates)
  556. {
  557. delete[] rstates;
  558. rstates = 0;
  559. }
  560. delete pMatrixDirtyForDDI;
  561. pMatrixDirtyForDDI = NULL;
  562. CD3DBase::Destroy();
  563. }
  564. catch(HRESULT ret)
  565. {
  566. DPF_ERR("There was some error when Reset()ing the device; as a result some resources may not be freed.");
  567. }
  568. }
  569. /*
  570. * Create a device.
  571. *
  572. * This method
  573. * implements the CreateDevice method of the CEnum object. (The CEnum
  574. * object exposes the IDirect3D8 interface which supports enumeration
  575. * etc.)
  576. *
  577. */
  578. #undef DPF_MODNAME
  579. #define DPF_MODNAME "CEnum::CreateDevice"
  580. STDMETHODIMP CEnum::CreateDevice(
  581. UINT iAdapter,
  582. D3DDEVTYPE DeviceType,
  583. HWND hwndFocusWindow,
  584. DWORD dwFlags,
  585. D3DPRESENT_PARAMETERS *pPresentationParams,
  586. IDirect3DDevice8 **ppNewInterface)
  587. {
  588. API_ENTER(this);
  589. PD3D8_DEVICEDATA pDD;
  590. LPD3DBASE pd3ddev;
  591. HRESULT ret = D3D_OK;
  592. VOID* pInit = NULL;
  593. if (!VALID_PTR_PTR(ppNewInterface))
  594. {
  595. DPF_ERR("Invalid IDirect3DDevice8* pointer, CreateDevice fails");
  596. return D3DERR_INVALIDCALL;
  597. }
  598. // Zero out out parameters
  599. *ppNewInterface = NULL;
  600. if (!VALID_PTR(pPresentationParams, sizeof(D3DPRESENT_PARAMETERS)))
  601. {
  602. DPF_ERR("Invalid D3DPRESENT_PARAMETERS pointer, CreateDevice fails");
  603. return D3DERR_INVALIDCALL;
  604. }
  605. // Check that fullscreen parameters are correct
  606. if (pPresentationParams->Windowed)
  607. {
  608. if (pPresentationParams->FullScreen_RefreshRateInHz != 0)
  609. {
  610. DPF_ERR("FullScreen_RefreshRateInHz must be zero for windowed mode. CreateDevice fails.");
  611. return D3DERR_INVALIDCALL;
  612. }
  613. if (pPresentationParams->FullScreen_PresentationInterval != 0)
  614. {
  615. DPF_ERR("FullScreen_PresentationInterval must be zero for windowed mode. CreateDevice fails.");
  616. return D3DERR_INVALIDCALL;
  617. }
  618. }
  619. else
  620. {
  621. DWORD interval = pPresentationParams->FullScreen_PresentationInterval;
  622. switch (interval)
  623. {
  624. case D3DPRESENT_INTERVAL_DEFAULT:
  625. case D3DPRESENT_INTERVAL_ONE:
  626. case D3DPRESENT_INTERVAL_TWO:
  627. case D3DPRESENT_INTERVAL_THREE:
  628. case D3DPRESENT_INTERVAL_FOUR:
  629. case D3DPRESENT_INTERVAL_IMMEDIATE:
  630. break;
  631. default:
  632. DPF_ERR("Invalid value for FullScreen_PresentationInterval. CreateDevice Fails.");
  633. return D3DERR_INVALIDCALL;
  634. }
  635. }
  636. if (pPresentationParams->BackBufferFormat == D3DFMT_UNKNOWN)
  637. {
  638. DPF_ERR("Invalid backbuffer format specified. CreateDevice fails.");
  639. return D3DERR_INVALIDCALL;
  640. }
  641. if (pPresentationParams->Flags & ~D3DPRESENTFLAG_LOCKABLE_BACKBUFFER)
  642. {
  643. DPF_ERR("Invalid flag for Flags. CreateDevice fails.");
  644. return D3DERR_INVALIDCALL;
  645. }
  646. // Validate the HWNDs that we are given
  647. if (hwndFocusWindow && !IsWindow(hwndFocusWindow))
  648. {
  649. DPF_ERR("Invalid HWND specified for hwndFocusWindow, CreateDevice fails");
  650. return D3DERR_INVALIDCALL;
  651. }
  652. if (pPresentationParams->hDeviceWindow && !IsWindow(pPresentationParams->hDeviceWindow))
  653. {
  654. DPF_ERR("Invalid HWND specified for PresentationParams.hDeviceWindow. CreateDevice fails.");
  655. return D3DERR_INVALIDCALL;
  656. }
  657. // Make sure that we are given a focus window or a device window
  658. if (NULL == hwndFocusWindow)
  659. {
  660. if (!pPresentationParams->Windowed)
  661. {
  662. DPF_ERR("Fullscreen CreateDevice must specify Focus window");
  663. return D3DERR_INVALIDCALL;
  664. }
  665. else
  666. if (NULL == pPresentationParams->hDeviceWindow)
  667. {
  668. DPF_ERR("Neither hDeviceWindow nor Focus window specified. CreateDevice Failed.");
  669. return D3DERR_INVALIDCALL;
  670. }
  671. }
  672. if (iAdapter >= m_cAdapter)
  673. {
  674. DPF_ERR("Invalid iAdapter parameter passed to CreateDevice");
  675. return D3DERR_INVALIDCALL;
  676. }
  677. if (dwFlags & ~VALID_D3DCREATE_FLAGS)
  678. {
  679. DPF_ERR("Invalid BehaviorFlags passed to CreateDevice");
  680. return D3DERR_INVALIDCALL;
  681. }
  682. // Check that exactly one of the vertex processing flags is set
  683. DWORD dwVertexProcessingFlags = dwFlags & (D3DCREATE_HARDWARE_VERTEXPROCESSING |
  684. D3DCREATE_SOFTWARE_VERTEXPROCESSING |
  685. D3DCREATE_MIXED_VERTEXPROCESSING);
  686. if (dwVertexProcessingFlags != D3DCREATE_HARDWARE_VERTEXPROCESSING &&
  687. dwVertexProcessingFlags != D3DCREATE_SOFTWARE_VERTEXPROCESSING &&
  688. dwVertexProcessingFlags != D3DCREATE_MIXED_VERTEXPROCESSING)
  689. {
  690. DPF_ERR("Invalid Flags parameter to CreateDevice: Exactly One of the"
  691. " following must be set: D3DCREATE_HARDWARE_VERTEXPROCESSING,"
  692. " D3DCREATE_SOFTWARE_VERTEXPROCESSING or"
  693. " D3DCREATE_MIXED_VERTEXPROCESSING");
  694. return D3DERR_INVALIDCALL;
  695. }
  696. if (DeviceType == D3DDEVTYPE_SW)
  697. {
  698. pInit = m_pSwInitFunction;
  699. if (pInit == NULL)
  700. {
  701. D3D_ERR("App specified D3DDEVTYPE_SW without first registering a software device. CreateDevice Failed.");
  702. return D3DERR_INVALIDCALL;
  703. }
  704. GetSwCaps(iAdapter);
  705. }
  706. else if (DeviceType == D3DDEVTYPE_REF)
  707. {
  708. GetRefCaps(iAdapter);
  709. }
  710. ret = InternalDirectDrawCreate(&pDD,
  711. &m_AdapterInfo[iAdapter],
  712. DeviceType,
  713. pInit,
  714. GetUnknown16(iAdapter),
  715. m_AdapterInfo[iAdapter].HALCaps.pGDD8SupportedFormatOps,
  716. m_AdapterInfo[iAdapter].HALCaps.GDD8NumSupportedFormatOps);
  717. if( FAILED(ret) )
  718. {
  719. D3D_ERR("Failed to create DirectDraw. CreateDevice Failed.");
  720. return ret;
  721. }
  722. if((dwFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING) != 0)
  723. {
  724. if((dwFlags & D3DCREATE_PUREDEVICE) != 0)
  725. {
  726. D3D_ERR("Pure device cannot perform software processing. CreateDevice Failed.");
  727. InternalDirectDrawRelease(pDD);
  728. return D3DERR_INVALIDCALL;
  729. }
  730. }
  731. else if((dwFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING) != 0)
  732. {
  733. if((pDD->DriverData.D3DCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
  734. == 0)
  735. {
  736. D3D_ERR("Device cannot perform hardware processing");
  737. InternalDirectDrawRelease(pDD);
  738. return D3DERR_INVALIDCALL;
  739. }
  740. }
  741. else if((dwFlags & D3DCREATE_MIXED_VERTEXPROCESSING) != 0)
  742. {
  743. if((pDD->DriverData.D3DCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 ||
  744. (dwFlags & D3DCREATE_PUREDEVICE) != 0)
  745. {
  746. D3D_ERR("Device cannot perform mixed processing because driver cannot do hardware T&L. CreateDevice Failed.");
  747. InternalDirectDrawRelease(pDD);
  748. return D3DERR_INVALIDCALL;
  749. }
  750. }
  751. else
  752. {
  753. if((dwFlags & D3DCREATE_PUREDEVICE) != 0)
  754. {
  755. if((pDD->DriverData.D3DCaps.DevCaps & D3DDEVCAPS_PUREDEVICE) == 0)
  756. {
  757. D3D_ERR("Hardware should be capable of creating a pure device");
  758. InternalDirectDrawRelease(pDD);
  759. return D3DERR_INVALIDCALL;
  760. }
  761. }
  762. else
  763. {
  764. D3D_ERR("Must specify software, hardware or mixed vertex processing");
  765. InternalDirectDrawRelease(pDD);
  766. return D3DERR_INVALIDCALL;
  767. }
  768. }
  769. switch (DeviceType)
  770. {
  771. case D3DDEVTYPE_SW:
  772. case D3DDEVTYPE_REF:
  773. case D3DDEVTYPE_HAL:
  774. if (dwFlags & D3DCREATE_PUREDEVICE)
  775. {
  776. pd3ddev = new CD3DBase();
  777. }
  778. else
  779. {
  780. pd3ddev = static_cast<LPD3DBASE>(new CD3DHal());
  781. }
  782. break;
  783. default:
  784. D3D_ERR("Unrecognized or unsupported DeviceType. CreateDevice Failed.");
  785. InternalDirectDrawRelease(pDD);
  786. return D3DERR_INVALIDCALL;
  787. }
  788. if (!pd3ddev)
  789. {
  790. D3D_ERR("Failed to allocate space for the device object. CreateDevice Failed.");
  791. InternalDirectDrawRelease(pDD);
  792. return (E_OUTOFMEMORY);
  793. }
  794. #if DBG
  795. {
  796. char DevTypeMsg[256];
  797. _snprintf( DevTypeMsg, 256, "=======================" );
  798. switch( DeviceType )
  799. {
  800. case D3DDEVTYPE_HAL:
  801. _snprintf( DevTypeMsg, 256, "%s Hal", DevTypeMsg );
  802. break;
  803. case D3DDEVTYPE_SW:
  804. _snprintf( DevTypeMsg, 256, "%s Pluggable SW", DevTypeMsg );
  805. break;
  806. case D3DDEVTYPE_REF:
  807. _snprintf( DevTypeMsg, 256, "%s Reference", DevTypeMsg );
  808. break;
  809. default:
  810. _snprintf( DevTypeMsg, 256, "%s Unknown", DevTypeMsg );
  811. break;
  812. }
  813. if (dwFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING)
  814. {
  815. _snprintf( DevTypeMsg, 256, "%s HWVP", DevTypeMsg );
  816. }
  817. else if (dwFlags & D3DCREATE_MIXED_VERTEXPROCESSING)
  818. {
  819. _snprintf( DevTypeMsg, 256, "%s MixedVP", DevTypeMsg );
  820. }
  821. else if (dwFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING)
  822. {
  823. _snprintf( DevTypeMsg, 256, "%s SWVP", DevTypeMsg );
  824. }
  825. if (dwFlags & D3DCREATE_PUREDEVICE)
  826. {
  827. _snprintf( DevTypeMsg, 256, "%s Pure", DevTypeMsg );
  828. }
  829. _snprintf( DevTypeMsg, 256, "%s device selected", DevTypeMsg );
  830. D3D_INFO( 0, DevTypeMsg );
  831. }
  832. #endif
  833. //
  834. // FW's Init
  835. //
  836. ret = static_cast<CBaseDevice*>(pd3ddev)->Init(
  837. pDD,
  838. DeviceType,
  839. hwndFocusWindow,
  840. dwFlags,
  841. pPresentationParams,
  842. iAdapter,
  843. this);
  844. if (FAILED(ret))
  845. {
  846. D3D_ERR("Failed to initialize Framework Device. CreateDevice Failed.");
  847. delete pd3ddev;
  848. return ret;
  849. }
  850. // We try and create a dummy vidmem vertexbuffer. If this doesn't
  851. // succeed, we just turn off vidmem VBs. This is to work around
  852. // the Rage 128 driver that reports DDERR_OUTOFVIDEOMEMORY even
  853. // though it simply doesn't support vidmem VBs
  854. if(!IS_DX8HAL_DEVICE(pd3ddev))
  855. {
  856. #ifdef WIN95
  857. //ON 9x we probe to see if the driver can do vidmem VBs...
  858. CVertexBuffer *pVertexBuffer;
  859. ret = CVertexBuffer::CreateDriverVertexBuffer(pd3ddev,
  860. 1024,
  861. D3DFVF_TLVERTEX,
  862. D3DUSAGE_WRITEONLY | D3DUSAGE_DONOTCLIP,
  863. D3DUSAGE_WRITEONLY | D3DUSAGE_DONOTCLIP | D3DUSAGE_LOCK,
  864. D3DPOOL_DEFAULT,
  865. D3DPOOL_DEFAULT,
  866. REF_INTERNAL,
  867. &pVertexBuffer);
  868. if(FAILED(ret))
  869. {
  870. if(pd3ddev->VBFailOversDisabled())
  871. {
  872. DPF_ERR("Cannot create Vidmem vertex buffer. Will ***NOT*** failover to Sysmem.");
  873. return ret;
  874. }
  875. DPF(1,"Driver doesnt support VidMemVBs which is fine");
  876. }
  877. else
  878. {
  879. // Get rid of the vb
  880. pVertexBuffer->DecrementUseCount();
  881. pd3ddev->EnableVidmemVBs();
  882. }
  883. #else //WIN95
  884. //On NT we require the drivers to tell us (by setting D3DDEVCAPS_HWVERTEXBUFFER)
  885. //Turn off DX7 driver VBs on NT if asked to do so...
  886. DWORD value;
  887. if ((GetD3DRegValue(REG_DWORD, "DisableVidMemVBs", &value, 4) != 0) &&
  888. (value != 0))
  889. {
  890. pd3ddev->DisableVidmemVBs();
  891. }
  892. #endif //!WIN95
  893. }
  894. ret = pd3ddev->Init();
  895. if (ret != D3D_OK)
  896. {
  897. delete pd3ddev;
  898. D3D_ERR("Failed to initialize D3DDevice. CreateDevice Failed.");
  899. return ret;
  900. }
  901. // Looks like everything is in order
  902. *ppNewInterface = static_cast<IDirect3DDevice8*>(pd3ddev);
  903. #ifdef APIPROF
  904. CApiProfileDevice* profile = new CApiProfileDevice;
  905. if (profile)
  906. {
  907. if (profile->Init() == D3D_OK)
  908. {
  909. profile->SetDevice(*ppNewInterface);
  910. *ppNewInterface = static_cast<IDirect3DDevice8*>(profile);
  911. }
  912. else
  913. {
  914. delete profile;
  915. }
  916. }
  917. #endif // APIPROF
  918. return S_OK;
  919. }
  920. #ifdef _X86_
  921. // --------------------------------------------------------------------------
  922. // Detect 3D extensions
  923. // --------------------------------------------------------------------------
  924. BOOL _asm_isX3D()
  925. {
  926. DWORD retval = 0;
  927. _asm
  928. {
  929. pushad ; CPUID trashes lots - save everything
  930. mov eax,80000000h ; Check for extended CPUID support
  931. ;;; We need to upgrade our compiler
  932. ;;; CPUID == 0f,a2
  933. _emit 0x0f
  934. _emit 0xa2
  935. cmp eax,80000001h ; Jump if no extended CPUID
  936. jb short done ;
  937. mov eax,80000001h ; Check for feature
  938. ;;; CPUID == 0f,a2
  939. _emit 0x0f
  940. _emit 0xa2
  941. xor eax,eax ;
  942. test edx,80000000h ;
  943. setnz al ;
  944. mov retval,eax ;
  945. done:
  946. popad ; Restore everything
  947. };
  948. return retval;
  949. }
  950. static BOOL isX3Dprocessor(void)
  951. {
  952. __try
  953. {
  954. if( _asm_isX3D() )
  955. {
  956. return TRUE;
  957. }
  958. }
  959. __except(GetExceptionCode() == STATUS_ILLEGAL_INSTRUCTION ?
  960. EXCEPTION_EXECUTE_HANDLER :
  961. EXCEPTION_CONTINUE_SEARCH)
  962. {
  963. }
  964. return FALSE;
  965. }
  966. //---------------------------------------------------------------------
  967. // Detects Intel SSE processor
  968. //
  969. #pragma optimize("", off)
  970. #define CPUID _asm _emit 0x0f _asm _emit 0xa2
  971. #define SSE_PRESENT 0x02000000 // bit number 25
  972. #define WNI_PRESENT 0x04000000 // bit number 26
  973. DWORD IsIntelSSEProcessor(void)
  974. {
  975. DWORD retval = 0;
  976. DWORD RegisterEAX;
  977. DWORD RegisterEDX;
  978. char VendorId[12];
  979. const char IntelId[13]="GenuineIntel";
  980. __try
  981. {
  982. _asm {
  983. xor eax,eax
  984. CPUID
  985. mov RegisterEAX, eax
  986. mov dword ptr VendorId, ebx
  987. mov dword ptr VendorId+4, edx
  988. mov dword ptr VendorId+8, ecx
  989. }
  990. } __except (1)
  991. {
  992. return retval;
  993. }
  994. // make sure EAX is > 0 which means the chip
  995. // supports a value >=1. 1 = chip info
  996. if (RegisterEAX == 0)
  997. return retval;
  998. // this CPUID can't fail if the above test passed
  999. __asm {
  1000. mov eax,1
  1001. CPUID
  1002. mov RegisterEAX,eax
  1003. mov RegisterEDX,edx
  1004. }
  1005. if (RegisterEDX & SSE_PRESENT) {
  1006. retval |= D3DCPU_SSE;
  1007. }
  1008. if (RegisterEDX & WNI_PRESENT) {
  1009. retval |= D3DCPU_WLMT;
  1010. }
  1011. return retval;
  1012. }
  1013. #pragma optimize("", on)
  1014. // IsProcessorFeatureAvailable() is supported only by WINNT. For other OS
  1015. // we emulate it
  1016. #ifdef WINNT
  1017. static BOOL D3DIsProcessorFeaturePresent(UINT feature)
  1018. {
  1019. switch (feature)
  1020. {
  1021. // WINNT does not recognize Willamette processor when we use
  1022. // PF_XMMI64_INSTRUCTIONS_AVAILABLE, so use our detection instead
  1023. case PF_XMMI64_INSTRUCTIONS_AVAILABLE:
  1024. {
  1025. DWORD flags = IsIntelSSEProcessor();
  1026. return flags & D3DCPU_WLMT;
  1027. }
  1028. default: return IsProcessorFeaturePresent(feature);
  1029. }
  1030. }
  1031. #else
  1032. #define PF_XMMI_INSTRUCTIONS_AVAILABLE 6
  1033. #define PF_3DNOW_INSTRUCTIONS_AVAILABLE 7
  1034. #define PF_XMMI64_INSTRUCTIONS_AVAILABLE 10
  1035. static BOOL D3DIsProcessorFeaturePresent(UINT feature)
  1036. {
  1037. switch (feature)
  1038. {
  1039. case PF_XMMI_INSTRUCTIONS_AVAILABLE:
  1040. {
  1041. if (IsWin95())
  1042. return FALSE;
  1043. DWORD flags = IsIntelSSEProcessor();
  1044. return flags & D3DCPU_SSE;
  1045. }
  1046. case PF_3DNOW_INSTRUCTIONS_AVAILABLE: return isX3Dprocessor();
  1047. case PF_XMMI64_INSTRUCTIONS_AVAILABLE:
  1048. {
  1049. if (IsWin95())
  1050. return FALSE;
  1051. DWORD flags = IsIntelSSEProcessor();
  1052. return flags & D3DCPU_WLMT;
  1053. }
  1054. default: return FALSE;
  1055. }
  1056. }
  1057. #endif // WINNT
  1058. #endif // _X86_
  1059. //------------------------------------------------------------------------------
  1060. #undef DPF_MODNAME
  1061. #define DPF_MODNAME "CD3DHal::InitDevice"
  1062. HRESULT
  1063. CD3DHal::InitDevice()
  1064. {
  1065. HRESULT ret;
  1066. // Initialize values so we don't crash at shutdown
  1067. this->GeometryFuncsGuaranteed = NULL;
  1068. this->rstates = NULL;
  1069. m_pLightArray = NULL;
  1070. m_pv = NULL;
  1071. m_pCurrentShader = NULL;
  1072. m_pConvObj = NULL;
  1073. pMatrixDirtyForDDI = NULL;
  1074. m_clrRects = NULL;
  1075. m_clrCount = 0;
  1076. m_pv = new D3DFE_PROCESSVERTICES;
  1077. if (m_pv == NULL)
  1078. {
  1079. D3D_ERR("Could not allocate the FE/PSGP data structure (D3DFE_PROCESSVERTICES).");
  1080. return E_OUTOFMEMORY;
  1081. }
  1082. m_pv->pGeometryFuncs = NULL;
  1083. ret = CD3DBase::InitDevice();
  1084. if (ret != D3D_OK)
  1085. {
  1086. D3D_ERR("Failed to initialize CD3DBase.");
  1087. return(ret);
  1088. }
  1089. pMatrixDirtyForDDI = new CPackedBitArray;
  1090. if( pMatrixDirtyForDDI == NULL )
  1091. {
  1092. D3D_ERR("Could not allocate memory for internal data structure pMatrixDirtyForDDI.");
  1093. return E_OUTOFMEMORY;
  1094. }
  1095. if (FAILED(rsVec.Init(D3D_MAXRENDERSTATES)) ||
  1096. FAILED(rsVecRetired.Init(D3D_MAXRENDERSTATES)) ||
  1097. FAILED(rsVertexProcessingOnly.Init(D3D_MAXRENDERSTATES)) ||
  1098. FAILED(pMatrixDirtyForDDI->Init(D3D_MAXTRANSFORMSTATES)))
  1099. {
  1100. D3D_ERR("Could not allocate memory for renderstate processing bit vectors");
  1101. return E_OUTOFMEMORY;
  1102. }
  1103. m_pLightArray = new CHandleArray;
  1104. if (m_pLightArray == NULL)
  1105. {
  1106. D3D_ERR("Could not allocate memory for internal data structure m_pLightArray");
  1107. return E_OUTOFMEMORY;
  1108. }
  1109. dwFEFlags = 0;
  1110. // Initialize FEFlags content that depends on DDI type
  1111. if ( (GetDDIType() == D3DDDITYPE_DX7TL) ||
  1112. (GetDDIType() == D3DDDITYPE_DX8TL) )
  1113. dwFEFlags |= D3DFE_TLHAL;
  1114. // Since this is HAL, initialize it to use the software pipeline
  1115. // this will be turned off when the SW/HW renderstate is set.
  1116. m_pv->dwVIDIn = 0;
  1117. m_pv->pD3DMappedTexI = (LPVOID*)(m_lpD3DMappedTexI);
  1118. /*-------------------------------------------------------------------------
  1119. * Up till now we have done the easy part of the initialization. This is
  1120. * the stuff that cannot fail. It initializes the object so that the
  1121. * destructor can be safely called if any of the further initialization
  1122. * does not succeed.
  1123. *-----------------------------------------------------------------------*/
  1124. this->GeometryFuncsGuaranteed = new D3DFE_PVFUNCSI;
  1125. if (this->GeometryFuncsGuaranteed == NULL)
  1126. {
  1127. D3D_ERR("Could not allocate memory for internal data structure GeometryFuncsGuaranteed");
  1128. return E_OUTOFMEMORY;
  1129. }
  1130. // Software constant register buffer must handle all constants, provided by
  1131. // hardware, to make Set/Get constants possible
  1132. this->GeometryFuncsGuaranteed->m_VertexVM.Init(GetD3DCaps()->MaxVertexShaderConst);
  1133. m_pv->pGeometryFuncs = (LPD3DFE_PVFUNCS)GeometryFuncsGuaranteed;
  1134. if (this->GeometryFuncsGuaranteed == NULL)
  1135. {
  1136. D3D_ERR("Could not allocate memory for FE/PSGP function table.");
  1137. return D3DERR_INVALIDCALL;
  1138. }
  1139. // set up flag to use MMX when requested RGB
  1140. BOOL bUseMMXAsRGBDevice = FALSE;
  1141. D3DSURFACE_DESC desc = this->RenderTarget()->InternalGetDesc();
  1142. /*
  1143. * Check if the 3D cap is set on the surface.
  1144. */
  1145. if ((desc.Usage & D3DUSAGE_RENDERTARGET) == 0)
  1146. {
  1147. D3D_ERR("**** The D3DUSAGE_RENDERTARGET is not set on this surface.");
  1148. D3D_ERR("**** You need to add D3DUSAGE_RENDERTARGET to the Usage parameter");
  1149. D3D_ERR("**** when creating the surface.");
  1150. return (D3DERR_INVALIDCALL);
  1151. }
  1152. // Create front-end support structures.
  1153. ret = this->D3DFE_Create();
  1154. if (ret != D3D_OK)
  1155. {
  1156. D3D_ERR("Failed to create front-end data-structures.");
  1157. goto handle_err;
  1158. }
  1159. // In all other cases we simply allocate memory for rstates
  1160. rstates = new DWORD[D3D_MAXRENDERSTATES];
  1161. m_pv->lpdwRStates = this->rstates;
  1162. #ifndef PROFILE4
  1163. #ifdef _X86_
  1164. if ((ULONG_PTR)&m_pv->view & 0xF)
  1165. {
  1166. char s[256];
  1167. sprintf(s, "0%xh \n", (ULONG_PTR)&m_pv->view);
  1168. OutputDebugString("INTERNAL ERROR:View matrix in D3DFE_PROCESSVERTICES structure must be aligned to 16 bytes\n");
  1169. OutputDebugString(s);
  1170. ret = D3DERR_INVALIDCALL;
  1171. goto handle_err;
  1172. }
  1173. // Check if we have a processor specific implementation available
  1174. // only use if DisablePSGP is not in registry or set to zero
  1175. DWORD value;
  1176. if (!GetD3DRegValue(REG_DWORD, "DisablePSGP", &value, sizeof(DWORD)))
  1177. {
  1178. value = 0;
  1179. }
  1180. #if DBG
  1181. if (m_pDbgMon && m_pDbgMon->MonitorConnected())
  1182. {
  1183. value = 1;
  1184. }
  1185. #endif
  1186. // value =
  1187. // 0 - PSGP enabled
  1188. // 1 - PSGP disabled
  1189. // 2 - X3D PSGP disabled
  1190. if (value != 1)
  1191. {
  1192. // Ask the PV implementation to create a device specific "context"
  1193. LPD3DFE_PVFUNCS pOptGeoFuncs = m_pv->pGeometryFuncs;
  1194. // TODO (bug 40438): Remove DLL interface for final
  1195. // Try to use PSGP DLL first
  1196. if (pfnFEContextCreate)
  1197. {
  1198. ret = pfnFEContextCreate(m_pv->dwDeviceFlags, &pOptGeoFuncs);
  1199. if ((ret == D3D_OK) && pOptGeoFuncs)
  1200. {
  1201. D3D_INFO(0, "Using PSGP DLL");
  1202. m_pv->pGeometryFuncs = pOptGeoFuncs;
  1203. goto l_chosen;
  1204. }
  1205. }
  1206. if (D3DIsProcessorFeaturePresent(PF_3DNOW_INSTRUCTIONS_AVAILABLE) &&
  1207. value != 2)
  1208. {
  1209. ret = x3DContextCreate(m_pv->dwDeviceFlags, &pOptGeoFuncs);
  1210. if (ret == S_OK && pOptGeoFuncs)
  1211. {
  1212. D3D_INFO(0, "Using X3D PSGP");
  1213. m_pv->pGeometryFuncs = pOptGeoFuncs;
  1214. goto l_chosen;
  1215. }
  1216. }
  1217. if (D3DIsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE))
  1218. {
  1219. ret = wlmt_FEContextCreate(m_pv->dwDeviceFlags, &pOptGeoFuncs);
  1220. if (ret == S_OK && pOptGeoFuncs)
  1221. {
  1222. D3D_INFO(0, "Using WLMT PSGP");
  1223. m_pv->pGeometryFuncs = pOptGeoFuncs;
  1224. goto l_chosen;
  1225. }
  1226. }
  1227. if (D3DIsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE))
  1228. {
  1229. ret = katmai_FEContextCreate(m_pv->dwDeviceFlags, &pOptGeoFuncs);
  1230. if (ret == S_OK && pOptGeoFuncs)
  1231. {
  1232. D3D_INFO(0, "Using P3 PSGP");
  1233. m_pv->pGeometryFuncs = pOptGeoFuncs;
  1234. goto l_chosen;
  1235. }
  1236. }
  1237. l_chosen:;
  1238. }
  1239. #endif // _X86_
  1240. #endif // PROFILE4
  1241. {
  1242. if (HVbuf.Grow((__INIT_VERTEX_NUMBER*2)*sizeof(D3DFE_CLIPCODE)) != DD_OK)
  1243. {
  1244. D3D_ERR( "Could not allocate memory for internal buffer HVBuf" );
  1245. ret = E_OUTOFMEMORY;
  1246. goto handle_err;
  1247. }
  1248. }
  1249. // Setup lights
  1250. if( FAILED( m_pLightArray->Grow( 8 ) ) )
  1251. {
  1252. D3D_ERR( "Could not allocate memory for the light array" );
  1253. ret = E_OUTOFMEMORY;
  1254. goto handle_err;
  1255. }
  1256. LIST_INITIALIZE(&m_ActiveLights);
  1257. // Setup material
  1258. memset(&m_pv->lighting.material, 0, sizeof(m_pv->lighting.material));
  1259. // Set viewport to update front-end data
  1260. SetViewportI(&m_Viewport);
  1261. m_pv->PointSizeMax = GetD3DCaps()->MaxPointSize;
  1262. {
  1263. DWORD EmulatePointSprites = 1;
  1264. GetD3DRegValue(REG_DWORD, "EmulatePointSprites", &EmulatePointSprites, sizeof(DWORD));
  1265. if ((m_pv->PointSizeMax == 0 || !(GetD3DCaps()->FVFCaps & D3DFVFCAPS_PSIZE)) &&
  1266. EmulatePointSprites)
  1267. {
  1268. m_dwRuntimeFlags |= D3DRT_DOPOINTSPRITEEMULATION;
  1269. if (m_pv->PointSizeMax == 0)
  1270. m_pv->PointSizeMax = __MAX_POINT_SIZE;
  1271. else
  1272. m_dwRuntimeFlags |= D3DRT_SUPPORTSPOINTSPRITES;
  1273. }
  1274. }
  1275. m_pfnPrepareToDraw = NULL;
  1276. return (D3D_OK);
  1277. handle_err:
  1278. return(ret);
  1279. }
  1280. //---------------------------------------------------------------------
  1281. DWORD
  1282. ProcessRects(CD3DHal* pDevI, DWORD dwCount, CONST D3DRECT* rects)
  1283. {
  1284. RECT vwport;
  1285. DWORD i,j;
  1286. /*
  1287. * Rip through the rects and validate that they
  1288. * are within the viewport.
  1289. */
  1290. if (dwCount == 0 && rects == NULL)
  1291. {
  1292. dwCount = 1;
  1293. }
  1294. #if DBG
  1295. else if (rects == NULL)
  1296. {
  1297. D3D_ERR("The rects parameter is NULL.");
  1298. throw D3DERR_INVALIDCALL;
  1299. }
  1300. #endif
  1301. if (dwCount > pDevI->m_clrCount)
  1302. {
  1303. LPD3DRECT newRects;
  1304. if (D3D_OK == D3DMalloc((void**)&newRects, dwCount * sizeof(D3DRECT)))
  1305. {
  1306. memcpy((void*)newRects,(void*)pDevI->m_clrRects,
  1307. pDevI->m_clrCount* sizeof(D3DRECT));
  1308. D3DFree((LPVOID)pDevI->m_clrRects);
  1309. pDevI->m_clrRects = newRects;
  1310. }
  1311. else
  1312. {
  1313. pDevI->m_clrCount = 0;
  1314. D3DFree((LPVOID)pDevI->m_clrRects);
  1315. pDevI->m_clrRects = NULL;
  1316. D3D_ERR("failed to allocate space for rects");
  1317. throw E_OUTOFMEMORY;
  1318. }
  1319. }
  1320. pDevI->m_clrCount = dwCount;
  1321. // If nothing is specified, assume the viewport needs to be cleared
  1322. if (!rects)
  1323. {
  1324. pDevI->m_clrRects[0].x1 = pDevI->m_Viewport.X;
  1325. pDevI->m_clrRects[0].y1 = pDevI->m_Viewport.Y;
  1326. pDevI->m_clrRects[0].x2 = pDevI->m_Viewport.X + pDevI->m_Viewport.Width;
  1327. pDevI->m_clrRects[0].y2 = pDevI->m_Viewport.Y + pDevI->m_Viewport.Height;
  1328. return 1;
  1329. }
  1330. else
  1331. {
  1332. vwport.left = pDevI->m_Viewport.X;
  1333. vwport.top = pDevI->m_Viewport.Y;
  1334. vwport.right = pDevI->m_Viewport.X + pDevI->m_Viewport.Width;
  1335. vwport.bottom = pDevI->m_Viewport.Y + pDevI->m_Viewport.Height;
  1336. j=0;
  1337. for (i = 0; i < dwCount; i++)
  1338. {
  1339. if (IntersectRect((LPRECT)(pDevI->m_clrRects + j), &vwport, (LPRECT)(rects + i)))
  1340. j++;
  1341. }
  1342. return j;
  1343. }
  1344. }
  1345. //---------------------------------------------------------------------
  1346. #undef DPF_MODNAME
  1347. #define DPF_MODNAME "CD3DHal::ClearI"
  1348. void
  1349. CD3DHal::ClearI(DWORD dwCount,
  1350. CONST D3DRECT* rects,
  1351. DWORD dwFlags,
  1352. D3DCOLOR dwColor,
  1353. D3DVALUE dvZ,
  1354. DWORD dwStencil)
  1355. {
  1356. dwCount = ProcessRects(this, dwCount, rects);
  1357. // Device should never receive 0 count, because for Pure device this
  1358. // means "clear whole viewport"
  1359. if (dwCount != 0)
  1360. {
  1361. // Call DDI specific Clear routine
  1362. m_pDDI->Clear(dwFlags, dwCount, m_clrRects, dwColor, dvZ, dwStencil);
  1363. }
  1364. }