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.

594 lines
18 KiB

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