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.

498 lines
19 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (C) Microsoft Corporation, 1998.
  3. //
  4. // fragrslv.cpp
  5. //
  6. // Direct3D Reference Rasterizer - Fragment Resolve Methods
  7. //
  8. ///////////////////////////////////////////////////////////////////////////////
  9. #include "pch.cpp"
  10. #pragma hdrstop
  11. // fragment resolution controls - need to expose these somehow (maybe...)
  12. static BOOL g_bPreMultAlpha = TRUE;
  13. static BOOL g_bDoCoverageOnly = FALSE;
  14. //-----------------------------------------------------------------------------
  15. //
  16. // CountFrags - Utility to count fragments in a linked list.
  17. //
  18. //-----------------------------------------------------------------------------
  19. int
  20. CountFrags(RRFRAGMENT* pFrag)
  21. {
  22. if (g_iDPFLevel < 4) { return 0; }
  23. int iRet = 0;
  24. while ( NULL != pFrag ) { pFrag = (RRFRAGMENT* )pFrag->pNext; iRet++; }
  25. return iRet;
  26. }
  27. //-----------------------------------------------------------------------------
  28. //
  29. // DPFFrags - Utility to debug-print fragment list.
  30. //
  31. //-----------------------------------------------------------------------------
  32. void
  33. DPFFrags(RRFRAGMENT* pFrag)
  34. {
  35. if (g_iDPFLevel < 7) { return; }
  36. while (NULL != pFrag)
  37. {
  38. DPFM(7,FRAG,(" (%06x,%06x) %08x %f %04x\n",
  39. pFrag,pFrag->pNext,UINT32(pFrag->Color),FLOAT(pFrag->Depth),pFrag->CvgMask))
  40. pFrag = (RRFRAGMENT *)pFrag->pNext;
  41. }
  42. }
  43. //-----------------------------------------------------------------------------
  44. //
  45. // DoFragResolve - Invoked during the buffer-resolve for each pixel which
  46. // has fragments. Takes a pointer to a linked list of fragments and returns
  47. // the resolved color.
  48. //
  49. // This constists of two steps: fragment sorting; and fragment resolve
  50. // accumulation. The fragments are sorted by stepping through the original
  51. // linked list and moving the fragments into a new linked list (using the
  52. // same link pointers) which is sorted in Z.
  53. //
  54. // The fragment resolve occurs in one of two ways depending on if any non-opaque
  55. // fragments exist in the list (this is determined during the sort). If there
  56. // are only opaque fragments, then the resolve accumulation depends only on
  57. // the coverage masks and is thus simplified. For cases with fragments due
  58. // to transparency, and more complex (and slower) resolve accumulation is
  59. // performed.
  60. //
  61. //-----------------------------------------------------------------------------
  62. void
  63. ReferenceRasterizer::DoFragResolve(
  64. RRColor& ResolvedColor, // out: final color for pixel
  65. RRDepth& ResolvedDepth, // out: final depth for pixel
  66. RRFRAGMENT* pFrag, // in: pointer to frag list for pixel
  67. const RRColor& CoveredColor ) // out: color of frontmost fully covered sample
  68. {
  69. DPFM(7,FRAG,(" presort\n")) DPFFrags(pFrag);
  70. //
  71. // reform fragments into sorted (front-to-back) linked list
  72. //
  73. // put first fragment into sortlist
  74. RRFRAGMENT* pFragSort = pFrag;
  75. pFrag = (RRFRAGMENT *)pFrag->pNext;
  76. pFragSort->pNext = NULL;
  77. // track if any non-opaque alphas (used to select resolve routine)
  78. // init value by checking the first one (already in sort list)
  79. BOOL bAnyNonOpaque = ( UINT8(pFragSort->Color.A) < 0xff );
  80. // step thru fragment list and move each fragment into sort list
  81. while ( NULL != pFrag )
  82. {
  83. // check for non-opaque alpha
  84. if ( UINT8(pFrag->Color.A) < 0xff ) { bAnyNonOpaque = TRUE; }
  85. // get ptr to next here so it can be overwritten
  86. RRFRAGMENT* pFragNext = (RRFRAGMENT *)pFrag->pNext;
  87. // use this to step thru sort list and insert
  88. RRFRAGMENT **ppFragSortT = &pFragSort;
  89. while ( NULL != *ppFragSortT )
  90. {
  91. if ( DepthCloser( pFrag->Depth, (*ppFragSortT)->Depth ) )
  92. {
  93. // current frag is closer than sort list entry, so
  94. // before this sort entry
  95. pFrag->pNext = *ppFragSortT;
  96. *ppFragSortT = pFrag;
  97. break;
  98. }
  99. else if ( NULL == (*ppFragSortT)->pNext )
  100. {
  101. // if last, then insert after this sort list entry
  102. (*ppFragSortT)->pNext = pFrag;
  103. pFrag->pNext = NULL;
  104. break;
  105. }
  106. ppFragSortT = (RRFRAGMENT **)&((*ppFragSortT)->pNext);
  107. }
  108. // advance input frag list
  109. pFrag = pFragNext;
  110. }
  111. // all fragments have now been passed to sort list in front-to-back order
  112. DPFM(7,FRAG,(" postsort\n")) DPFFrags(pFragSort);
  113. // return first sorted fragment (this is the closest, which is as good
  114. // as anything to put into the depth buffer for the resolved pixels...)
  115. ResolvedDepth = pFragSort->Depth;
  116. //
  117. // now step thru sorted list and accumulate color
  118. //
  119. if ( bAnyNonOpaque )
  120. {
  121. // here for fragment resolve accumulation which also does
  122. // full transparency computations - use this only if any
  123. // non-opaque fragments
  124. // instantiate and reset fragment resolve accumulator
  125. FragResolveAccum ResAccum;
  126. ResAccum.Reset();
  127. // per frag
  128. pFrag = pFragSort;
  129. BOOL bCovered = FALSE;
  130. while ( NULL != pFrag )
  131. {
  132. bCovered = ResAccum.Accum( pFrag->CvgMask, pFrag->Color );
  133. if (bCovered) { break; } // fully covered, so don't do rest of frags (or background)
  134. pFrag = (RRFRAGMENT *)pFrag->pNext;
  135. }
  136. // add in background color (last)
  137. if ( !bCovered && ( UINT8(CoveredColor.A) > 0 ) )
  138. {
  139. ResAccum.Accum( TL_CVGFULL, CoveredColor );
  140. }
  141. // unload accumulator
  142. ResAccum.GetColor( ResolvedColor );
  143. }
  144. else
  145. {
  146. //
  147. // here for fragment resolve of all fully opaque fragments
  148. //
  149. //
  150. // accumulated coverage and color
  151. //
  152. CVGMASK CvgMaskAccum = 0x0;
  153. FLOAT fRAcc = 0.F; // these 0. to 1. range
  154. FLOAT fGAcc = 0.F;
  155. FLOAT fBAcc = 0.F;
  156. FLOAT fWeightAccum = 0.F;
  157. // per frag
  158. pFrag = pFragSort;
  159. while ( NULL != pFrag )
  160. {
  161. // compute this fragment's contribution
  162. CVGMASK CvgMaskContrib = pFrag->CvgMask & ~(CvgMaskAccum);
  163. FLOAT fWeight = (1.f/16.f) * (FLOAT)CountSetBits(CvgMaskContrib, 16);
  164. // accumulate rgb
  165. fRAcc += fWeight * FLOAT(pFrag->Color.R);
  166. fGAcc += fWeight * FLOAT(pFrag->Color.G);
  167. fBAcc += fWeight * FLOAT(pFrag->Color.B);
  168. // accumulate total coverage and weight
  169. CvgMaskAccum |= CvgMaskContrib;
  170. fWeightAccum += fWeight;
  171. // bail out early if fully covered
  172. if ( TL_CVGFULL == CvgMaskAccum ) { goto DoneAccumulating; }
  173. // next
  174. pFrag = (RRFRAGMENT *)pFrag->pNext;
  175. }
  176. // blend with background color/alpha
  177. if ( (fWeightAccum < 1.f) && ( UINT8(CoveredColor.A) > 0 ) )
  178. {
  179. // blend in remaining weight of background color
  180. FLOAT fWeightBg = 1.F - fWeightAccum;
  181. fRAcc += fWeightBg * FLOAT(CoveredColor.R);
  182. fGAcc += fWeightBg * FLOAT(CoveredColor.G);
  183. fBAcc += fWeightBg * FLOAT(CoveredColor.B);
  184. // fix accumulated weight - pixel is fully covered now
  185. fWeightAccum = 1.f;
  186. }
  187. DoneAccumulating:
  188. // clamp accumulators
  189. if ( fWeightAccum > 1.F ) { fWeightAccum = 1.F; }
  190. if ( fRAcc > 1.F ) { fRAcc = 1.F; }
  191. if ( fGAcc > 1.F ) { fGAcc = 1.F; }
  192. if ( fBAcc > 1.F ) { fBAcc = 1.F; }
  193. // set in color return
  194. ResolvedColor.A = fWeightAccum;
  195. ResolvedColor.R = fRAcc;
  196. ResolvedColor.G = fGAcc;
  197. ResolvedColor.B = fBAcc;
  198. }
  199. // free this pixel's fragments
  200. pFrag = pFragSort;
  201. while ( NULL != pFrag )
  202. {
  203. RRFRAGMENT* pFragFree = pFrag;
  204. pFrag = (RRFRAGMENT*)pFrag->pNext;
  205. FragFree( pFragFree );
  206. }
  207. return;
  208. }
  209. //-----------------------------------------------------------------------------
  210. //
  211. // DoBufferResolve - Invoked at EndScene to resolve fragments into single
  212. // color for each pixel location.
  213. //
  214. //-----------------------------------------------------------------------------
  215. void
  216. ReferenceRasterizer::DoBufferResolve(void)
  217. {
  218. DPFM(2,FRAG,(" DoBufferResolve (%d,%d)\n",m_pRenderTarget->m_iWidth,m_pRenderTarget->m_iHeight))
  219. // buffer may not be allocated if there were no fragments
  220. if (NULL == m_ppFragBuf) { return; }
  221. for ( int iY=0; iY < m_pRenderTarget->m_iHeight; iY++ )
  222. {
  223. for ( int iX=0; iX < m_pRenderTarget->m_iWidth; iX++ )
  224. {
  225. RRFRAGMENT* pFrag = *(m_ppFragBuf + (m_pRenderTarget->m_iWidth*iY) + iX);
  226. if ( NULL != pFrag )
  227. {
  228. DPFM(5,FRAG,(" DoResolve(%d,%d) %d\n",iX,iY,CountFrags(pFrag)))
  229. // read buffer color for background blend
  230. RRColor PixelColor; m_pRenderTarget->ReadPixelColor( iX,iY, PixelColor);
  231. // do resolve
  232. RRColor ResolvedColor;
  233. RRDepth ResolvedDepth(pFrag->Depth.GetSType());
  234. DoFragResolve( ResolvedColor, ResolvedDepth, pFrag, PixelColor );
  235. // write color back to buffer; write frontmost depth back to
  236. // pixel buffer (it's at least a little better than the backmost
  237. // opaque sample...)
  238. WritePixel( iX,iY, ResolvedColor, ResolvedDepth );
  239. // show frags freed (free happens during resolve)
  240. *(m_ppFragBuf + (m_pRenderTarget->m_iWidth*iY) + iX) = NULL;
  241. }
  242. }
  243. }
  244. DPFM(3,FRAG,(" DoBufferResolve - done\n"))
  245. }
  246. ///////////////////////////////////////////////////////////////////////////////
  247. // //
  248. // Fragment Resolve Accumulator //
  249. // //
  250. ///////////////////////////////////////////////////////////////////////////////
  251. //
  252. // FragResolveAccum - This object is the fragment resolver used when
  253. // non-opaque fragments are present. This has the effect of resolving
  254. // each of the 16 subpixel locations independently to produce the fully
  255. // correct result. Several optimizations are used to minimize the actual
  256. // number of accumulation computations that need to occur.
  257. //
  258. //-----------------------------------------------------------------------------
  259. //
  260. // Reset - Called prior to resolving a list of fragments to initialize the
  261. // internal state.
  262. //
  263. //-----------------------------------------------------------------------------
  264. void
  265. FragResolveAccum::Reset(void)
  266. {
  267. DPFM(5, FRAG, (" FragResolveAccum: reset\n"))
  268. m_ArrayUsageMask = 0x0001; // use first array entry only (at first)
  269. m_CvgArray[0].Mask = TL_CVGFULL;
  270. m_CvgArray[0].fAlpha = 1.;
  271. m_fA = 0.;
  272. m_fR = 0.;
  273. m_fG = 0.;
  274. m_fB = 0.;
  275. m_CvgOpaqueMask = 0x0000;
  276. }
  277. //-----------------------------------------------------------------------------
  278. //
  279. // Accum - Called for each fragment. Fragments must be accumulated in front-
  280. // to-back order (sort is done prior to accumulation).
  281. //
  282. // Returns TRUE if full coverage has been achieved and thus subsequent
  283. // fragments will have no further contribution to the final pixel color and
  284. // opacity.
  285. //
  286. //-----------------------------------------------------------------------------
  287. BOOL
  288. FragResolveAccum::Accum(
  289. const CVGMASK CvgMask,
  290. const RRColor& ColorFrag)
  291. {
  292. DPFM(6, FRAG, (" FragResolveAccum: accum %04x %08x\n",
  293. CvgMask, UINT32(ColorFrag) ) )
  294. FLOAT fAlphaFrag = FLOAT(ColorFrag.A);
  295. // exit (don't accum) if all covered
  296. if (TL_CVGFULL == m_CvgOpaqueMask) { return TRUE; }
  297. // controls for doing (up to) 4 accumulations at a time
  298. INT32 iAccumsDeferred = 0; // the current number of deferred accumulations
  299. FLOAT fColorScaleAccum; // the accumulated color scale for the deferred accums
  300. // compute ArrayCheck - each set bit indicates a coverage mask
  301. // bit for which an accumulation needs to be done (indicated by
  302. // a valid entry in the coverage array which is not opaque and
  303. // for which the corresponding bit is set in this fragment's
  304. // coverage mask)
  305. CVGMASK ArrayCheck = 0x0;
  306. for (INT32 i=0; i<16; i++)
  307. {
  308. if (m_CvgArray[i].Mask & CvgMask)
  309. {
  310. ArrayCheck |= ((0x1 << i) & ~(m_CvgOpaqueMask));
  311. }
  312. }
  313. INT32 iIdx;
  314. CVGMASK ArrayMaskT = m_ArrayUsageMask;
  315. while (0x0 != ArrayMaskT)
  316. {
  317. // track from MSB to LSB of usage mask
  318. iIdx = FindLastSetBit(ArrayMaskT,TL_CVGBITS);
  319. ArrayMaskT &= ~(0x1 << iIdx);
  320. // compute masks for overlapped coverage (requiring
  321. // accumulation) and non-overlapped area (which may
  322. // require an updated coverage/alpha entry)
  323. CVGMASK AccumCvgMask = m_CvgArray[iIdx].Mask & CvgMask;
  324. CVGMASK UpdateCvgMask = m_CvgArray[iIdx].Mask & ~CvgMask;
  325. // remove bits in the overlapped coverage mask for subsamples
  326. // which already have opaque alphas
  327. AccumCvgMask &= ~(m_CvgOpaqueMask);
  328. // read alpha old here - the location that this is stored
  329. // may be changed in the accumulate step but needs to be
  330. // remembered for the update (non-covered area) step
  331. FLOAT fAlphaOld = m_CvgArray[iIdx].fAlpha;
  332. // compute alpha scale value - this is used to scale color
  333. // for accumulation and to compute updated alpha for overlap
  334. FLOAT fAlphaScale = fAlphaOld * fAlphaFrag;
  335. // new alpha for overlapped area (this cannot go negative
  336. // since 0 < AlphaScale < AlphaOld)
  337. // AlphaNext = AlphaOld(1 - Alpha) = AlphaOld - AlphaOld*Alpha =
  338. FLOAT fAlphaNext = fAlphaOld - fAlphaScale;
  339. if (0x0 != AccumCvgMask)
  340. {
  341. // contribution to accumulate - this is the portion
  342. // the previous mask starting at the uIdx bit location
  343. // which is covered by the new fragment, so accumulate
  344. // this coverage and update the mask and alpha
  345. UINT32 iIdxT = FindFirstSetBit(AccumCvgMask,TL_CVGBITS);
  346. m_ArrayUsageMask |= (0x1 << iIdxT);
  347. m_CvgArray[iIdxT].Mask = AccumCvgMask;
  348. // set the alpha of the overlapped area
  349. m_CvgArray[iIdxT].fAlpha = fAlphaNext;
  350. // compute scale for color channels - depends on if
  351. // we want pre-multiplied alphas or not...
  352. //
  353. // base for scale is either array value alone or product
  354. // of array value and Afrag (AlphaScale)
  355. FLOAT fColorScaleBase = (g_bPreMultAlpha) ? (fAlphaOld) : (fAlphaScale);
  356. // do either multiply or bypass for full coverage
  357. FLOAT fColorScale = fColorScaleBase;
  358. if ( TL_CVGFULL != AccumCvgMask )
  359. {
  360. FLOAT fCvgFraction =
  361. (FLOAT)(CountSetBits(AccumCvgMask, TL_CVGBITS)) * (1./TL_CVGBITS);
  362. fColorScale *= fCvgFraction;
  363. }
  364. // accumulate up to four accumulations to do at once - the accumulated
  365. // value is the color scale to be applied to the multiple locations
  366. // update color scale accum - either set (1st deferral) or
  367. // accumulate (subsequent deferrals)
  368. fColorScaleAccum = (0 == iAccumsDeferred) ?
  369. (fColorScale) : (fColorScale + fColorScaleAccum);
  370. // track number of deferrals and bypass accumulation if not
  371. // up to 4 (or if this is the last one)
  372. if ( (++iAccumsDeferred != 4) &&
  373. (0x0 != (ArrayMaskT & ArrayCheck)) )
  374. {
  375. goto _update_CvgMask_Location;
  376. }
  377. // start over on deferral
  378. iAccumsDeferred = 0;
  379. // clamp color scale to max before accumulation
  380. fColorScale = MIN( fColorScaleAccum, 1. );
  381. // do accumulation and write back to accumulator
  382. // decide what to use for alpha accumulate - if we are using
  383. // pre-multiplied alphas, then AFrag is not incorporated into
  384. // color scale, thus mult by AFrag
  385. FLOAT fAPartial = fColorScale * ( (g_bPreMultAlpha) ? (fAlphaFrag) : (1.) );
  386. FLOAT fRPartial = fColorScale * FLOAT(ColorFrag.R);
  387. FLOAT fGPartial = fColorScale * FLOAT(ColorFrag.G);
  388. FLOAT fBPartial = fColorScale * FLOAT(ColorFrag.B);
  389. m_fA += fAPartial;
  390. m_fR += fRPartial;
  391. m_fG += fGPartial;
  392. m_fB += fBPartial;
  393. }
  394. _update_CvgMask_Location:
  395. if (0x0 != UpdateCvgMask)
  396. {
  397. // mask to update - this is the portion of the
  398. // previous mask starting at the uIdx bit location
  399. // which is still visible, so update the coverage
  400. // (the alpha stays the same)
  401. UINT32 iIdxT = FindFirstSetBit(UpdateCvgMask,TL_CVGBITS);
  402. m_ArrayUsageMask |= (0x1 << iIdxT);
  403. m_CvgArray[iIdxT].Mask = UpdateCvgMask;
  404. m_CvgArray[iIdxT].fAlpha = fAlphaOld;
  405. }
  406. }
  407. // determine if this new fragment is has an opaque alpha
  408. // if so then update opaque mask - this must be done after
  409. // the accumulations because the opaque mask refers to the
  410. // current state of the coverage array and should apply only to
  411. // accumulations of subsequent fragments
  412. //
  413. // g_bDoCoverageOnly overrides this to always act as if fragments'
  414. // alphas are opaque for the purposes of generating antialiased
  415. // shadow attenuation surfaces
  416. {
  417. if ((fAlphaFrag >= 1.) || (g_bDoCoverageOnly))
  418. { m_CvgOpaqueMask |= CvgMask; }
  419. }
  420. // check opaque mask for return boolean - returns TRUE if we
  421. // are done
  422. return (TL_CVGFULL == m_CvgOpaqueMask) ? (TRUE) : (FALSE);
  423. }
  424. //-----------------------------------------------------------------------------
  425. //
  426. // GetColor - Called after accumulating a series of fragments to get the final
  427. // pixel color and alpha.
  428. //
  429. //-----------------------------------------------------------------------------
  430. void
  431. FragResolveAccum::GetColor( RRColor& Color )
  432. {
  433. // clamp and assign for return
  434. Color.A = (FLOAT)MIN( m_fA, 1. );
  435. Color.R = (FLOAT)MIN( m_fR, 1. );
  436. Color.G = (FLOAT)MIN( m_fG, 1. );
  437. Color.B = (FLOAT)MIN( m_fB, 1. );
  438. }
  439. ///////////////////////////////////////////////////////////////////////////////
  440. // end