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.

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