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.

671 lines
21 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // setup.cpp
  4. //
  5. // PrimProcessor setup methods.
  6. //
  7. // Copyright (C) Microsoft Corporation, 1997.
  8. //
  9. //----------------------------------------------------------------------------
  10. #include "rgb_pch.h"
  11. #pragma hdrstop
  12. #include "d3dutil.h"
  13. #include "setup.hpp"
  14. #include "attrs_mh.h"
  15. #include "tstp_mh.h"
  16. #include "walk_mh.h"
  17. #include "rsdbg.hpp"
  18. DBG_DECLARE_FILE();
  19. //----------------------------------------------------------------------------
  20. //
  21. // MINMAX3
  22. //
  23. // Computes the min and max of three integer values.
  24. //
  25. //----------------------------------------------------------------------------
  26. #define MINMAX3(iV0, iV1, iV2, iMin, iMax) \
  27. if ((iV0) <= (iV1)) \
  28. { \
  29. if ((iV1) <= (iV2)) \
  30. { \
  31. (iMin) = (iV0); \
  32. (iMax) = (iV2); \
  33. } \
  34. else if ((iV0) <= (iV2)) \
  35. { \
  36. (iMin) = (iV0); \
  37. (iMax) = (iV1); \
  38. } \
  39. else \
  40. { \
  41. (iMin) = (iV2); \
  42. (iMax) = (iV1); \
  43. } \
  44. } \
  45. else if ((iV1) <= (iV2)) \
  46. { \
  47. (iMin) = (iV1); \
  48. if ((iV0) <= (iV2)) \
  49. { \
  50. (iMax) = (iV2); \
  51. } \
  52. else \
  53. { \
  54. (iMax) = (iV0); \
  55. } \
  56. } \
  57. else \
  58. { \
  59. (iMin) = (iV2); \
  60. (iMax) = (iV0); \
  61. }
  62. // Determine whether any of the given values are less than zero or greater
  63. // than one. Negative zero counts as less than zero so this check will
  64. // produce some false positives but that's OK.
  65. //
  66. // ATTENTION Just wipe this out for now. Need a test for W too close to
  67. // zero to avoid numerical problems.
  68. //#define NEEDS_NORMALIZE3(fV0, fV1, fV2) \
  69. // ((ASUINT32(fV0) | ASUINT32(fV1) | ASUINT32(fV2)) > INT32_FLOAT_ONE)
  70. #define NEEDS_NORMALIZE3(fV0, fV1, fV2) \
  71. (1)
  72. //----------------------------------------------------------------------------
  73. //
  74. // PrimProcessor::NormalizeTriRHW
  75. //
  76. // D3DTLVERTEX.dvRHW can be anything, but our internal structures only
  77. // allow for it being in the range [0, 1]. This function ensures that
  78. // the RHWs are in the proper range by finding the largest one and
  79. // scaling all of them down by it.
  80. //
  81. //----------------------------------------------------------------------------
  82. void
  83. PrimProcessor::NormalizeTriRHW(LPD3DTLVERTEX pV0, LPD3DTLVERTEX pV1,
  84. LPD3DTLVERTEX pV2)
  85. {
  86. // Save original values.
  87. m_dvV0RHW = pV0->dvRHW;
  88. m_dvV1RHW = pV1->dvRHW;
  89. m_dvV2RHW = pV2->dvRHW;
  90. // Produce a warning when a value is out of the desired range.
  91. #if DBG
  92. if (FLOAT_LTZ(pV0->dvRHW) ||
  93. FLOAT_LTZ(pV1->dvRHW) ||
  94. FLOAT_LTZ(pV2->dvRHW))
  95. {
  96. RSDPF(("Triangle RHW out of range %f,%f,%f\n",
  97. pV0->dvRHW, pV1->dvRHW, pV2->dvRHW));
  98. }
  99. #endif
  100. // Find bounds and compute scale.
  101. FLOAT fMax;
  102. if (pV0->dvRHW < pV1->dvRHW)
  103. {
  104. if (pV1->dvRHW < pV2->dvRHW)
  105. {
  106. fMax = pV2->dvRHW;
  107. }
  108. else if (pV0->dvRHW < pV2->dvRHW)
  109. {
  110. fMax = pV1->dvRHW;
  111. }
  112. else
  113. {
  114. fMax = pV1->dvRHW;
  115. }
  116. }
  117. else if (pV1->dvRHW < pV2->dvRHW)
  118. {
  119. if (pV0->dvRHW < pV2->dvRHW)
  120. {
  121. fMax = pV2->dvRHW;
  122. }
  123. else
  124. {
  125. fMax = pV0->dvRHW;
  126. }
  127. }
  128. else
  129. {
  130. fMax = pV0->dvRHW;
  131. }
  132. FLOAT fRHWScale;
  133. fRHWScale = NORMALIZED_RHW_MAX / fMax;
  134. // Scale all values by scaling factor.
  135. pV0->dvRHW = pV0->dvRHW * fRHWScale;
  136. pV1->dvRHW = pV1->dvRHW * fRHWScale;
  137. pV2->dvRHW = pV2->dvRHW * fRHWScale;
  138. #ifdef DBG_RHW_NORM
  139. RSDPF(("%f,%f,%f - %f,%f,%f\n",
  140. m_dvV0RHW, m_dvV1RHW, m_dvV2RHW,
  141. pV0->dvRHW, pV1->dvRHW, pV2->dvRHW));
  142. #endif
  143. }
  144. //----------------------------------------------------------------------------
  145. //
  146. // PrimProcessor::TriSetup
  147. //
  148. // Takes three vertices and does triangle setup, filling in both a
  149. // primitive structure for the triangle and a span structure for the first
  150. // span. All internal intermediates and DY values are computed.
  151. //
  152. // Uses the current D3DI_RASTPRIM and D3DI_RASTSPAN so these pointers must
  153. // be valid before calling this routine.
  154. //
  155. // Returns whether the triangle was kept or not. Culled triangles return
  156. // FALSE.
  157. //
  158. //----------------------------------------------------------------------------
  159. BOOL
  160. PrimProcessor::TriSetup(LPD3DTLVERTEX pV0,
  161. LPD3DTLVERTEX pV1,
  162. LPD3DTLVERTEX pV2)
  163. {
  164. // Preserve original first vertex for flat shading reference.
  165. m_StpCtx.pFlatVtx = pV0;
  166. //
  167. // Sort vertices in Y.
  168. // This can cause ordering changes from the original vertex set
  169. // so track reversals.
  170. //
  171. // Determinant computation and culling could be done before this.
  172. // Doing so causes headaches with computing deltas up front, though,
  173. // because the edges may change during sorting.
  174. //
  175. LPD3DTLVERTEX pVTmp;
  176. UINT uReversed;
  177. uReversed = 0;
  178. if (pV0->dvSY <= pV1->dvSY)
  179. {
  180. if (pV1->dvSY <= pV2->dvSY)
  181. {
  182. // Sorted.
  183. }
  184. else if (pV0->dvSY <= pV2->dvSY)
  185. {
  186. // Sorted order is 0 2 1.
  187. pVTmp = pV1;
  188. pV1 = pV2;
  189. pV2 = pVTmp;
  190. uReversed = 1;
  191. }
  192. else
  193. {
  194. // Sorted order is 2 0 1.
  195. pVTmp = pV0;
  196. pV0 = pV2;
  197. pV2 = pV1;
  198. pV1 = pVTmp;
  199. }
  200. }
  201. else if (pV1->dvSY < pV2->dvSY)
  202. {
  203. if (pV0->dvSY <= pV2->dvSY)
  204. {
  205. // Sorted order is 1 0 2.
  206. pVTmp = pV0;
  207. pV0 = pV1;
  208. pV1 = pVTmp;
  209. uReversed = 1;
  210. }
  211. else
  212. {
  213. // Sorted order is 1 2 0.
  214. pVTmp = pV0;
  215. pV0 = pV1;
  216. pV1 = pV2;
  217. pV2 = pVTmp;
  218. }
  219. }
  220. else
  221. {
  222. // Sorted order is 2 1 0.
  223. pVTmp = pV0;
  224. pV0 = pV2;
  225. pV2 = pVTmp;
  226. uReversed = 1;
  227. }
  228. FLOAT fX0 = pV0->dvSX;
  229. FLOAT fX1 = pV1->dvSX;
  230. FLOAT fX2 = pV2->dvSX;
  231. FLOAT fY0 = pV0->dvSY;
  232. FLOAT fY1 = pV1->dvSY;
  233. FLOAT fY2 = pV2->dvSY;
  234. //
  235. // Compute x,y deltas.
  236. //
  237. m_StpCtx.fDX10 = fX1 - fX0;
  238. m_StpCtx.fDX20 = fX2 - fX0;
  239. m_StpCtx.fDY10 = fY1 - fY0;
  240. m_StpCtx.fDY20 = fY2 - fY0;
  241. //
  242. // Compute determinant and do culling.
  243. //
  244. FLOAT fDet;
  245. fDet = m_StpCtx.fDX20 * m_StpCtx.fDY10 - m_StpCtx.fDX10 * m_StpCtx.fDY20;
  246. if (FLOAT_EQZ(fDet))
  247. {
  248. // No area, so bail out
  249. return FALSE;
  250. }
  251. // Get sign of determinant.
  252. UINT uDetCcw = FLOAT_GTZ(fDet) ? 1 : 0;
  253. // If culling is off the cull sign to check against is set to a
  254. // value that can't be matched so this single check is sufficient
  255. // for all three culling cases.
  256. //
  257. // Fold in sign reversal here rather than in uDetCcw because
  258. // we need the true sign later to determine whether the long edge is
  259. // to the left or the right.
  260. if ((uDetCcw ^ uReversed) == m_StpCtx.pCtx->uCullFaceSign)
  261. {
  262. return FALSE;
  263. }
  264. // Snap bounding vertex Y's to pixel centers and check for trivial reject.
  265. m_StpCtx.iY = ICEILF(fY0);
  266. m_iY2 = ICEILF(fY2);
  267. if (m_StpCtx.iY >= m_StpCtx.pCtx->Clip.bottom ||
  268. m_iY2 <= m_StpCtx.pCtx->Clip.top)
  269. {
  270. return FALSE;
  271. }
  272. INT iX0 = ICEILF(fX0);
  273. INT iX1 = ICEILF(fX1);
  274. INT iX2 = ICEILF(fX2);
  275. // Start 2 - 0 edge DXDY divide so that it's overlapped with the
  276. // integer processing done during X clip checking. The assumption
  277. // is that it's nearly zero cost when overlapped so it's worth
  278. // it to start it even when the clip check rejects the triangle.
  279. FLOAT fDX20, fDY20, fDXDY20;
  280. // Need to use stack variables so the assembly can understand the
  281. // address.
  282. fDX20 = m_StpCtx.fDX20;
  283. fDY20 = m_StpCtx.fDY20;
  284. FLD_BEGIN_DIVIDE(fDX20, fDY20, fDXDY20);
  285. // Computing the X triangle bounds involves quite a few operations,
  286. // but it allows for both trivial rejection and trivial acceptance.
  287. // Given that guard band clipping can lead to a lot of trivial rejections
  288. // and that there will usually be a lot of trivial acceptance cases,
  289. // the work is worth it.
  290. INT iMinX, iMaxX;
  291. BOOL bXAccept;
  292. MINMAX3(iX0, iX1, iX2, iMinX, iMaxX);
  293. m_iXWidth = iMaxX - iMinX;
  294. // Use X bounds for trivial reject and accept.
  295. if (iMinX >= m_StpCtx.pCtx->Clip.right ||
  296. iMaxX <= m_StpCtx.pCtx->Clip.left ||
  297. m_iXWidth <= 0)
  298. {
  299. bXAccept = FALSE;
  300. }
  301. else
  302. {
  303. if (iMinX >= m_StpCtx.pCtx->Clip.left &&
  304. iMaxX <= m_StpCtx.pCtx->Clip.right)
  305. {
  306. m_StpCtx.uFlags |= PRIMF_TRIVIAL_ACCEPT_X;
  307. }
  308. else
  309. {
  310. RSDPFM((RSM_XCLIP, "XClip bounds %5d - %5d, %5d\n",
  311. iMinX, iMaxX, m_iXWidth));
  312. }
  313. bXAccept = TRUE;
  314. }
  315. // Complete divide.
  316. FSTP_END_DIVIDE(fDXDY20);
  317. if (!bXAccept)
  318. {
  319. return FALSE;
  320. }
  321. // Clamp triangle Y's to clip rect.
  322. m_iY1 = ICEILF(fY1);
  323. if (m_StpCtx.iY < m_StpCtx.pCtx->Clip.top)
  324. {
  325. RSDPFM((RSM_YCLIP, "YClip iY %d to %d\n",
  326. m_StpCtx.iY, m_StpCtx.pCtx->Clip.top));
  327. m_StpCtx.iY = m_StpCtx.pCtx->Clip.top;
  328. if (m_iY1 < m_StpCtx.pCtx->Clip.top)
  329. {
  330. RSDPFM((RSM_YCLIP, "YClip iY1 %d to %d\n",
  331. m_iY1, m_StpCtx.pCtx->Clip.top));
  332. m_iY1 = m_StpCtx.pCtx->Clip.top;
  333. }
  334. }
  335. if (m_iY1 > m_StpCtx.pCtx->Clip.bottom)
  336. {
  337. RSDPFM((RSM_YCLIP, "YClip iY1 %d, iY2 %d to %d\n",
  338. m_iY1, m_iY2, m_StpCtx.pCtx->Clip.bottom));
  339. m_iY1 = m_StpCtx.pCtx->Clip.bottom;
  340. m_iY2 = m_StpCtx.pCtx->Clip.bottom;
  341. }
  342. else if (m_iY2 > m_StpCtx.pCtx->Clip.bottom)
  343. {
  344. RSDPFM((RSM_YCLIP, "YClip iY2 %d to %d\n",
  345. m_iY2, m_StpCtx.pCtx->Clip.bottom));
  346. m_iY2 = m_StpCtx.pCtx->Clip.bottom;
  347. }
  348. // Compute Y subpixel correction. This will include any Y
  349. // offset due to clamping.
  350. m_StpCtx.fDY = m_StpCtx.iY - fY0;
  351. // Compute trapzeoid heights. These will be restricted to
  352. // lie in the clip rect.
  353. RSASSERT(m_iY1 >= m_StpCtx.iY && m_iY2 >= m_iY1);
  354. m_uHeight10 = m_iY1 - m_StpCtx.iY;
  355. m_uHeight21 = m_iY2 - m_iY1;
  356. m_uHeight20 = m_uHeight10 + m_uHeight21;
  357. if (m_uHeight20 == 0)
  358. {
  359. // Triangle doesn't cover any pixels.
  360. return FALSE;
  361. }
  362. RSDPFM((RSM_TRIS, "Tstp (%.4f,%.4f) (%.4f,%.4f) (%.4f,%.4f)\n",
  363. fX0, fY0, fX1, fY1, fX2, fY2));
  364. RSDPFM((RSM_TRIS, " (%.4f,%.4f : %.4f,%.4f) %d:%d det %.4f\n",
  365. m_StpCtx.fDX10, m_StpCtx.fDY10,
  366. m_StpCtx.fDX20, m_StpCtx.fDY20,
  367. m_uHeight10, m_uHeight21, fDet));
  368. RSDPFM((RSM_Z, " Z (%f) (%f) (%f)\n",
  369. pV0->dvSZ, pV1->dvSZ, pV2->dvSZ));
  370. RSDPFM((RSM_DIFF, " diff (0x%08X) (0x%08X) (0x%08X)\n",
  371. pV0->dcColor, pV1->dcColor, pV2->dcColor));
  372. RSDPFM((RSM_DIDX, " didx (0x%08X) (0x%08X) (0x%08X)\n",
  373. pV0->dcColor, pV1->dcColor, pV2->dcColor));
  374. RSDPFM((RSM_SPEC, " spec (0x%08X) (0x%08X) (0x%08X)\n",
  375. pV0->dcSpecular & 0xffffff, pV1->dcSpecular & 0xffffff,
  376. pV2->dcSpecular & 0xffffff));
  377. RSDPFM((RSM_OOW, " OoW (%f) (%f) (%f)\n",
  378. pV0->dvRHW, pV1->dvRHW, pV2->dvRHW));
  379. RSDPFM((RSM_TEX1, " Tex1 (%f,%f) (%f,%f) (%f,%f)\n",
  380. pV0->dvTU, pV0->dvTV, pV1->dvTU, pV1->dvTV,
  381. pV2->dvTU, pV2->dvTV));
  382. RSDPFM((RSM_FOG, " Fog (0x%02X) (0x%02X) (0x%02X)\n",
  383. RGBA_GETALPHA(pV0->dcSpecular),
  384. RGBA_GETALPHA(pV1->dcSpecular),
  385. RGBA_GETALPHA(pV2->dcSpecular)));
  386. // Compute dx/dy for edges and initial X's.
  387. m_StpCtx.fDX = m_StpCtx.fDY * fDXDY20;
  388. FLOAT fX20 = fX0 + m_StpCtx.fDX;
  389. ComputeIntCarry(fX20, fDXDY20, &m_StpCtx.X20);
  390. m_StpCtx.fX20NC = (FLOAT)m_StpCtx.X20.iNC;
  391. m_StpCtx.fX20CY = (FLOAT)m_StpCtx.X20.iCY;
  392. RSDPFM((RSM_TRIS, " edge20 %f dxdy %f\n", fX20, fDXDY20));
  393. RSDPFM((RSM_TRIS, " (?.%d d %d nc %d cy %d)\n",
  394. m_StpCtx.X20.iFrac,
  395. m_StpCtx.X20.iDFrac, m_StpCtx.X20.iNC, m_StpCtx.X20.iCY));
  396. if (m_uHeight10 > 0)
  397. {
  398. FLOAT fDXDY10;
  399. FLOAT fX10;
  400. #ifdef CHECK_VERTICAL
  401. // This case probably doesn't occur enough to justify the code.
  402. if (FLOAT_EQZ(m_StpCtx.fDX10))
  403. {
  404. fDXDY10 = g_fZero;
  405. fX10 = fX0;
  406. }
  407. else
  408. #endif
  409. {
  410. fDXDY10 = m_StpCtx.fDX10 / m_StpCtx.fDY10;
  411. fX10 = fX0 + m_StpCtx.fDY * fDXDY10;
  412. }
  413. m_StpCtx.X10.iV = ICEILF(fX10);
  414. ComputeIntCarry(fX10, fDXDY10, &m_StpCtx.X10);
  415. RSDPFM((RSM_TRIS, " edge10 %f dxdy %f\n", fX10, fDXDY10));
  416. RSDPFM((RSM_TRIS, " (%d.%d d %d nc %d cy %d)\n",
  417. m_StpCtx.X10.iV, m_StpCtx.X10.iFrac,
  418. m_StpCtx.X10.iDFrac, m_StpCtx.X10.iNC, m_StpCtx.X10.iCY));
  419. }
  420. #if DBG
  421. else
  422. {
  423. // Make it easier to detect when an invalid edge is used.
  424. memset(&m_StpCtx.X10, 0, sizeof(m_StpCtx.X10));
  425. }
  426. #endif
  427. if (m_uHeight21 > 0)
  428. {
  429. FLOAT fDXDY21;
  430. FLOAT fX21;
  431. #ifdef CHECK_VERTICAL
  432. // This case probably doesn't occur enough to justify the code.
  433. if (FLOAT_COMPARE(fX1, ==, fX2))
  434. {
  435. fDXDY21 = g_fZero;
  436. fX21 = fX1;
  437. }
  438. else
  439. #endif
  440. {
  441. fDXDY21 = (fX2 - fX1) / (fY2 - fY1);
  442. fX21 = fX1 + (m_iY1 - fY1) * fDXDY21;
  443. }
  444. m_StpCtx.X21.iV = ICEILF(fX21);
  445. ComputeIntCarry(fX21, fDXDY21, &m_StpCtx.X21);
  446. RSDPFM((RSM_TRIS, " edge21 %f dxdy %f\n", fX21, fDXDY21));
  447. RSDPFM((RSM_TRIS, " (%d.%d d %d nc %d cy %d)\n",
  448. m_StpCtx.X21.iV, m_StpCtx.X21.iFrac,
  449. m_StpCtx.X21.iDFrac, m_StpCtx.X21.iNC, m_StpCtx.X21.iCY));
  450. }
  451. #if DBG
  452. else
  453. {
  454. // Make it easier to detect when an invalid edge is used.
  455. memset(&m_StpCtx.X21, 0, sizeof(m_StpCtx.X21));
  456. }
  457. #endif
  458. // The edge walker always walks the long edge so it may either
  459. // be a left or a right edge. Determine what side the long edge
  460. // is and perform appropriate snapping and subpixel adjustment
  461. // computations.
  462. //
  463. // The clip-clamped initial X pixel position is also computed and
  464. // any necessary offset added into the subpixel correction delta.
  465. if (uDetCcw)
  466. {
  467. // Long edge (0-2) is to the right.
  468. m_StpCtx.uFlags |= TRIF_X_DEC;
  469. m_StpCtx.pPrim->uFlags = D3DI_RASTPRIM_X_DEC;
  470. m_StpCtx.X20.iV = ICEILF(fX20) - 1;
  471. // Other edges are left edges. Bias them back by one
  472. // so that the span width computation can do R - L
  473. // rather than R - L + 1.
  474. m_StpCtx.X10.iV--;
  475. m_StpCtx.X21.iV--;
  476. // Clamp the initial X position.
  477. if (m_StpCtx.X20.iV >= m_StpCtx.pCtx->Clip.right)
  478. {
  479. m_StpCtx.iX = m_StpCtx.pCtx->Clip.right - 1;
  480. }
  481. else
  482. {
  483. m_StpCtx.iX = m_StpCtx.X20.iV;
  484. }
  485. }
  486. else
  487. {
  488. // Long edge (0-2) is to the left.
  489. m_StpCtx.pPrim->uFlags = 0;
  490. m_StpCtx.X20.iV = ICEILF(fX20);
  491. // Other edges are right edges. The ICEILF snapping done
  492. // already leaves them off by one so that R - L works.
  493. // Clamp the initial X position.
  494. if (m_StpCtx.X20.iV < m_StpCtx.pCtx->Clip.left)
  495. {
  496. m_StpCtx.iX = m_StpCtx.pCtx->Clip.left;
  497. }
  498. else
  499. {
  500. m_StpCtx.iX = m_StpCtx.X20.iV;
  501. }
  502. }
  503. // Update X subpixel correction. This delta includes any
  504. // offseting due to clamping of the initial pixel position.
  505. m_StpCtx.fDX += m_StpCtx.iX - fX20;
  506. RSDPFM((RSM_TRIS, " subp %f,%f\n", m_StpCtx.fDX, m_StpCtx.fDY));
  507. // Compute span-to-span steps for buffer pointers.
  508. m_StpCtx.DAttrNC.ipSurface = m_StpCtx.pCtx->iSurfaceStride +
  509. m_StpCtx.X20.iNC * m_StpCtx.pCtx->iSurfaceStep;
  510. m_StpCtx.DAttrNC.ipZ = m_StpCtx.pCtx->iZStride +
  511. m_StpCtx.X20.iNC * m_StpCtx.pCtx->iZStep;
  512. // Start one over determinant divide. Done after the multiplies
  513. // since integer multiplies require some of the FP unit.
  514. FLOAT fOoDet;
  515. FLD_BEGIN_DIVIDE(g_fOne, fDet, fOoDet);
  516. if (m_StpCtx.X20.iCY > m_StpCtx.X20.iNC)
  517. {
  518. m_StpCtx.DAttrCY.ipSurface = m_StpCtx.DAttrNC.ipSurface +
  519. m_StpCtx.pCtx->iSurfaceStep;
  520. m_StpCtx.DAttrCY.ipZ = m_StpCtx.DAttrNC.ipZ + m_StpCtx.pCtx->iZStep;
  521. }
  522. else
  523. {
  524. m_StpCtx.DAttrCY.ipSurface = m_StpCtx.DAttrNC.ipSurface -
  525. m_StpCtx.pCtx->iSurfaceStep;
  526. m_StpCtx.DAttrCY.ipZ = m_StpCtx.DAttrNC.ipZ - m_StpCtx.pCtx->iZStep;
  527. }
  528. //
  529. // Compute attribute functions.
  530. //
  531. // Set pure X/Y step deltas for surface and Z so that DX, DY, CY and NC all
  532. // have complete information and can be used interchangeably.
  533. if (m_StpCtx.uFlags & TRIF_X_DEC)
  534. {
  535. m_StpCtx.DAttrDX.ipSurface = -m_StpCtx.pCtx->iSurfaceStep;
  536. m_StpCtx.DAttrDX.ipZ = -m_StpCtx.pCtx->iZStep;
  537. }
  538. else
  539. {
  540. m_StpCtx.DAttrDX.ipSurface = m_StpCtx.pCtx->iSurfaceStep;
  541. m_StpCtx.DAttrDX.ipZ = m_StpCtx.pCtx->iZStep;
  542. }
  543. m_StpCtx.DAttrDY.ipSurface = m_StpCtx.pCtx->iSurfaceStride;
  544. m_StpCtx.DAttrDY.ipZ = m_StpCtx.pCtx->iZStride;
  545. // Finish overlapped divide.
  546. FSTP_END_DIVIDE(fOoDet);
  547. m_StpCtx.fOoDet = fOoDet;
  548. // The PrimProcessor is created zeroed out so the initial
  549. // state is FP clean. Later uses may put FP values in slots but
  550. // they should still be valid, so the optional computations here
  551. // should never result in FP garbage. It should therefore be
  552. // OK to use any mixture of attribute handlers since there should
  553. // never be any case where FP garbage will creep in.
  554. BOOL bNorm;
  555. // USED checks cannot be combined since TEX_USED is a multibit check.
  556. if ((m_StpCtx.uFlags & PRIMSF_TEX_USED) &&
  557. (m_StpCtx.uFlags & PRIMSF_PERSP_USED) &&
  558. (m_uPpFlags & PPF_NORMALIZE_RHW) &&
  559. NEEDS_NORMALIZE3(pV0->dvRHW, pV1->dvRHW, pV2->dvRHW))
  560. {
  561. NormalizeTriRHW(pV0, pV1, pV2);
  562. bNorm = TRUE;
  563. }
  564. else
  565. {
  566. bNorm = FALSE;
  567. }
  568. TriSetup_Start(&m_StpCtx, pV0, pV1, pV2);
  569. if (bNorm)
  570. {
  571. pV0->dvRHW = m_dvV0RHW;
  572. pV1->dvRHW = m_dvV1RHW;
  573. pV2->dvRHW = m_dvV2RHW;
  574. }
  575. return TRUE;
  576. }