Leaked source code of windows server 2003
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.

1405 lines
51 KiB

  1. /*==========================================================================;
  2. *
  3. * Copyright (C) 1997 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: dpoldhal.c
  6. * Content: DrawPrimitive implementation for legacy (DX2) HALs
  7. *
  8. ***************************************************************************/
  9. #include "pch.cpp"
  10. #pragma hdrstop
  11. #include "drawprim.hpp"
  12. #include "clipfunc.h"
  13. #include "commdrv.hpp"
  14. extern D3DLINE LineListPrecomp[];
  15. extern D3DLINE LineStripPrecomp[];
  16. extern D3DTRIANGLE TriangleListPrecomp[];
  17. extern D3DTRIANGLE TriangleStripPrecomp[];
  18. extern D3DTRIANGLE TriangleFanPrecomp[];
  19. #define BFCULLTEST_TVertTri(TLV0,TLV1,TLV2) (((TLV1).sx-(TLV0).sx)*((TLV2).sy-(TLV0).sy) - \
  20. ((TLV2).sx-(TLV0).sx)*((TLV1).sy-(TLV0).sy))
  21. #define ISCULLED(lpDevI, CullTestRes) ((CullTestRes==0.0) || \
  22. ((lpDevI->rstates[D3DRENDERSTATE_CULLMODE]==D3DCULL_CW) ^ (CullTestRes < 0.0)))
  23. //---------------------------------------------------------------------
  24. void WaitForFlip( LPDIRECT3DDEVICEI lpDevI )
  25. {
  26. if (! (lpDevI->lpD3DHALGlobalDriverData->hwCaps.dwDevCaps & D3DDEVCAPS_CANRENDERAFTERFLIP) )
  27. {
  28. LPDDRAWI_DDRAWSURFACE_LCL lpLcl = ((LPDDRAWI_DDRAWSURFACE_INT) lpDevI->lpDDSTarget)->lpLcl;
  29. if (lpLcl->ddsCaps.dwCaps & DDSCAPS_FLIP) {
  30. HRESULT ret;
  31. D3D_INFO(5, "Waiting for flip");
  32. do {
  33. ret = lpDevI->lpDDSTarget->GetFlipStatus(DDGFS_ISFLIPDONE);
  34. } while (ret == DDERR_WASSTILLDRAWING);
  35. }
  36. }
  37. }
  38. //---------------------------------------------------------------------
  39. #undef DPF_MODNAME
  40. #define DPF_MODNAME "FlushStatesHW"
  41. HRESULT CDirect3DDeviceIHW::FlushStates()
  42. {
  43. DWORD i;
  44. LPDWORD lpScan = (LPDWORD) this->lpHWVertices;
  45. LPD3DTRIANGLE lpTriScan = (LPD3DTRIANGLE) this->lpHWTris;
  46. DWORD dwRet;
  47. D3DHAL_RENDERSTATEDATA StateData;
  48. D3DHAL_RENDERPRIMITIVEDATA PrimitiveData;
  49. CDDSurfaceFromMem TLBuffer(NULL);
  50. CDDSurfaceFromMem ExeBuffer(lpTriScan);
  51. FlushTextureFromDevice( this ); // delink all texture surfaces
  52. if (this->dwHWOffset == 0) return D3D_OK;
  53. this->dwHWOffset = 0; //zeroed to prevent re-enter by drivers's locking surfaces
  54. // Legacy HAL, therefore we have to wait
  55. // until the render target has flipped.
  56. WaitForFlip(this);
  57. // Pick up Win16 lock
  58. LOCK_HAL( dwRet, this );
  59. LOCK_DIBENGINE(dwRet, this);
  60. #if _D3D_FORCEDOUBLE
  61. CD3DForceFPUDouble ForceFPUDouble(this);
  62. #endif //_D3D_FORCEDOUBLE
  63. memset(&StateData, 0, sizeof(StateData) );
  64. memset(&PrimitiveData, 0, sizeof(PrimitiveData) );
  65. // dwHWNumCounts is the number of recorded structs with
  66. // primitives attached.
  67. for (i = 0; i < this->dwHWNumCounts+1; i += 1)
  68. {
  69. if ( this->lpHWCounts[i].wNumStateChanges )
  70. {
  71. TLBuffer.SetBits(lpScan);
  72. StateData.dwhContext = this->dwhContext;
  73. StateData.dwOffset = 0;
  74. StateData.dwCount = this->lpHWCounts[i].wNumStateChanges;
  75. StateData.lpExeBuf = TLBuffer.GetSurface();
  76. dwRet = (*this->lpD3DHALCallbacks->RenderState)(&StateData);
  77. // No provision for NOT_HANDLED
  78. lpScan += 2*this->lpHWCounts[i].wNumStateChanges;
  79. lpScan = (LPDWORD) ( (((ULONG_PTR) lpScan) + 31) & ~31);
  80. }
  81. if ( this->lpHWCounts[i].wNumVertices )
  82. {
  83. TLBuffer.SetBits(this->lpHWVertices);
  84. ExeBuffer.SetBits(lpTriScan);
  85. PrimitiveData.dwhContext = this->dwhContext;
  86. PrimitiveData.dwOffset = 0;
  87. PrimitiveData.dwStatus = 0;
  88. PrimitiveData.lpExeBuf = ExeBuffer.GetSurface();
  89. PrimitiveData.dwTLOffset = 0;
  90. PrimitiveData.lpTLBuf = TLBuffer.GetSurface();
  91. PrimitiveData.diInstruction.bOpcode = D3DOP_TRIANGLE;
  92. PrimitiveData.diInstruction.bSize = sizeof(D3DTRIANGLE);
  93. PrimitiveData.diInstruction.wCount = (WORD) this->lpHWCounts[i].wNumTriangles;
  94. dwRet = (*this->lpD3DHALCallbacks->RenderPrimitive)(&PrimitiveData);
  95. // No provision for NOT_HANDLED
  96. lpScan = (LPDWORD)(((LPD3DTLVERTEX) lpScan) + this->lpHWCounts[i].wNumVertices);
  97. lpTriScan += this->lpHWCounts[i].wNumTriangles;
  98. }
  99. }
  100. UNLOCK_DIBENGINE( this );
  101. UNLOCK_HAL( this );
  102. this->dwHWTriIndex = 0;
  103. this->dwHWNumCounts = 0;
  104. memset(this->lpHWCounts, 0, sizeof(D3DI_HWCOUNTS) );
  105. return D3D_OK;
  106. }
  107. //---------------------------------------------------------------------
  108. #undef DPF_MODNAME
  109. #define DPF_MODNAME "DrawPrimitiveLegacyHalCall"
  110. HRESULT
  111. DrawPrimitiveLegacyHalCall(CDirect3DDeviceIHW * lpDevI,
  112. LPD3DTLVERTEX lpVertices, LPVOID lpvData,
  113. LPD3DINSTRUCTION ins, DWORD dwNumVertices, D3DVERTEXTYPE VtxType)
  114. {
  115. DWORD dwRet;
  116. CDDSurfaceFromMem TLBuffer(lpVertices);
  117. CDDSurfaceFromMem ExeBuffer(lpvData);
  118. D3DHAL_RENDERPRIMITIVEDATA rdata;
  119. memset(&rdata, 0, sizeof(rdata) );
  120. rdata.dwhContext = lpDevI->dwhContext;
  121. rdata.dwOffset = 0;
  122. rdata.dwStatus = 0;
  123. rdata.lpExeBuf = ExeBuffer.GetSurface();
  124. rdata.dwTLOffset = 0;
  125. rdata.lpTLBuf = TLBuffer.GetSurface();
  126. rdata.diInstruction = *ins;
  127. #ifndef WIN95
  128. if((dwRet = CheckContextSurface(lpDevI)) != D3D_OK)
  129. {
  130. return (dwRet);
  131. }
  132. #endif //WIN95
  133. #if _D3D_FORCEDOUBLE
  134. CD3DForceFPUDouble ForceFPUDouble(lpDevI);
  135. #endif //_D3D_FORCEDOUBLE
  136. CALL_HALONLY(dwRet, lpDevI, RenderPrimitive, &rdata);
  137. if (dwRet != DDHAL_DRIVER_HANDLED)
  138. {
  139. D3D_ERR ( "Driver not handled in DrawPrimitive" );
  140. // Need sensible return value in this case,
  141. // currently we return whatever the driver stuck in here.
  142. }
  143. return D3D_OK;
  144. }
  145. #undef DPF_MODNAME
  146. #define DPF_MODNAME "FillLegacyHalIndices"
  147. void
  148. FillLegacyHalIndices(D3DPRIMITIVETYPE PrimitiveType, LPVOID lpOut,
  149. LPWORD lpwIndices, DWORD dwNumPrimitives)
  150. {
  151. LPD3DLINE lpTmpLines;
  152. LPD3DTRIANGLE lpTmpTris;
  153. DWORD i;
  154. WORD wIndex = 0;
  155. switch (PrimitiveType)
  156. {
  157. case D3DPT_LINELIST:
  158. lpTmpLines = (LPD3DLINE) lpOut;
  159. for (i = 0; i < dwNumPrimitives; i += 1)
  160. {
  161. lpTmpLines[i].v1 = lpwIndices[wIndex++];
  162. lpTmpLines[i].v2 = lpwIndices[wIndex++];
  163. }
  164. break;
  165. case D3DPT_LINESTRIP:
  166. lpTmpLines = (LPD3DLINE) lpOut;
  167. for (i = 0; i < dwNumPrimitives; i += 1)
  168. {
  169. lpTmpLines[i].v1 = lpwIndices[wIndex++];
  170. lpTmpLines[i].v2 = lpwIndices[wIndex];
  171. }
  172. break;
  173. case D3DPT_TRIANGLELIST:
  174. lpTmpTris = (LPD3DTRIANGLE) lpOut;
  175. for (i = 0; i < dwNumPrimitives; i += 1)
  176. {
  177. lpTmpTris[i].v1 = lpwIndices[wIndex++];
  178. lpTmpTris[i].v2 = lpwIndices[wIndex++];
  179. lpTmpTris[i].v3 = lpwIndices[wIndex++];
  180. lpTmpTris[i].wFlags = D3DTRIFLAG_EDGEENABLETRIANGLE;
  181. }
  182. break;
  183. case D3DPT_TRIANGLESTRIP:
  184. lpTmpTris = (LPD3DTRIANGLE) lpOut;
  185. for (i = 0; i < dwNumPrimitives; i += 1)
  186. {
  187. lpTmpTris[i].v1 = lpwIndices[wIndex++];
  188. lpTmpTris[i].v2 = lpwIndices[wIndex++];
  189. lpTmpTris[i].v3 = lpwIndices[wIndex++];
  190. lpTmpTris[i].wFlags = D3DTRIFLAG_EDGEENABLETRIANGLE;
  191. i++;
  192. if (i<dwNumPrimitives)
  193. {
  194. lpTmpTris[i].v1 = lpTmpTris[i-1].v2;
  195. lpTmpTris[i].v2 = lpwIndices[wIndex--];
  196. lpTmpTris[i].v3 = lpTmpTris[i-1].v3;
  197. lpTmpTris[i].wFlags = D3DTRIFLAG_EDGEENABLETRIANGLE;
  198. }
  199. }
  200. break;
  201. case D3DPT_TRIANGLEFAN:
  202. lpTmpTris = (LPD3DTRIANGLE) lpOut;
  203. lpTmpTris[0].v3 = lpwIndices[wIndex++];
  204. lpTmpTris[0].v1 = lpwIndices[wIndex++];
  205. lpTmpTris[0].v2 = lpwIndices[wIndex++];
  206. lpTmpTris[0].wFlags = D3DTRIFLAG_EDGEENABLETRIANGLE;
  207. for (i = 1; i < dwNumPrimitives; i += 1)
  208. {
  209. lpTmpTris[i].v1 = lpTmpTris[i-1].v2;
  210. lpTmpTris[i].v2 = lpwIndices[wIndex++];
  211. lpTmpTris[i].v3 = lpTmpTris[i-1].v3;
  212. lpTmpTris[i].wFlags = D3DTRIFLAG_EDGEENABLETRIANGLE;
  213. }
  214. break;
  215. }
  216. }
  217. #undef DPF_MODNAME
  218. #define DPF_MODNAME "DrawPrimitiveInBatchesHW"
  219. HRESULT
  220. DrawPrimitiveInBatchesHW(CDirect3DDeviceIHW * lpDevI, D3DPRIMITIVETYPE PrimitiveType, D3DVERTEXTYPE VertexType, LPD3DTLVERTEX lpVertices, DWORD dwNumPrimitives)
  221. {
  222. DWORD i;
  223. D3DTLVERTEX tmpV;
  224. LPD3DTLVERTEX lpFirstVertex;
  225. D3DINSTRUCTION ins;
  226. HRESULT ret;
  227. switch (PrimitiveType)
  228. {
  229. case D3DPT_LINELIST:
  230. ins.bOpcode = D3DOP_LINE;
  231. ins.bSize = sizeof(D3DLINE);
  232. for (i = 0; i < dwNumPrimitives; i += dwLineBatchSize)
  233. {
  234. ins.wCount = (WORD)min(dwNumPrimitives-i, dwLineBatchSize);
  235. ret = DrawPrimitiveLegacyHalCall(lpDevI, lpVertices, LineListPrecomp, &ins, 0, VertexType);
  236. if (ret)
  237. return ret;
  238. lpVertices += ins.wCount*2;
  239. }
  240. break;
  241. case D3DPT_LINESTRIP:
  242. ins.bOpcode = D3DOP_LINE;
  243. ins.bSize = sizeof(D3DLINE);
  244. for (i = 0; i < dwNumPrimitives; i += dwLineBatchSize)
  245. {
  246. ins.wCount = (WORD)min(dwNumPrimitives-i, dwLineBatchSize);
  247. ret = DrawPrimitiveLegacyHalCall(lpDevI, lpVertices, LineStripPrecomp, &ins, 0, VertexType);
  248. if (ret)
  249. return ret;
  250. lpVertices += ins.wCount;
  251. }
  252. break;
  253. case D3DPT_TRIANGLELIST:
  254. ins.bOpcode = D3DOP_TRIANGLE;
  255. ins.bSize = sizeof(D3DTRIANGLE);
  256. for (i = 0; i < dwNumPrimitives; i += dwD3DTriBatchSize)
  257. {
  258. ins.wCount = (WORD)min(dwNumPrimitives-i, dwD3DTriBatchSize);
  259. ret = DrawPrimitiveLegacyHalCall(lpDevI, lpVertices, TriangleListPrecomp, &ins, 0, VertexType);
  260. if (ret)
  261. return ret;
  262. lpVertices += 3*ins.wCount;
  263. }
  264. break;
  265. case D3DPT_TRIANGLESTRIP:
  266. ins.bOpcode = D3DOP_TRIANGLE;
  267. ins.bSize = sizeof(D3DTRIANGLE);
  268. for (i = 0; i < dwNumPrimitives; i += dwD3DTriBatchSize)
  269. {
  270. ins.wCount = (WORD)min(dwNumPrimitives-i, dwD3DTriBatchSize);
  271. ret = DrawPrimitiveLegacyHalCall(lpDevI, lpVertices, TriangleStripPrecomp, &ins, 0, VertexType);
  272. if (ret)
  273. return ret;
  274. lpVertices += ins.wCount;
  275. }
  276. break;
  277. case D3DPT_TRIANGLEFAN:
  278. ins.bOpcode = D3DOP_TRIANGLE;
  279. ins.bSize = sizeof(D3DTRIANGLE);
  280. // Save the first vertex to spoof the driver
  281. lpFirstVertex = lpVertices;
  282. tmpV = lpVertices[0];
  283. for (i = 0; i < dwNumPrimitives; i += dwD3DTriBatchSize)
  284. {
  285. ins.wCount = (WORD)min(dwNumPrimitives-i, dwD3DTriBatchSize);
  286. tmpV = *lpVertices;
  287. *lpVertices = *lpFirstVertex;
  288. ret = DrawPrimitiveLegacyHalCall(lpDevI, lpVertices, TriangleFanPrecomp, &ins, 0, VertexType);
  289. if (ret)
  290. return ret;
  291. *lpVertices = tmpV;
  292. lpVertices += ins.wCount;
  293. }
  294. break;
  295. }
  296. return D3D_OK;
  297. }
  298. #undef DPF_MODNAME
  299. #define DPF_MODNAME "DrawIndexedPrimitiveInBatchesHW"
  300. HRESULT
  301. DrawIndexedPrimitiveInBatchesHW(CDirect3DDeviceIHW * lpDevI,
  302. D3DPRIMITIVETYPE PrimitiveType,
  303. D3DVERTEXTYPE VertexType,
  304. LPD3DTLVERTEX lpVertices,
  305. DWORD dwNumPrimitives,
  306. LPWORD lpwIndices)
  307. {
  308. DWORD i;
  309. WORD tmpW;
  310. LPWORD lpFirstIndex;
  311. D3DINSTRUCTION ins;
  312. HRESULT ret;
  313. switch (PrimitiveType)
  314. {
  315. case D3DPT_LINELIST:
  316. ins.bOpcode = D3DOP_LINE;
  317. ins.bSize = sizeof(D3DLINE);
  318. for (i = 0; i < dwNumPrimitives; i += dwLineBatchSize)
  319. {
  320. ins.wCount = (WORD)min(dwNumPrimitives-i, dwLineBatchSize);
  321. FillLegacyHalIndices(PrimitiveType, lpDevI->wTriIndex, lpwIndices, ins.wCount);
  322. ret = DrawPrimitiveLegacyHalCall(lpDevI, lpVertices, lpDevI->wTriIndex, &ins, 0, VertexType);
  323. if (ret)
  324. return ret;
  325. lpwIndices += ins.wCount*2;
  326. }
  327. break;
  328. case D3DPT_LINESTRIP:
  329. ins.bOpcode = D3DOP_LINE;
  330. ins.bSize = sizeof(D3DLINE);
  331. for (i = 0; i < dwNumPrimitives; i += dwLineBatchSize)
  332. {
  333. ins.wCount = (WORD)min(dwNumPrimitives-i, dwLineBatchSize);
  334. FillLegacyHalIndices(PrimitiveType, lpDevI->wTriIndex, lpwIndices, ins.wCount);
  335. ret = DrawPrimitiveLegacyHalCall(lpDevI, lpVertices, lpDevI->wTriIndex, &ins, 0, VertexType);
  336. if (ret)
  337. return ret;
  338. lpVertices += ins.wCount;
  339. }
  340. break;
  341. case D3DPT_TRIANGLELIST:
  342. ins.bOpcode = D3DOP_TRIANGLE;
  343. ins.bSize = sizeof(D3DTRIANGLE);
  344. for (i = 0; i < dwNumPrimitives; i += dwD3DTriBatchSize)
  345. {
  346. ins.wCount = (WORD)min(dwNumPrimitives-i, dwD3DTriBatchSize);
  347. FillLegacyHalIndices(PrimitiveType, lpDevI->wTriIndex, lpwIndices, ins.wCount);
  348. ret = DrawPrimitiveLegacyHalCall(lpDevI, lpVertices, lpDevI->wTriIndex, &ins, 0, VertexType);
  349. if (ret)
  350. return ret;
  351. lpwIndices += 3*ins.wCount;
  352. }
  353. break;
  354. case D3DPT_TRIANGLESTRIP:
  355. ins.bOpcode = D3DOP_TRIANGLE;
  356. ins.bSize = sizeof(D3DTRIANGLE);
  357. for (i = 0; i < dwNumPrimitives; i += dwD3DTriBatchSize)
  358. {
  359. ins.wCount = (WORD)min(dwNumPrimitives-i, dwD3DTriBatchSize);
  360. FillLegacyHalIndices(PrimitiveType, lpDevI->wTriIndex, lpwIndices, ins.wCount);
  361. ret = DrawPrimitiveLegacyHalCall(lpDevI, lpVertices, lpDevI->wTriIndex, &ins, 0, VertexType);
  362. if (ret)
  363. return ret;
  364. lpwIndices += ins.wCount;
  365. }
  366. break;
  367. case D3DPT_TRIANGLEFAN:
  368. ins.bOpcode = D3DOP_TRIANGLE;
  369. ins.bSize = sizeof(D3DTRIANGLE);
  370. // Save the first index to spoof the driver
  371. lpFirstIndex = lpwIndices;
  372. tmpW = lpwIndices[0];
  373. for (i = 0; i < dwNumPrimitives; i += dwD3DTriBatchSize)
  374. {
  375. ins.wCount = (WORD)min(dwNumPrimitives-i, dwD3DTriBatchSize);
  376. tmpW = *lpwIndices;
  377. *lpwIndices = *lpFirstIndex;
  378. FillLegacyHalIndices(PrimitiveType, lpDevI->wTriIndex, lpwIndices, ins.wCount);
  379. ret = DrawPrimitiveLegacyHalCall(lpDevI, lpVertices, lpDevI->wTriIndex, &ins, 0, VertexType);
  380. if (ret)
  381. return ret;
  382. *lpwIndices = tmpW;
  383. lpwIndices += ins.wCount;
  384. }
  385. break;
  386. }
  387. return D3D_OK;
  388. }
  389. //---------------------------------------------------------------------
  390. // This is a call for a clipped primitive
  391. //
  392. HRESULT CDirect3DDeviceIHW::DrawIndexPrim()
  393. {
  394. LPD3DTLVERTEX lpVertices = (LPD3DTLVERTEX)this->lpvOut;
  395. DWORD dwNumVertices = this->dwNumVertices;
  396. DWORD dwNumPrimitives = this->dwNumPrimitives;
  397. WORD *lpwIndices = this->lpwIndices;
  398. HRESULT ret;
  399. // Do we need to map new texture stage operations to DX5 renderstates?
  400. if(this->dwFEFlags & D3DFE_MAP_TSS_TO_RS) {
  401. MapTSSToRS();
  402. this->dwFEFlags &= ~D3DFE_MAP_TSS_TO_RS; // Reset request bit
  403. }
  404. if(this->dwFEFlags & D3DFE_NEED_TEXTURE_UPDATE)
  405. {
  406. UpdateTextures();
  407. this->dwFEFlags &= ~D3DFE_NEED_TEXTURE_UPDATE;
  408. }
  409. // If the number of vertices is small, then just batch them.
  410. if ( (this->primType == D3DPT_TRIANGLELIST ||
  411. this->primType == D3DPT_TRIANGLEFAN ||
  412. this->primType == D3DPT_TRIANGLESTRIP) &&
  413. this->dwNumVertices < dwHWFewVertices)
  414. {
  415. LPD3DTRIANGLE lpTriOut;
  416. DWORD i,dwTriOutCount,iV0,iV1,iV2;
  417. WORD wVertexOffset;
  418. float fCullTestResult;
  419. BOOL bDoBFCulling;
  420. // Pad the offset, if needed. But first save the offset to restore for
  421. // case in which no vertices are added to the buffer. This is necessary
  422. // when renderstates are buffered before and after a non-visible primitive.
  423. DWORD dwHWOffsetSave = this->dwHWOffset;
  424. this->dwHWOffset = (this->dwHWOffset + 31) & ~31;
  425. if (this->dwHWOffset + dwNumVertices*sizeof(D3DTLVERTEX) >= dwHWBufferSize ||
  426. this->dwHWTriIndex + dwNumPrimitives >= dwHWMaxTris )
  427. {
  428. CLockD3DST lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock (ST only).
  429. // Release in the destructor
  430. ret = FlushStates();
  431. if (ret != D3D_OK)
  432. {
  433. D3D_ERR("Error trying to render batched commands in DrawIndexPrim");
  434. return ret;
  435. }
  436. dwHWOffsetSave = this->dwHWOffset;
  437. }
  438. LPVOID lpvBatchAddress = (char*)this->lpHWVertices + this->dwHWOffset;
  439. if (this->dwVIDOut == D3DFVF_TLVERTEX)
  440. memcpy(lpvBatchAddress, lpVertices,
  441. this->dwNumVertices*sizeof(D3DTLVERTEX));
  442. else
  443. {
  444. // We have to map FVF vertices to the D3DTLVERTEX.
  445. // This is only the case when lpvOut points to the user input
  446. // buffer.
  447. HRESULT ret;
  448. // Output will be in the batch buffer
  449. if ((ret = MapFVFtoTLVertex(this, lpvBatchAddress)) != D3D_OK)
  450. return ret;
  451. lpVertices = (D3DTLVERTEX*)lpvBatchAddress;
  452. }
  453. lpTriOut = this->lpHWTris + this->dwHWTriIndex;
  454. wVertexOffset = (WORD) (this->dwHWOffset/sizeof(D3DTLVERTEX));
  455. dwTriOutCount=0; bDoBFCulling=(this->rstates[D3DRENDERSTATE_CULLMODE]!=D3DCULL_NONE);
  456. switch (this->primType)
  457. {
  458. case D3DPT_TRIANGLELIST:
  459. iV0=0; iV1=1; iV2=2;
  460. for (i = 0; i < dwNumPrimitives; i++,iV0+=3,iV1+=3,iV2+=3)
  461. {
  462. if(bDoBFCulling)
  463. {
  464. fCullTestResult = BFCULLTEST_TVertTri(lpVertices[lpwIndices[iV0]],lpVertices[lpwIndices[iV1]],lpVertices[lpwIndices[iV2]]);
  465. if(ISCULLED(this, fCullTestResult))
  466. continue;
  467. }
  468. lpTriOut->v1 = lpwIndices[iV0] + wVertexOffset;
  469. lpTriOut->v2 = lpwIndices[iV1] + wVertexOffset;
  470. lpTriOut->v3 = lpwIndices[iV2] + wVertexOffset;
  471. lpTriOut->wFlags = D3DTRIFLAG_EDGEENABLETRIANGLE;
  472. lpTriOut += 1;
  473. dwTriOutCount++;
  474. }
  475. break;
  476. case D3DPT_TRIANGLEFAN:
  477. iV0=1; iV1=2; iV2=0;
  478. for (i = 0; i < dwNumPrimitives; i++,iV0++,iV1++)
  479. {
  480. if(bDoBFCulling)
  481. {
  482. fCullTestResult = BFCULLTEST_TVertTri(lpVertices[lpwIndices[iV0]],lpVertices[lpwIndices[iV1]],lpVertices[lpwIndices[iV2]]);
  483. if(ISCULLED(this, fCullTestResult))
  484. continue;
  485. }
  486. lpTriOut->v1 = lpwIndices[iV0] + wVertexOffset;
  487. lpTriOut->v2 = lpwIndices[iV1] + wVertexOffset;
  488. lpTriOut->v3 = lpwIndices[iV2] + wVertexOffset;
  489. lpTriOut->wFlags = D3DTRIFLAG_EDGEENABLETRIANGLE;
  490. lpTriOut += 1;
  491. dwTriOutCount++;
  492. }
  493. break;
  494. case D3DPT_TRIANGLESTRIP:
  495. iV0=0; iV1=1; iV2=2;
  496. for (i = 0; i < dwNumPrimitives; i++,iV0++,iV1++,iV2++)
  497. {
  498. if(bDoBFCulling)
  499. {
  500. fCullTestResult = BFCULLTEST_TVertTri(lpVertices[lpwIndices[iV0]],lpVertices[lpwIndices[iV1]],lpVertices[lpwIndices[iV2]]);
  501. if(ISCULLED(this, fCullTestResult))
  502. goto SecondTri;
  503. }
  504. lpTriOut->v1 = lpwIndices[iV0] + wVertexOffset;
  505. lpTriOut->v2 = lpwIndices[iV1] + wVertexOffset;
  506. lpTriOut->v3 = lpwIndices[iV2] + wVertexOffset;
  507. lpTriOut->wFlags = D3DTRIFLAG_EDGEENABLETRIANGLE;
  508. lpTriOut += 1;
  509. dwTriOutCount++;
  510. SecondTri:
  511. i++;
  512. if(i < dwNumPrimitives)
  513. {
  514. iV0++,iV1++,iV2++;
  515. // swap vtx order for every 2nd tri
  516. if(bDoBFCulling)
  517. {
  518. fCullTestResult = BFCULLTEST_TVertTri(lpVertices[lpwIndices[iV0]],lpVertices[lpwIndices[iV2]],lpVertices[lpwIndices[iV1]]);
  519. if(ISCULLED(this, fCullTestResult))
  520. continue;
  521. }
  522. lpTriOut->v1 = lpwIndices[iV0] + wVertexOffset;
  523. lpTriOut->v2 = lpwIndices[iV2] + wVertexOffset;
  524. lpTriOut->v3 = lpwIndices[iV1] + wVertexOffset;
  525. lpTriOut->wFlags = D3DTRIFLAG_EDGEENABLETRIANGLE;
  526. lpTriOut += 1;
  527. dwTriOutCount++;
  528. }
  529. }
  530. break;
  531. }
  532. if(dwTriOutCount==0)
  533. {
  534. this->dwHWOffset = dwHWOffsetSave; // restore unpadded offset
  535. return D3D_OK; // avoid adding unused verts to output
  536. }
  537. this->lpHWCounts[this->dwHWNumCounts].wNumTriangles += (WORD) dwTriOutCount;
  538. this->lpHWCounts[this->dwHWNumCounts].wNumVertices += (WORD) dwNumVertices;
  539. this->dwHWOffset += dwNumVertices * sizeof(D3DTLVERTEX);
  540. this->dwHWTriIndex += dwTriOutCount;
  541. return D3D_OK;
  542. }
  543. else
  544. {
  545. CLockD3DST lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock (ST only).
  546. // Release in the destructor
  547. ret = FlushStates();
  548. if (ret != D3D_OK)
  549. {
  550. D3D_ERR("Error trying to render batched commands in DrawIndexPrim");
  551. return ret;
  552. }
  553. // We have to map FVF vertices to the D3DTLVERTEX.
  554. // This is only the case when lpvOut points to the user input buffer.
  555. if (this->dwVIDOut != D3DFVF_TLVERTEX)
  556. {
  557. HRESULT ret;
  558. // Output will be in the TL buffer
  559. if ((ret = MapFVFtoTLVertex(this, NULL)) != D3D_OK)
  560. return ret;
  561. lpVertices = (D3DTLVERTEX*)this->TLVbuf.GetAddress();
  562. }
  563. ret = DrawIndexedPrimitiveInBatchesHW(this, this->primType,
  564. D3DVT_TLVERTEX, lpVertices,
  565. dwNumPrimitives, this->lpwIndices);
  566. return ret;
  567. }
  568. }
  569. //---------------------------------------------------------------------
  570. // This is a call for a clipped primitive
  571. //
  572. HRESULT CDirect3DDeviceIHW::DrawPrim()
  573. {
  574. D3DPOINT TmpPoint;
  575. D3DINSTRUCTION ins = {D3DOP_POINT, sizeof(D3DPOINT), 1};
  576. LPD3DTLVERTEX lpVertices = (LPD3DTLVERTEX)this->lpvOut;
  577. // Do we need to map new texture stage operations to DX5 renderstates?
  578. if(this->dwFEFlags & D3DFE_MAP_TSS_TO_RS) {
  579. MapTSSToRS();
  580. this->dwFEFlags &= ~D3DFE_MAP_TSS_TO_RS; // Reset request bit
  581. }
  582. if(this->dwFEFlags & D3DFE_NEED_TEXTURE_UPDATE)
  583. {
  584. UpdateTextures();
  585. this->dwFEFlags &= ~D3DFE_NEED_TEXTURE_UPDATE;
  586. }
  587. // If the number of vertices is small, and none require
  588. // clipping, then just batch them.
  589. if ((this->primType == D3DPT_TRIANGLELIST ||
  590. this->primType == D3DPT_TRIANGLEFAN ||
  591. this->primType == D3DPT_TRIANGLESTRIP) &&
  592. this->dwNumVertices < dwHWFewVertices)
  593. {
  594. LPD3DTRIANGLE lpTriOut, lpTriPrim;
  595. DWORD i, dwTriOutCount;
  596. WORD wVertexOffset;
  597. float fCullTestResult;
  598. BOOL bDoBFCulling;
  599. // Pad the offset, if needed. But first save the offset to restore for
  600. // case in which no vertices are added to the buffer. This is necessary
  601. // when renderstates are buffered before and after a non-visible primitive.
  602. DWORD dwHWOffsetSave = this->dwHWOffset;
  603. this->dwHWOffset = (this->dwHWOffset + 31) & ~31;
  604. if (this->dwHWOffset +
  605. this->dwNumVertices * sizeof(D3DTLVERTEX) >= dwHWBufferSize ||
  606. this->dwHWTriIndex + this->dwNumPrimitives >= dwHWMaxTris )
  607. {
  608. // Takes D3D lock (ST only).
  609. CLockD3DST lockObject(this, DPF_MODNAME, REMIND(""));
  610. HRESULT ret = FlushStates();
  611. if (ret != D3D_OK)
  612. {
  613. D3D_ERR("Error trying to render batched commands in DrawPrim");
  614. return ret;
  615. }
  616. dwHWOffsetSave = this->dwHWOffset;
  617. }
  618. LPVOID lpvBatchAddress = (char*)this->lpHWVertices + this->dwHWOffset;
  619. if (this->dwVIDOut == D3DFVF_TLVERTEX)
  620. memcpy(lpvBatchAddress, lpVertices,
  621. this->dwNumVertices*sizeof(D3DTLVERTEX));
  622. else
  623. {
  624. // We have to map FVF vertices to the D3DTLVERTEX.
  625. // This is only the case when lpvOut points to the user input
  626. // buffer.
  627. HRESULT ret;
  628. // Output will be in the batch buffer
  629. if ((ret = MapFVFtoTLVertex(this, lpvBatchAddress)) != D3D_OK)
  630. return ret;
  631. lpVertices = (LPD3DTLVERTEX)lpvBatchAddress;
  632. }
  633. switch (this->primType)
  634. {
  635. case D3DPT_TRIANGLELIST:
  636. lpTriPrim = TriangleListPrecomp;
  637. break;
  638. case D3DPT_TRIANGLEFAN:
  639. lpTriPrim = TriangleFanPrecomp;
  640. break;
  641. case D3DPT_TRIANGLESTRIP:
  642. lpTriPrim = TriangleStripPrecomp;
  643. break;
  644. }
  645. wVertexOffset = (WORD) (this->dwHWOffset/sizeof(D3DTLVERTEX));
  646. lpTriOut = this->lpHWTris + this->dwHWTriIndex;
  647. bDoBFCulling = (this->rstates[D3DRENDERSTATE_CULLMODE]!=D3DCULL_NONE);
  648. for (dwTriOutCount=0, i = 0; i < this->dwNumPrimitives; i++, lpTriPrim += 1)
  649. {
  650. if(bDoBFCulling)
  651. {
  652. fCullTestResult = BFCULLTEST_TVertTri(lpVertices[lpTriPrim->v1],lpVertices[lpTriPrim->v2],lpVertices[lpTriPrim->v3]);
  653. if(ISCULLED(this, fCullTestResult))
  654. continue;
  655. }
  656. lpTriOut->v1 = lpTriPrim->v1 + wVertexOffset;
  657. lpTriOut->v2 = lpTriPrim->v2 + wVertexOffset;
  658. lpTriOut->v3 = lpTriPrim->v3 + wVertexOffset;
  659. lpTriOut->wFlags = D3DTRIFLAG_EDGEENABLETRIANGLE;
  660. lpTriOut += 1;
  661. dwTriOutCount++;
  662. }
  663. if(dwTriOutCount==0)
  664. {
  665. this->dwHWOffset = dwHWOffsetSave; // restore unpadded offset
  666. return D3D_OK; // avoid adding unused verts to output
  667. }
  668. this->lpHWCounts[this->dwHWNumCounts].wNumTriangles += (WORD) dwTriOutCount;
  669. this->lpHWCounts[this->dwHWNumCounts].wNumVertices += (WORD)this->dwNumVertices;
  670. this->dwHWOffset += this->dwNumVertices * sizeof(D3DTLVERTEX);
  671. this->dwHWTriIndex += dwTriOutCount;
  672. return D3D_OK;
  673. }
  674. else
  675. {
  676. CLockD3DST lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock (ST only).
  677. // Release in the destructor
  678. HRESULT ret = FlushStates();
  679. if (ret != D3D_OK)
  680. {
  681. D3D_ERR("Error trying to render batched commands in DrawPrim");
  682. return ret;
  683. }
  684. // We have to map FVF vertices to the D3DTLVERTEX.
  685. // This is only the case when lpvOut points to the user input buffer.
  686. if (this->dwVIDOut != D3DFVF_TLVERTEX)
  687. {
  688. HRESULT ret;
  689. // Output will be in the TL buffer
  690. if ((ret = MapFVFtoTLVertex(this, NULL)) != D3D_OK)
  691. return ret;
  692. lpVertices = (D3DTLVERTEX*)this->TLVbuf.GetAddress();
  693. }
  694. if (this->primType == D3DPT_POINTLIST)
  695. {
  696. TmpPoint.wFirst = 0;
  697. TmpPoint.wCount = (WORD)this->dwNumPrimitives;
  698. return DrawPrimitiveLegacyHalCall(this, lpVertices, &TmpPoint,
  699. &ins, 0, D3DVT_TLVERTEX);
  700. }
  701. else
  702. return DrawPrimitiveInBatchesHW(this, this->primType,
  703. D3DVT_TLVERTEX, lpVertices,
  704. this->dwNumPrimitives);
  705. }
  706. }
  707. #undef DPF_MODNAME
  708. #define DPF_MODNAME "CDirect3DDeviceIHW::SetTextureStageState"
  709. HRESULT D3DAPI
  710. CDirect3DDeviceIHW::SetTextureStageState(DWORD dwStage,
  711. D3DTEXTURESTAGESTATETYPE dwState,
  712. DWORD dwValue)
  713. {
  714. // Holds D3D lock until exit.
  715. CLockD3DMT ldmLock(this, DPF_MODNAME, REMIND(""));
  716. #if DBG
  717. if (dwStage >= D3DHAL_TSS_MAXSTAGES ||
  718. dwState == 0 || dwState >= D3DTSS_MAX)
  719. {
  720. D3D_ERR( "Invalid texture stage or state index" );
  721. return DDERR_INVALIDPARAMS;
  722. }
  723. #endif //DBG
  724. // Update runtime copy of state.
  725. DWORD dwOldValue = tsstates[dwStage][dwState];
  726. tsstates[dwStage][dwState] = dwValue;
  727. if (dwStage > 0 ) return D3D_OK; // Ignore higher stage states
  728. if (dwState == D3DTSS_TEXCOORDINDEX && TextureStageEnabled(this, dwStage) ||
  729. dwState == D3DTSS_COLOROP &&
  730. ((dwValue == D3DTOP_DISABLE) == !(dwOldValue == D3DTOP_DISABLE)))
  731. {
  732. this->dwFVFLastIn = 0; // Force to recompute outputVID
  733. this->dwFEFlags |= D3DFE_TSSINDEX_DIRTY;
  734. }
  735. switch(dwState) {
  736. case D3DTSS_ADDRESS:
  737. if(this->rstates[D3DRENDERSTATE_TEXTUREADDRESS] != dwValue) {
  738. SetDeviceRenderState(this, D3DRENDERSTATE_TEXTUREADDRESS, dwValue);
  739. return SetRenderStateI(D3DRENDERSTATE_TEXTUREADDRESS, dwValue);
  740. }
  741. else {
  742. D3D_WARN(4,"Ignoring redundant SetTextureStageState");
  743. return D3D_OK;
  744. }
  745. break;
  746. case D3DTSS_ADDRESSU:
  747. if(this->rstates[D3DRENDERSTATE_TEXTUREADDRESSU] != dwValue) {
  748. SetDeviceRenderState(this, D3DRENDERSTATE_TEXTUREADDRESSU, dwValue);
  749. return SetRenderStateI(D3DRENDERSTATE_TEXTUREADDRESSU, dwValue);
  750. }
  751. else {
  752. D3D_WARN(4,"Ignoring redundant SetTextureStageState");
  753. return D3D_OK;
  754. }
  755. break;
  756. case D3DTSS_ADDRESSV:
  757. if(this->rstates[D3DRENDERSTATE_TEXTUREADDRESSV] != dwValue) {
  758. SetDeviceRenderState(this, D3DRENDERSTATE_TEXTUREADDRESSV, dwValue);
  759. return SetRenderStateI(D3DRENDERSTATE_TEXTUREADDRESSV, dwValue);
  760. }
  761. else {
  762. D3D_WARN(4,"Ignoring redundant SetTextureStageState");
  763. return D3D_OK;
  764. }
  765. break;
  766. case D3DTSS_BORDERCOLOR:
  767. if(this->rstates[D3DRENDERSTATE_BORDERCOLOR] != dwValue) {
  768. SetDeviceRenderState(this, D3DRENDERSTATE_BORDERCOLOR, dwValue);
  769. return SetRenderStateI(D3DRENDERSTATE_BORDERCOLOR, dwValue);
  770. }
  771. else {
  772. D3D_WARN(4,"Ignoring redundant SetTextureStageState");
  773. return D3D_OK;
  774. }
  775. break;
  776. case D3DTSS_MIPMAPLODBIAS:
  777. if(this->rstates[D3DRENDERSTATE_MIPMAPLODBIAS] != dwValue) {
  778. SetDeviceRenderState(this, D3DRENDERSTATE_MIPMAPLODBIAS, dwValue);
  779. return SetRenderStateI(D3DRENDERSTATE_MIPMAPLODBIAS, dwValue);
  780. }
  781. else {
  782. D3D_WARN(4,"Ignoring redundant SetTextureStageState");
  783. return D3D_OK;
  784. }
  785. break;
  786. case D3DTSS_MAXANISOTROPY:
  787. if(this->rstates[D3DRENDERSTATE_ANISOTROPY] != dwValue) {
  788. SetDeviceRenderState(this, D3DRENDERSTATE_ANISOTROPY, dwValue);
  789. return SetRenderStateI(D3DRENDERSTATE_ANISOTROPY, dwValue);
  790. }
  791. else {
  792. D3D_WARN(4,"Ignoring redundant SetTextureStageState");
  793. return D3D_OK;
  794. }
  795. break;
  796. }
  797. // Set a bit requesting mapping to DX5 renderstates
  798. this->dwFEFlags |= D3DFE_MAP_TSS_TO_RS;
  799. return D3D_OK; // return Ok for the time being?
  800. }
  801. #undef DPF_MODNAME
  802. #define DPF_MODNAME "CDirect3DDeviceIHW::MapTSSToRS"
  803. HRESULT CDirect3DDeviceIHW::MapTSSToRS()
  804. {
  805. DWORD mag = this->tsstates[0][D3DTSS_MAGFILTER];
  806. DWORD min = this->tsstates[0][D3DTSS_MINFILTER];
  807. DWORD mip = this->tsstates[0][D3DTSS_MIPFILTER];
  808. if(mip == D3DTFP_NONE) {
  809. if(min != D3DTFN_POINT && min != D3DTFN_LINEAR) {
  810. min = D3DTFN_LINEAR;
  811. D3D_WARN(2,"Unable to map D3DTSS_MINFILTER mode to driver. Rendering maybe incorrect");
  812. }
  813. if(this->rstates[D3DRENDERSTATE_TEXTUREMIN] != min) {
  814. (void) SetDeviceRenderState(this, D3DRENDERSTATE_TEXTUREMIN, min);
  815. (void) this->SetRenderStateI(D3DRENDERSTATE_TEXTUREMIN, min);
  816. }
  817. else {
  818. D3D_WARN(4,"Ignoring redundant renderstate");
  819. }
  820. }
  821. else if(mip == D3DTFP_POINT) {
  822. if(min == D3DTFN_POINT) {
  823. if(this->rstates[D3DRENDERSTATE_TEXTUREMIN] != D3DFILTER_MIPNEAREST) {
  824. (void) SetDeviceRenderState(this, D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_MIPNEAREST);
  825. (void) this->SetRenderStateI(D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_MIPNEAREST);
  826. }
  827. else {
  828. D3D_WARN(4,"Ignoring redundant renderstate");
  829. }
  830. }
  831. else if(min == D3DTFN_LINEAR) {
  832. if(this->rstates[D3DRENDERSTATE_TEXTUREMIN] != D3DFILTER_MIPLINEAR) {
  833. (void) SetDeviceRenderState(this, D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_MIPLINEAR);
  834. (void) this->SetRenderStateI(D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_MIPLINEAR);
  835. }
  836. else {
  837. D3D_WARN(4,"Ignoring redundant renderstate");
  838. }
  839. }
  840. else {
  841. if(this->rstates[D3DRENDERSTATE_TEXTUREMIN] != D3DFILTER_MIPLINEAR) {
  842. (void) SetDeviceRenderState(this, D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_MIPLINEAR);
  843. (void) this->SetRenderStateI(D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_MIPLINEAR);
  844. }
  845. else {
  846. D3D_WARN(4,"Ignoring redundant renderstate");
  847. }
  848. D3D_WARN(2,"Unable to map D3DTSS_MINFILTER mode to driver. Rendering maybe incorrect");
  849. }
  850. }
  851. else { // mip == D3DTFP_LINEAR
  852. if(min == D3DTFN_POINT) {
  853. if(this->rstates[D3DRENDERSTATE_TEXTUREMIN] != D3DFILTER_LINEARMIPNEAREST) {
  854. (void) SetDeviceRenderState(this, D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_LINEARMIPNEAREST);
  855. (void) this->SetRenderStateI(D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_LINEARMIPNEAREST);
  856. }
  857. else {
  858. D3D_WARN(4,"Ignoring redundant renderstate");
  859. }
  860. }
  861. else if(min == D3DTFN_LINEAR) {
  862. if(this->rstates[D3DRENDERSTATE_TEXTUREMIN] != D3DFILTER_LINEARMIPLINEAR) {
  863. (void) SetDeviceRenderState(this, D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_LINEARMIPLINEAR);
  864. (void) this->SetRenderStateI(D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_LINEARMIPLINEAR);
  865. }
  866. else {
  867. D3D_WARN(4,"Ignoring redundant renderstate");
  868. }
  869. }
  870. else {
  871. if(this->rstates[D3DRENDERSTATE_TEXTUREMIN] != D3DFILTER_LINEARMIPLINEAR) {
  872. (void) SetDeviceRenderState(this, D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_LINEARMIPLINEAR);
  873. (void) this->SetRenderStateI(D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_LINEARMIPLINEAR);
  874. }
  875. else {
  876. D3D_WARN(4,"Ignoring redundant renderstate");
  877. }
  878. D3D_WARN(2,"Unable to map D3DTSS_MINFILTER mode to driver. Rendering maybe incorrect");
  879. }
  880. }
  881. if(mag != D3DTFG_POINT && mag != D3DTFG_LINEAR) {
  882. mag = D3DTFG_LINEAR;
  883. D3D_WARN(2,"Unable to map D3DTSS_MAGFILTER mode to driver. Rendering maybe incorrect");
  884. }
  885. if(this->rstates[D3DRENDERSTATE_TEXTUREMAG] != mag) {
  886. (void) SetDeviceRenderState(this, D3DRENDERSTATE_TEXTUREMAG, mag);
  887. (void) this->SetRenderStateI(D3DRENDERSTATE_TEXTUREMAG, mag);
  888. }
  889. else {
  890. D3D_WARN(4,"Ignoring redundant renderstate");
  891. }
  892. DWORD cop = this->tsstates[0][D3DTSS_COLOROP];
  893. DWORD ca1 = this->tsstates[0][D3DTSS_COLORARG1];
  894. DWORD ca2 = this->tsstates[0][D3DTSS_COLORARG2];
  895. DWORD aop = this->tsstates[0][D3DTSS_ALPHAOP];
  896. DWORD aa1 = this->tsstates[0][D3DTSS_ALPHAARG1];
  897. DWORD aa2 = this->tsstates[0][D3DTSS_ALPHAARG2];
  898. // Current is the same as diffuse in stage 0
  899. if(ca2 == D3DTA_CURRENT)
  900. ca2 = D3DTA_DIFFUSE;
  901. if(aa2 == D3DTA_CURRENT)
  902. aa2 = D3DTA_DIFFUSE;
  903. // Check if we need to disable texturing
  904. if(cop == D3DTOP_DISABLE ||
  905. (cop == D3DTOP_SELECTARG2 && ca2 == D3DTA_DIFFUSE && ((aop == D3DTOP_SELECTARG2 && aa2 == D3DTA_DIFFUSE) || aop == D3DTOP_DISABLE))
  906. ) {
  907. if(this->rstates[D3DRENDERSTATE_TEXTUREHANDLE] != 0) {
  908. (void) SetDeviceRenderState(this, D3DRENDERSTATE_TEXTUREHANDLE, 0);
  909. (void) this->SetRenderStateI(D3DRENDERSTATE_TEXTUREHANDLE, 0);
  910. }
  911. else {
  912. D3D_WARN(4,"Ignoring redundant renderstate");
  913. }
  914. this->dwFEFlags |= D3DFE_DISABLE_TEXTURES;
  915. }
  916. else if ((LPD3DI_TEXTUREBLOCK)TRUE != lpD3DMappedBlock[0])
  917. {
  918. LPD3DI_TEXTUREBLOCK lpBlock = this->lpD3DMappedBlock[0];
  919. if (lpBlock) {
  920. if(this->rstates[D3DRENDERSTATE_TEXTUREHANDLE] != lpBlock->hTex) {
  921. (void) SetDeviceRenderState(this, D3DRENDERSTATE_TEXTUREHANDLE, lpBlock->hTex);
  922. (void) this->SetRenderStateI(D3DRENDERSTATE_TEXTUREHANDLE, lpBlock->hTex);
  923. }
  924. else {
  925. D3D_WARN(4,"Ignoring redundant renderstate");
  926. }
  927. }
  928. this->dwFEFlags &= ~D3DFE_DISABLE_TEXTURES;
  929. }
  930. else
  931. this->dwFEFlags &= ~D3DFE_DISABLE_TEXTURES;
  932. // Check if we need to decal
  933. if((ca1 == D3DTA_TEXTURE && cop == D3DTOP_SELECTARG1) &&
  934. (aa1 == D3DTA_TEXTURE && aop == D3DTOP_SELECTARG1)) {
  935. if(this->rstates[D3DRENDERSTATE_TEXTUREMAPBLEND] != D3DTBLEND_DECAL) {
  936. (void) SetDeviceRenderState(this, D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_DECAL);
  937. (void) this->SetRenderStateI(D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_DECAL);
  938. }
  939. else {
  940. D3D_WARN(4,"Ignoring redundant renderstate");
  941. }
  942. }
  943. // Check if we need to modulate
  944. else if((ca2 == D3DTA_DIFFUSE && ca1 == D3DTA_TEXTURE) && cop == D3DTOP_MODULATE &&
  945. ((aa1 == D3DTA_TEXTURE && aop == D3DTOP_SELECTARG1) || (aa2 == D3DTA_DIFFUSE && aop == D3DTOP_SELECTARG2))) {
  946. if(this->rstates[D3DRENDERSTATE_TEXTUREMAPBLEND] != D3DTBLEND_MODULATE) {
  947. (void) SetDeviceRenderState(this, D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATE);
  948. (void) this->SetRenderStateI(D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATE);
  949. }
  950. else {
  951. D3D_WARN(4,"Ignoring redundant renderstate");
  952. }
  953. }
  954. // Check if we need to decal alpha
  955. else if((ca2 == D3DTA_DIFFUSE && ca1 == D3DTA_TEXTURE) && cop == D3DTOP_BLENDTEXTUREALPHA &&
  956. (aa2 == D3DTA_DIFFUSE && aop == D3DTOP_SELECTARG2)) {
  957. if(this->rstates[D3DRENDERSTATE_TEXTUREMAPBLEND] != D3DTBLEND_DECALALPHA) {
  958. (void) SetDeviceRenderState(this, D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_DECALALPHA);
  959. (void) this->SetRenderStateI(D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_DECALALPHA);
  960. }
  961. else {
  962. D3D_WARN(4,"Ignoring redundant renderstate");
  963. }
  964. }
  965. // Check if we need to modulate alpha
  966. else if((ca2 == D3DTA_DIFFUSE && ca1 == D3DTA_TEXTURE) && cop == D3DTOP_MODULATE &&
  967. (aa2 == D3DTA_DIFFUSE && aa1 == D3DTA_TEXTURE) && aop == D3DTOP_MODULATE) {
  968. if(this->rstates[D3DRENDERSTATE_TEXTUREMAPBLEND] != D3DTBLEND_MODULATEALPHA) {
  969. (void) SetDeviceRenderState(this, D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA);
  970. (void) this->SetRenderStateI(D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA);
  971. }
  972. else {
  973. D3D_WARN(4,"Ignoring redundant renderstate");
  974. }
  975. }
  976. // Check if we need to add
  977. else if((ca2 == D3DTA_DIFFUSE && ca1 == D3DTA_TEXTURE) && cop == D3DTOP_ADD &&
  978. (aa2 == D3DTA_DIFFUSE && aop == D3DTOP_SELECTARG2)) {
  979. if(this->rstates[D3DRENDERSTATE_TEXTUREMAPBLEND] != D3DTBLEND_ADD) {
  980. (void) SetDeviceRenderState(this, D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_ADD);
  981. (void) this->SetRenderStateI(D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_ADD);
  982. }
  983. else {
  984. D3D_WARN(4,"Ignoring redundant renderstate");
  985. }
  986. }
  987. else {
  988. if(!(this->dwFEFlags & D3DFE_DISABLE_TEXTURES))
  989. {
  990. D3D_WARN(2,"Mapping textureblend stage states to renderstates failed. Rendering maybe incorrect.");
  991. }
  992. }
  993. return D3D_OK;
  994. }
  995. #undef DPF_MODNAME
  996. #define DPF_MODNAME "CDirect3DDeviceIHW::ValidateDevice"
  997. HRESULT D3DAPI
  998. CDirect3DDeviceIHW::ValidateDevice(LPDWORD lpdwNumPasses)
  999. {
  1000. // Holds D3D lock until exit.
  1001. CLockD3DMT ldmLock(this, DPF_MODNAME, REMIND(""));
  1002. HRESULT ret;
  1003. D3DHAL_VALIDATETEXTURESTAGESTATEDATA vbod;
  1004. TRY
  1005. {
  1006. if (!VALID_DIRECT3DDEVICE3_PTR(this))
  1007. {
  1008. D3D_ERR( "Invalid Direct3DDevice3 pointer" );
  1009. return DDERR_INVALIDOBJECT;
  1010. }
  1011. if (!VALID_PTR(lpdwNumPasses, sizeof(DWORD)))
  1012. {
  1013. D3D_ERR( "Invalid lpdwNumPasses pointer" );
  1014. return DDERR_INVALIDPARAMS;
  1015. }
  1016. }
  1017. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1018. {
  1019. D3D_ERR( "Exception encountered validating parameters" );
  1020. return DDERR_INVALIDPARAMS;
  1021. }
  1022. {
  1023. DWORD mag = this->tsstates[0][D3DTSS_MAGFILTER];
  1024. DWORD min = this->tsstates[0][D3DTSS_MINFILTER];
  1025. DWORD mip = this->tsstates[0][D3DTSS_MIPFILTER];
  1026. DWORD texcap;
  1027. if (this->dwFEFlags & D3DFE_REALHAL)
  1028. {
  1029. texcap = this->d3dHWDevDesc.dpcTriCaps.dwTextureFilterCaps;
  1030. }
  1031. else
  1032. {
  1033. texcap = this->d3dHELDevDesc.dpcTriCaps.dwTextureFilterCaps;
  1034. }
  1035. ret = D3DERR_UNSUPPORTEDTEXTUREFILTER;
  1036. if(mip == D3DTFP_NONE) {
  1037. if(min == D3DTFG_POINT) {
  1038. if(!(texcap & D3DPTFILTERCAPS_NEAREST))
  1039. goto err;
  1040. }
  1041. else if(min == D3DTFG_LINEAR) {
  1042. if(!(texcap & D3DPTFILTERCAPS_LINEAR))
  1043. goto err;
  1044. }
  1045. else
  1046. {
  1047. goto err;
  1048. }
  1049. }
  1050. else if(mip == D3DTFP_POINT) {
  1051. if(min == D3DTFG_POINT) {
  1052. if(!(texcap & D3DPTFILTERCAPS_MIPNEAREST))
  1053. goto err;
  1054. }
  1055. else if(min == D3DTFG_LINEAR) {
  1056. if(!(texcap & D3DPTFILTERCAPS_MIPLINEAR))
  1057. goto err;
  1058. }
  1059. else
  1060. {
  1061. ret = D3DERR_CONFLICTINGTEXTUREFILTER;
  1062. goto err;
  1063. }
  1064. }
  1065. else if(mip == D3DTFP_LINEAR) {
  1066. if(min == D3DTFG_POINT) {
  1067. if(!(texcap & D3DPTFILTERCAPS_LINEARMIPNEAREST))
  1068. goto err;
  1069. }
  1070. else if(min == D3DTFG_LINEAR) {
  1071. if(!(texcap & D3DPTFILTERCAPS_LINEARMIPLINEAR))
  1072. goto err;
  1073. }
  1074. else
  1075. {
  1076. ret = D3DERR_CONFLICTINGTEXTUREFILTER;
  1077. goto err;
  1078. }
  1079. }
  1080. if(mag == D3DTFG_POINT) {
  1081. if(!(texcap & D3DPTFILTERCAPS_NEAREST))
  1082. goto err;
  1083. }
  1084. else if(mag == D3DTFG_LINEAR) {
  1085. if(!(texcap & D3DPTFILTERCAPS_LINEAR))
  1086. goto err;
  1087. }
  1088. else
  1089. {
  1090. goto err;
  1091. }
  1092. }
  1093. {
  1094. DWORD cop = this->tsstates[0][D3DTSS_COLOROP];
  1095. DWORD ca1 = this->tsstates[0][D3DTSS_COLORARG1];
  1096. DWORD ca2 = this->tsstates[0][D3DTSS_COLORARG2];
  1097. DWORD aop = this->tsstates[0][D3DTSS_ALPHAOP];
  1098. DWORD aa1 = this->tsstates[0][D3DTSS_ALPHAARG1];
  1099. DWORD aa2 = this->tsstates[0][D3DTSS_ALPHAARG2];
  1100. DWORD texcap;
  1101. if (this->dwFEFlags & D3DFE_REALHAL)
  1102. {
  1103. texcap = this->d3dHWDevDesc.dpcTriCaps.dwTextureBlendCaps;
  1104. }
  1105. else
  1106. {
  1107. texcap = this->d3dHELDevDesc.dpcTriCaps.dwTextureBlendCaps;
  1108. }
  1109. // Current is the same as diffuse in stage 0
  1110. if(ca2 == D3DTA_CURRENT)
  1111. ca2 = D3DTA_DIFFUSE;
  1112. if(aa2 == D3DTA_CURRENT)
  1113. aa2 = D3DTA_DIFFUSE;
  1114. switch (cop)
  1115. {
  1116. // Check decal
  1117. case D3DTOP_SELECTARG1:
  1118. if(!(texcap & D3DPTBLENDCAPS_DECAL))
  1119. {
  1120. ret = D3DERR_UNSUPPORTEDCOLOROPERATION;
  1121. goto err;
  1122. }
  1123. if (ca1 != D3DTA_TEXTURE)
  1124. {
  1125. ret = D3DERR_UNSUPPORTEDCOLORARG;
  1126. goto err;
  1127. }
  1128. if (aa1 != D3DTA_TEXTURE)
  1129. {
  1130. ret = D3DERR_UNSUPPORTEDALPHAARG;
  1131. goto err;
  1132. }
  1133. if (aop != D3DTOP_SELECTARG1)
  1134. {
  1135. ret = D3DERR_UNSUPPORTEDALPHAOPERATION;
  1136. goto err;
  1137. }
  1138. break;
  1139. case D3DTOP_MODULATE:
  1140. switch (aop)
  1141. {
  1142. // Check modulate
  1143. case D3DTOP_SELECTARG1:
  1144. if(!(texcap & D3DPTBLENDCAPS_MODULATE))
  1145. {
  1146. ret = D3DERR_UNSUPPORTEDCOLOROPERATION;
  1147. goto err;
  1148. }
  1149. if (ca1 != D3DTA_TEXTURE)
  1150. {
  1151. ret = D3DERR_UNSUPPORTEDCOLORARG;
  1152. goto err;
  1153. }
  1154. if (ca2 != D3DTA_DIFFUSE)
  1155. {
  1156. ret = D3DERR_UNSUPPORTEDCOLORARG;
  1157. goto err;
  1158. }
  1159. if (aa1 != D3DTA_TEXTURE)
  1160. {
  1161. ret = D3DERR_UNSUPPORTEDALPHAARG;
  1162. goto err;
  1163. }
  1164. break;
  1165. // Check modulate (second case)
  1166. case D3DTOP_SELECTARG2:
  1167. if(!(texcap & D3DPTBLENDCAPS_MODULATE))
  1168. {
  1169. ret = D3DERR_UNSUPPORTEDCOLOROPERATION;
  1170. goto err;
  1171. }
  1172. if (ca1 != D3DTA_TEXTURE)
  1173. {
  1174. ret = D3DERR_UNSUPPORTEDCOLORARG;
  1175. goto err;
  1176. }
  1177. if (ca2 != D3DTA_DIFFUSE)
  1178. {
  1179. ret = D3DERR_UNSUPPORTEDCOLORARG;
  1180. goto err;
  1181. }
  1182. if (aa2 != D3DTA_DIFFUSE)
  1183. {
  1184. ret = D3DERR_UNSUPPORTEDALPHAARG;
  1185. goto err;
  1186. }
  1187. break;
  1188. // Check modulate alpha
  1189. case D3DTOP_MODULATE:
  1190. if(!(texcap & D3DPTBLENDCAPS_MODULATEALPHA))
  1191. {
  1192. ret = D3DERR_UNSUPPORTEDCOLOROPERATION;
  1193. goto err;
  1194. }
  1195. if (ca1 != D3DTA_TEXTURE)
  1196. {
  1197. ret = D3DERR_UNSUPPORTEDCOLORARG;
  1198. goto err;
  1199. }
  1200. if (ca2 != D3DTA_DIFFUSE)
  1201. {
  1202. ret = D3DERR_UNSUPPORTEDCOLORARG;
  1203. goto err;
  1204. }
  1205. if (aa1 != D3DTA_TEXTURE)
  1206. {
  1207. ret = D3DERR_UNSUPPORTEDALPHAARG;
  1208. goto err;
  1209. }
  1210. if (aa2 != D3DTA_DIFFUSE)
  1211. {
  1212. ret = D3DERR_UNSUPPORTEDALPHAARG;
  1213. goto err;
  1214. }
  1215. break;
  1216. default:
  1217. ret = D3DERR_UNSUPPORTEDALPHAOPERATION;
  1218. goto err;
  1219. }
  1220. break;
  1221. // Check decal alpha
  1222. case D3DTOP_BLENDTEXTUREALPHA:
  1223. if(!(texcap & D3DPTBLENDCAPS_DECALALPHA))
  1224. {
  1225. ret = D3DERR_UNSUPPORTEDCOLOROPERATION;
  1226. goto err;
  1227. }
  1228. if (ca1 != D3DTA_TEXTURE)
  1229. {
  1230. ret = D3DERR_UNSUPPORTEDCOLORARG;
  1231. goto err;
  1232. }
  1233. if (ca2 != D3DTA_DIFFUSE)
  1234. {
  1235. ret = D3DERR_UNSUPPORTEDCOLORARG;
  1236. goto err;
  1237. }
  1238. if (aa2 != D3DTA_DIFFUSE)
  1239. {
  1240. ret = D3DERR_UNSUPPORTEDALPHAARG;
  1241. goto err;
  1242. }
  1243. if (aop != D3DTOP_SELECTARG2)
  1244. {
  1245. ret = D3DERR_UNSUPPORTEDALPHAOPERATION;
  1246. goto err;
  1247. }
  1248. break;
  1249. case D3DTOP_ADD:
  1250. if(!(texcap & D3DPTBLENDCAPS_ADD))
  1251. {
  1252. ret = D3DERR_UNSUPPORTEDCOLOROPERATION;
  1253. goto err;
  1254. }
  1255. if (ca1 != D3DTA_TEXTURE)
  1256. {
  1257. ret = D3DERR_UNSUPPORTEDCOLORARG;
  1258. goto err;
  1259. }
  1260. if (ca2 != D3DTA_DIFFUSE)
  1261. {
  1262. ret = D3DERR_UNSUPPORTEDCOLORARG;
  1263. goto err;
  1264. }
  1265. if (aa2 != D3DTA_DIFFUSE)
  1266. {
  1267. ret = D3DERR_UNSUPPORTEDALPHAARG;
  1268. goto err;
  1269. }
  1270. if (aop != D3DTOP_SELECTARG2)
  1271. {
  1272. ret = D3DERR_UNSUPPORTEDALPHAOPERATION;
  1273. goto err;
  1274. }
  1275. break;
  1276. // Check disable
  1277. case D3DTOP_SELECTARG2:
  1278. if (ca2 != D3DTA_DIFFUSE)
  1279. {
  1280. ret = D3DERR_UNSUPPORTEDCOLORARG;
  1281. goto err;
  1282. }
  1283. if (aop != D3DTOP_DISABLE)
  1284. {
  1285. if (aop != D3DTOP_SELECTARG2)
  1286. {
  1287. ret = D3DERR_UNSUPPORTEDALPHAOPERATION;
  1288. goto err;
  1289. }
  1290. if (aa2 != D3DTA_DIFFUSE)
  1291. {
  1292. ret = D3DERR_UNSUPPORTEDALPHAARG;
  1293. goto err;
  1294. }
  1295. }
  1296. break;
  1297. // Check disable
  1298. case D3DTOP_DISABLE:
  1299. break;
  1300. default:
  1301. ret = D3DERR_UNSUPPORTEDCOLOROPERATION;
  1302. goto err;
  1303. }
  1304. }
  1305. *lpdwNumPasses = 1;
  1306. return D3D_OK;
  1307. err:
  1308. D3D_INFO(1,"Failed to validate texture stage state.");
  1309. *lpdwNumPasses = 0;
  1310. return ret;
  1311. }