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.

604 lines
18 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // buffer.cpp
  4. //
  5. // PrimProcessor buffering 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. // Define to use new/delete instead of VirtualAlloc/VirtualFree.
  20. #if 0
  21. #define USE_CPP_HEAP
  22. #endif
  23. // Define to show FP exceptions.
  24. #if 0
  25. #define UNMASK_EXCEPTIONS
  26. #endif
  27. //----------------------------------------------------------------------------
  28. //
  29. // PrimProcessor::PrimProcessor
  30. //
  31. // Initializes a triangle processor to an invalid state.
  32. //
  33. //----------------------------------------------------------------------------
  34. PrimProcessor::PrimProcessor(void)
  35. {
  36. // Zero everything to NULL initial pointers and eliminate FP garbage.
  37. memset(this, 0, sizeof(PrimProcessor)); // TODO: Fix this unextendable stuff.
  38. m_StpCtx.PrimProcessor = (PVOID)this;
  39. // Initialize to values that will force a validation.
  40. // ATTENTION - Default to normalizing RHW. This is a performance hit
  41. // and should be removed if possible.
  42. m_uPpFlags = PPF_STATE_CHANGED | PPF_NORMALIZE_RHW;
  43. m_PrimType = D3DPT_FORCE_DWORD;
  44. m_VertType = RAST_FORCE_DWORD;
  45. }
  46. //----------------------------------------------------------------------------
  47. //
  48. // PrimProcessor::Initialize
  49. //
  50. // Initializes the triangle processor to an active state.
  51. //
  52. //----------------------------------------------------------------------------
  53. #define CACHE_LINE 32
  54. #define BUFFER_SIZE 4096
  55. // Uncomment to force a flush every span for debug purposes
  56. //#define BUFFER_SIZE ((8 * sizeof(D3DI_RASTSPAN)) + sizeof(D3DI_RASTPRIM))
  57. // TODO: Move into constructor? How many places called?
  58. HRESULT
  59. PrimProcessor::Initialize(void)
  60. {
  61. HRESULT hr;
  62. INT32 uSize = sizeof(D3DI_RASTPRIM);
  63. // Assert that both RASTPRIM and RASTSPAN are multiples of the cache
  64. // line size so that everything in the buffer stays cache aligned.
  65. RSASSERT((uSize & (CACHE_LINE - 1)) == 0 &&
  66. (uSize & (CACHE_LINE - 1)) == 0);
  67. #ifdef USE_CPP_HEAP
  68. m_pBuffer = new UINT8[BUFFER_SIZE];
  69. #else
  70. // Get a page-aligned buffer.
  71. m_pBuffer = (PUINT8)
  72. VirtualAlloc(NULL, BUFFER_SIZE,
  73. MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
  74. #endif
  75. if (m_pBuffer == NULL)
  76. {
  77. return RSHRCHK(E_OUTOFMEMORY);
  78. }
  79. m_pBufferEnd = m_pBuffer+BUFFER_SIZE;
  80. #ifdef USE_CPP_HEAP
  81. // Compute cache-line aligned start in the buffer. Formulated
  82. // somewhat oddly to avoid casting a complete pointer to a DWORD and
  83. // back.
  84. m_pBufferStart = m_pBuffer +
  85. ((CACHE_LINE - ((UINT)m_pBuffer & (CACHE_LINE - 1))) &
  86. (CACHE_LINE - 1));
  87. #else
  88. // Page aligned memory should be cache aligned.
  89. RSASSERT(((UINT_PTR)m_pBuffer & (CACHE_LINE - 1)) == 0);
  90. m_pBufferStart = m_pBuffer;
  91. #endif
  92. m_pCur = m_pBufferStart;
  93. return S_OK;
  94. }
  95. //----------------------------------------------------------------------------
  96. //
  97. // PrimProcessor::~PrimProcessor
  98. //
  99. //----------------------------------------------------------------------------
  100. PrimProcessor::~PrimProcessor(void)
  101. {
  102. #ifdef USE_CPP_HEAP
  103. delete m_pBuffer;
  104. #else
  105. if (m_pBuffer != NULL)
  106. {
  107. VirtualFree(m_pBuffer, 0, MEM_RELEASE);
  108. }
  109. #endif
  110. }
  111. //----------------------------------------------------------------------------
  112. //
  113. // PrimProcessor::ResetBuffer
  114. //
  115. // Initialize buffer pointers to an empty state.
  116. //
  117. //----------------------------------------------------------------------------
  118. inline void
  119. PrimProcessor::ResetBuffer(void)
  120. {
  121. m_pCur = m_pBufferStart;
  122. m_StpCtx.pPrim = NULL;
  123. m_pOldPrim = NULL;
  124. }
  125. //----------------------------------------------------------------------------
  126. //
  127. // DumpPrims
  128. //
  129. // Debugging function to dump primitives sent to the span renderer.
  130. //
  131. //----------------------------------------------------------------------------
  132. #if DBG
  133. void
  134. DumpPrims(PSETUPCTX pStpCtx)
  135. {
  136. PD3DI_RASTPRIM pPrim;
  137. UINT uOldFlags;
  138. uOldFlags = RSGETFLAGS(DBG_OUTPUT_FLAGS);
  139. RSSETFLAGS(DBG_OUTPUT_FLAGS, uOldFlags | DBG_OUTPUT_ALL_MATCH);
  140. for (pPrim = pStpCtx->pCtx->pPrim; pPrim != NULL; pPrim = pPrim->pNext)
  141. {
  142. RSDPFM((RSM_BUFPRIM, "Prim at %p, %d spans at %p\n",
  143. pPrim, pPrim->uSpans, pPrim+1));
  144. RSDPFM((RSM_BUFPRIM | RSM_OOW, " DOoWDX %X (%f)\n",
  145. pPrim->iDOoWDX, (FLOAT)pPrim->iDOoWDX / OOW_SCALE));
  146. if ((RSGETFLAGS(DBG_OUTPUT_MASK) & RSM_BUFSPAN) ||
  147. (RSGETFLAGS(DBG_USER_FLAGS) & (RSU_MARK_SPAN_EDGES |
  148. RSU_CHECK_SPAN_EDGES)))
  149. {
  150. PD3DI_RASTSPAN pSpan;
  151. UINT16 i;
  152. pSpan = (PD3DI_RASTSPAN)(pPrim+1);
  153. for (i = 0; i < pPrim->uSpans; i++)
  154. {
  155. RSDPFM((RSM_BUFSPAN,
  156. " Span at (%d,%d), pix %c%d, S %p Z %p\n",
  157. pSpan->uX, pSpan->uY,
  158. (pPrim->uFlags & D3DI_RASTPRIM_X_DEC) ? '-' : '+',
  159. pSpan->uPix, pSpan->pSurface, pSpan->pZ));
  160. if (RSGETFLAGS(DBG_USER_FLAGS) & (RSU_MARK_SPAN_EDGES |
  161. RSU_CHECK_SPAN_EDGES))
  162. {
  163. PUINT16 pPix;
  164. pPix = (PUINT16)pSpan->pSurface;
  165. if (RSGETFLAGS(DBG_USER_FLAGS) & RSU_CHECK_SPAN_EDGES)
  166. {
  167. if (*pPix != 0)
  168. {
  169. RSDPF((" Overwrite at %p: %X\n", pPix, *pPix));
  170. }
  171. }
  172. if (RSGETFLAGS(DBG_USER_FLAGS) & RSU_MARK_SPAN_EDGES)
  173. {
  174. *pPix = 0xffff;
  175. }
  176. if (pSpan->uPix > 1)
  177. {
  178. if (pPrim->uFlags & D3DI_RASTPRIM_X_DEC)
  179. {
  180. pPix = (PUINT16)pSpan->pSurface -
  181. (pSpan->uPix - 1);
  182. }
  183. else
  184. {
  185. pPix = (PUINT16)pSpan->pSurface +
  186. (pSpan->uPix - 1);
  187. }
  188. if (RSGETFLAGS(DBG_USER_FLAGS) & RSU_CHECK_SPAN_EDGES)
  189. {
  190. if (*pPix != 0)
  191. {
  192. RSDPF((" Overwrite at %p: %X\n",
  193. pPix, *pPix));
  194. }
  195. }
  196. if (RSGETFLAGS(DBG_USER_FLAGS) & RSU_MARK_SPAN_EDGES)
  197. {
  198. *pPix = 0xffff;
  199. }
  200. }
  201. }
  202. FLOAT fZScale;
  203. if (pStpCtx->pCtx->iZBitCount == 16)
  204. {
  205. fZScale = Z16_SCALE;
  206. }
  207. else
  208. {
  209. fZScale = Z32_SCALE;
  210. }
  211. RSDPFM((RSM_BUFSPAN | RSM_Z,
  212. " Z %X (%f)\n",
  213. pSpan->uZ, (FLOAT)pSpan->uZ / fZScale));
  214. RSDPFM((RSM_BUFSPAN | RSM_DIFF,
  215. " D %X,%X,%X,%X (%f,%f,%f,%f)\n",
  216. pSpan->uB, pSpan->uG, pSpan->uR, pSpan->uA,
  217. (FLOAT)pSpan->uB / COLOR_SCALE,
  218. (FLOAT)pSpan->uG / COLOR_SCALE,
  219. (FLOAT)pSpan->uR / COLOR_SCALE,
  220. (FLOAT)pSpan->uA / COLOR_SCALE));
  221. RSDPFM((RSM_BUFSPAN | RSM_SPEC,
  222. " S %X,%X,%X (%f,%f,%f)\n",
  223. pSpan->uBS, pSpan->uGS, pSpan->uRS,
  224. (FLOAT)pSpan->uBS / COLOR_SCALE,
  225. (FLOAT)pSpan->uGS / COLOR_SCALE,
  226. (FLOAT)pSpan->uRS / COLOR_SCALE));
  227. RSDPFM((RSM_BUFSPAN | RSM_DIDX,
  228. " I %X,%X (%f,%f)\n",
  229. pSpan->iIdx, pSpan->iIdxA,
  230. (FLOAT)pSpan->iIdx / INDEX_COLOR_SCALE,
  231. (FLOAT)pSpan->iIdxA / INDEX_COLOR_SCALE));
  232. RSDPFM((RSM_BUFSPAN | RSM_OOW,
  233. " OoW %X (%f), W %X (%f)\n",
  234. pSpan->iOoW, (FLOAT)pSpan->iOoW / OOW_SCALE,
  235. pSpan->iW, (FLOAT)pSpan->iW / W_SCALE));
  236. RSDPFM((RSM_BUFSPAN | RSM_LOD,
  237. " LOD %X (%f), DLOD %X (%f)\n",
  238. pSpan->iLOD, (FLOAT)pSpan->iLOD / LOD_SCALE,
  239. pSpan->iDLOD, (FLOAT)pSpan->iDLOD / LOD_SCALE));
  240. if (pStpCtx->uFlags & PRIMSF_PERSP_USED)
  241. {
  242. RSDPFM((RSM_BUFSPAN | RSM_TEX1,
  243. " PTex1 %X,%X (%f,%f) (%f,%f)\n",
  244. pSpan->UVoW[0].iUoW, pSpan->UVoW[0].iVoW,
  245. (FLOAT)pSpan->UVoW[0].iUoW / TEX_SCALE,
  246. (FLOAT)pSpan->UVoW[0].iVoW / TEX_SCALE,
  247. ((FLOAT)pSpan->UVoW[0].iUoW * OOW_SCALE) /
  248. (TEX_SCALE * (FLOAT)pSpan->iOoW),
  249. ((FLOAT)pSpan->UVoW[0].iVoW * OOW_SCALE) /
  250. (TEX_SCALE * (FLOAT)pSpan->iOoW)));
  251. }
  252. else
  253. {
  254. RSDPFM((RSM_BUFSPAN | RSM_TEX1,
  255. " ATex1 %X,%X (%f,%f)\n",
  256. pSpan->UVoW[0].iUoW, pSpan->UVoW[0].iVoW,
  257. (FLOAT)pSpan->UVoW[0].iUoW / TEX_SCALE,
  258. (FLOAT)pSpan->UVoW[0].iVoW / TEX_SCALE));
  259. }
  260. RSDPFM((RSM_BUFSPAN | RSM_FOG,
  261. " Fog %X (%f), DFog %X (%f)\n",
  262. pSpan->uFog, (FLOAT)pSpan->uFog / FOG_SCALE,
  263. pSpan->iDFog, (FLOAT)pSpan->iDFog / FOG_SCALE));
  264. pSpan++;
  265. }
  266. }
  267. }
  268. RSSETFLAGS(DBG_OUTPUT_FLAGS, uOldFlags);
  269. }
  270. #endif // DBG
  271. //----------------------------------------------------------------------------
  272. //
  273. // PrimProcessor::Flush
  274. //
  275. // Flushes any remaining data from the buffer.
  276. //
  277. //----------------------------------------------------------------------------
  278. HRESULT
  279. PrimProcessor::Flush(void)
  280. {
  281. HRESULT hr;
  282. if (m_pCur - m_pBufferStart > sizeof(D3DI_RASTPRIM))
  283. {
  284. // Process data.
  285. m_StpCtx.pCtx->pPrim = (PD3DI_RASTPRIM)m_pBufferStart;
  286. m_StpCtx.pCtx->pNext = NULL;
  287. #if DBG
  288. if ((RSGETFLAGS(DBG_OUTPUT_MASK) & (RSM_BUFPRIM | RSM_BUFSPAN)) ||
  289. (RSGETFLAGS(DBG_USER_FLAGS) & (RSU_MARK_SPAN_EDGES |
  290. RSU_CHECK_SPAN_EDGES)))
  291. {
  292. DumpPrims(&m_StpCtx);
  293. }
  294. if ((RSGETFLAGS(DBG_USER_FLAGS) & RSU_NO_RENDER_SPANS) == 0)
  295. {
  296. if (RSGETFLAGS(DBG_USER_FLAGS) & RSU_BREAK_ON_RENDER_SPANS)
  297. {
  298. DebugBreak();
  299. }
  300. RSHRCHK(m_StpCtx.pCtx->pfnRenderSpans(m_StpCtx.pCtx));
  301. }
  302. else
  303. {
  304. hr = DD_OK;
  305. }
  306. #else
  307. hr = m_StpCtx.pCtx->pfnRenderSpans(m_StpCtx.pCtx);
  308. #endif
  309. ResetBuffer();
  310. }
  311. else
  312. {
  313. hr = DD_OK;
  314. }
  315. return hr;
  316. }
  317. //----------------------------------------------------------------------------
  318. //
  319. // PrimProcessor::FlushPartial
  320. //
  321. // Flushes the buffer in the middle of a primitive. Preserves last
  322. // partial primitive and replaces it in the buffer after the flush.
  323. //
  324. //----------------------------------------------------------------------------
  325. HRESULT
  326. PrimProcessor::FlushPartial(void)
  327. {
  328. D3DI_RASTPRIM SavedPrim;
  329. HRESULT hr;
  330. RSDPFM((RSM_BUFFER, "FlushPartial, saving prim at %p, Y %d\n",
  331. m_StpCtx.pPrim, m_StpCtx.iY));
  332. // Not enough space. Flush current buffer. We need to
  333. // save the current prim and put it back in the buffer after the
  334. // flush since it's being extended.
  335. SavedPrim = *m_StpCtx.pPrim;
  336. RSHRRET(Flush());
  337. GET_PRIM();
  338. *m_StpCtx.pPrim = SavedPrim;
  339. COMMIT_PRIM(FALSE);
  340. return DD_OK;
  341. }
  342. //----------------------------------------------------------------------------
  343. //
  344. // PrimProcessor::AppendPrim
  345. //
  346. // Ensures that some primitive is active in the buffer for spans to
  347. // be added to. If no valid primitive is available to append to,
  348. // a zeroed primitive is committed into the buffer.
  349. //
  350. //----------------------------------------------------------------------------
  351. HRESULT
  352. PrimProcessor::AppendPrim(void)
  353. {
  354. // If there's no primitive or the current primitive has not
  355. // been committed, commit a clean primitive into the buffer.
  356. if (m_StpCtx.pPrim == NULL ||
  357. (PUINT8)m_StpCtx.pPrim == m_pCur)
  358. {
  359. GET_PRIM();
  360. COMMIT_PRIM(TRUE);
  361. }
  362. return DD_OK;
  363. }
  364. //----------------------------------------------------------------------------
  365. //
  366. // PrimProcessor::Begin
  367. //
  368. // Resets the buffer to an empty state in preparation for incoming
  369. // triangles.
  370. //
  371. //----------------------------------------------------------------------------
  372. void
  373. PrimProcessor::Begin(void)
  374. {
  375. UINT16 uFpCtrl;
  376. FPU_GET_MODE(uFpCtrl);
  377. m_uFpCtrl = uFpCtrl;
  378. uFpCtrl =
  379. FPU_MODE_CHOP_ROUND(
  380. FPU_MODE_LOW_PRECISION(
  381. FPU_MODE_MASK_EXCEPTIONS(m_uFpCtrl)));
  382. #if defined(_X86_) && defined(UNMASK_EXCEPTIONS)
  383. // Unmask some exceptions so that we can eliminate them.
  384. // This requires a safe set to clear any exceptions that
  385. // are currently asserted.
  386. //
  387. // Exceptions left masked:
  388. // Precision, denormal.
  389. // Exceptions unmasked:
  390. // Underflow, overflow, divzero, invalid op.
  391. uFpCtrl &= ~0x1d;
  392. FPU_SAFE_SET_MODE(uFpCtrl);
  393. #else
  394. FPU_SET_MODE(uFpCtrl);
  395. #endif
  396. m_uPpFlags |= PPF_IN_BEGIN;
  397. ResetBuffer();
  398. }
  399. //----------------------------------------------------------------------------
  400. //
  401. // PrimProcessor::End
  402. //
  403. // Flushes if necessary and cleans up.
  404. //
  405. //----------------------------------------------------------------------------
  406. HRESULT
  407. PrimProcessor::End(void)
  408. {
  409. HRESULT hr;
  410. if (m_pCur - m_pBufferStart > sizeof(D3DI_RASTPRIM))
  411. {
  412. RSHRCHK(Flush());
  413. }
  414. else
  415. {
  416. hr = DD_OK;
  417. }
  418. UINT16 uFpCtrl = m_uFpCtrl;
  419. FPU_SAFE_SET_MODE(uFpCtrl);
  420. m_uPpFlags &= ~PPF_IN_BEGIN;
  421. return hr;
  422. }
  423. //----------------------------------------------------------------------------
  424. //
  425. // PrimProcessor::SetCtx
  426. //
  427. // Sets the rasterization context to operate in.
  428. //
  429. //----------------------------------------------------------------------------
  430. void
  431. PrimProcessor::SetCtx(PD3DI_RASTCTX pCtx)
  432. {
  433. // This function can't be called inside a Begin/End pair. This
  434. // is enforced so that we don't have to worry about the span
  435. // rendering function changing in the middle of a batch.
  436. RSASSERT((m_uPpFlags & PPF_IN_BEGIN) == 0);
  437. m_StpCtx.pCtx = pCtx;
  438. }
  439. //----------------------------------------------------------------------------
  440. //
  441. // PrimProcessor::AllocSpans
  442. //
  443. // Checks to see if there's room in the buffer for the requested number
  444. // of spans. If so the buffer pointer is updated and a pointer is returned.
  445. // If the requested number is not available but some reasonable number is,
  446. // return that many. Otherwise the buffer is flushed and the process starts
  447. // over. The "reasonable" number must therefore be no more than what
  448. // can fit in the buffer at once.
  449. //
  450. //----------------------------------------------------------------------------
  451. // Space for enough spans to avoid a flush.
  452. #define AVOID_FLUSH_SPACE (8 * sizeof(D3DI_RASTSPAN))
  453. HRESULT
  454. PrimProcessor::AllocSpans(PUINT pcSpans, PD3DI_RASTSPAN *ppSpan)
  455. {
  456. PD3DI_RASTSPAN pSpan;
  457. HRESULT hr;
  458. UINT uSpanSize;
  459. RSASSERT(AVOID_FLUSH_SPACE <= (BUFFER_SIZE - sizeof(D3DI_RASTPRIM)));
  460. // The multiplies and divides here will be really bad unless
  461. // RASTPRIM is a nice power-of-two in size.
  462. RSASSERT((sizeof(D3DI_RASTSPAN) & (sizeof(D3DI_RASTSPAN) - 1)) == 0);
  463. uSpanSize = *pcSpans * sizeof(D3DI_RASTSPAN);
  464. for (;;)
  465. {
  466. // First check for space for all requested spans.
  467. if (m_pCur + uSpanSize > m_pBufferEnd)
  468. {
  469. // Not enough space for everything, so see if we have
  470. // enough space to avoid a flush.
  471. if (m_pCur + AVOID_FLUSH_SPACE > m_pBufferEnd)
  472. {
  473. // Not enough space, so flush.
  474. RSHRCHK(FlushPartial());
  475. if (hr != DD_OK)
  476. {
  477. *pcSpans = 0;
  478. return hr;
  479. }
  480. // Loop around. Flush is guaranteed to at least produce
  481. // AVOID_FLUSH_SPACE so the loop will always exit.
  482. }
  483. else
  484. {
  485. // Not enough space for everything but enough space
  486. // to return some. Set new span count.
  487. *pcSpans = (UINT)((m_pBufferEnd - m_pCur) / sizeof(D3DI_RASTSPAN));
  488. uSpanSize = *pcSpans * sizeof(D3DI_RASTSPAN);
  489. break;
  490. }
  491. }
  492. else
  493. {
  494. break;
  495. }
  496. }
  497. pSpan = (PD3DI_RASTSPAN)m_pCur;
  498. m_pCur += uSpanSize;
  499. *ppSpan = pSpan;
  500. RSDPFM((RSM_BUFFER, "Alloc %d spans at %p, cur %p\n",
  501. *pcSpans, pSpan, m_pCur));
  502. return DD_OK;
  503. }
  504. //----------------------------------------------------------------------------
  505. //
  506. // PrimProcessor::FreeSpans and FreeSpans
  507. //
  508. // Returns space given out by AllocSpans.
  509. //
  510. //----------------------------------------------------------------------------
  511. void
  512. PrimProcessor::FreeSpans(UINT cSpans)
  513. {
  514. m_pCur -= cSpans * sizeof(D3DI_RASTSPAN);
  515. RSDPFM((RSM_BUFFER, "Free %d spans at %p, cur %p\n", cSpans,
  516. m_pCur + cSpans * sizeof(D3DI_RASTSPAN), m_pCur));
  517. }