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.

257 lines
10 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (C) Microsoft Corporation, 1998.
  3. //
  4. // fragproc.cpp
  5. //
  6. // Direct3D Reference Rasterizer - Fragment Processing Methods
  7. //
  8. ///////////////////////////////////////////////////////////////////////////////
  9. #include "pch.cpp"
  10. #pragma hdrstop
  11. //
  12. // Fragments are managed by a separate 'surface' of fragment pointers which
  13. // form an (initially empty) linked list of fragment structures for each pixel.
  14. //
  15. // The fragment management consists of generating fragments for partially
  16. // covered pixels (either due to coverage mask or non-opaque alpha), and
  17. // freeing fragments which are obscurred by a fully covered pixel in
  18. // front of them.
  19. //
  20. // The fragment generation occurs when a new pixel is partially covered.
  21. // If the pixel location already has at least one fragment, then a fragment
  22. // merge is attempted. This merge is attempted with the fragment most recently
  23. // added to the pixel (at the front of the linked list), which has the best
  24. // chance of merging since it is most likely to be from the same object.
  25. // The merge tests the Z and color values, and if they are within a threshold
  26. // then the new fragmented pixel's contribution is OR'd into the existing
  27. // fragment instead of generating a new fragment. The depth merge criteria is
  28. // an absolute value compare. The color merge criteria is done with a bitmask
  29. // (because ripping apart the color into channels for the value compare is too
  30. // expensive). Set bits in bitmask FRAGMERGE_COLORDIFF_MASK are bits for which
  31. // the two colors must match. This actually works pretty well...
  32. //
  33. // If the merge fails, then a new fragment is allocated, filled out, and added
  34. // to the linked list for this pixel location.
  35. //
  36. // If the merge results in a fully covered pixel, then the fragment is freed
  37. // and the fragment's color and depth are written to the color/depth buffers.
  38. //
  39. //
  40. // controls for fragment merging
  41. //
  42. // TODO - not sure that merge works correctly right now...
  43. //#define DO_FRAGMERGE
  44. // mask for crude (but fast) color differencing - this is not so fast now
  45. // that colors are stored as floats...
  46. #define FRAGMERGE_COLORDIFF_MASK 0xe0c0e0c0
  47. // depth difference must be less than this for merge to occur
  48. FLOAT g_fFragMergeDepthThreshold = 1.F/(FLOAT)(1<<16);
  49. //-----------------------------------------------------------------------------
  50. //
  51. // DoFragmentGenerationProcessing - Does initial work of generating a fragment
  52. // buffer entry (if appropriate) and filling it out. Also attempts fragment
  53. // merge.
  54. //
  55. // Returns TRUE if processing for this pixel is complete.
  56. //
  57. //-----------------------------------------------------------------------------
  58. BOOL
  59. ReferenceRasterizer::DoFragmentGenerationProcessing( RRPixel& Pixel )
  60. {
  61. // TRUE if pixel is geometrically partially covered
  62. BOOL bDoFragCvg = ( TL_CVGFULL != Pixel.CvgMask );
  63. // TRUE if pixel is partially covered due to transparency
  64. BOOL bDoFragTransp = FALSE;
  65. if ( m_dwRenderState[D3DRENDERSTATE_TRANSLUCENTSORTINDEPENDENT] )
  66. {
  67. // only generate fragments for transparency if
  68. // D3DRENDERSTATE_TRANSLUCENTSORTINDEPENDENT is enabled and the
  69. // alpha is less than the threshold
  70. bDoFragTransp = ( UINT8(Pixel.Color.A) < g_uTransparencyAlphaThreshold );
  71. }
  72. else
  73. {
  74. // so we won't use alpha for determining transparency in fragment resolve
  75. Pixel.Color.A = 1.0F;
  76. }
  77. // get pointer to fragment list for this pixel location - may be NULL due to
  78. // deferred allocation of fragment buffer
  79. RRFRAGMENT** ppFrag = (NULL == m_ppFragBuf) ? (NULL)
  80. : (m_ppFragBuf + (m_pRenderTarget->m_iWidth*Pixel.iY) + Pixel.iX);
  81. if ( bDoFragCvg || bDoFragTransp )
  82. {
  83. // get pointer to pointer to first fragment in linked list for this pixel
  84. if (NULL == m_ppFragBuf)
  85. {
  86. // do (deferred) allocation of fragment pointer buffer - clear this
  87. // initially and it will always be cleared during the fragment resolve process
  88. size_t cbBuf = sizeof(RRFRAGMENT*)*m_pRenderTarget->m_iWidth*m_pRenderTarget->m_iHeight;
  89. // allocate fragment pointer buffer for rendering core - clear initially
  90. m_ppFragBuf = (RRFRAGMENT**)MEMALLOC( cbBuf );
  91. _ASSERTa( NULL != m_ppFragBuf, "malloc failure on RRFRAGMENT pointer buffer",
  92. return FALSE; );
  93. memset( m_ppFragBuf, 0x0, cbBuf );
  94. // ppFrag only not set if (NULL == m_ppFragBuf)
  95. ppFrag = (m_ppFragBuf + (m_pRenderTarget->m_iWidth*Pixel.iY) + Pixel.iX);
  96. }
  97. #ifdef DO_FRAGMERGE
  98. // try to do fragment merge
  99. if ( NULL != (*ppFrag) )
  100. {
  101. // check if new depth is close enough to depth of first frag in list
  102. FLOAT fDepthDiff = fabs( FLOAT((*ppFrag)->Depth) - FLOAT(Pixel.Depth) );
  103. BOOL bDepthClose = ( fDepthDiff < g_fFragMergeDepthThreshold );
  104. // check if new color is close enough to color of first frag in list
  105. UINT32 uARGBSame = ~( UINT32(Pixel.Color) ^ UINT32((*ppFrag)->Color) );
  106. BOOL bColorClose = ( FRAGMERGE_COLORDIFF_MASK == ( uARGBSame & FRAGMERGE_COLORDIFF_MASK ) );
  107. if ( bDepthClose && bColorClose )
  108. {
  109. m_pStt->cFragsMerged++;
  110. // here to do merge
  111. CVGMASK FirstFragCvgMask = (*ppFrag)->CvgMask;
  112. CVGMASK MergedCvgMask = FirstFragCvgMask | Pixel.CvgMask;
  113. // check for merge to full coverage
  114. if ( ( TL_CVGFULL == MergedCvgMask ) && !bDoFragTransp )
  115. {
  116. m_pStt->cFragsMergedToFull++;
  117. // free first fragment
  118. RRFRAGMENT* pFragFree = (*ppFrag); // keep ptr to frag to free
  119. (*ppFrag) = (RRFRAGMENT*)(*ppFrag)->pNext; // set buffer to point to next
  120. FragFree( pFragFree);
  121. // now need to write this pixel into pixel buffer, so return
  122. // FALSE so pixel processing will continue
  123. return FALSE;
  124. }
  125. else
  126. {
  127. // mask not full, so update first frag's cm and done
  128. (*ppFrag)->CvgMask = MergedCvgMask;
  129. // done with this pixel
  130. return TRUE;
  131. }
  132. }
  133. // else fall into allocating new frag
  134. }
  135. #endif
  136. // allocate and fill fragment
  137. RRFRAGMENT* pFragNew = FragAlloc();
  138. if ( NULL == pFragNew ) { return FALSE; }
  139. pFragNew->Color = Pixel.Color;
  140. pFragNew->Depth = Pixel.Depth;
  141. pFragNew->CvgMask = Pixel.CvgMask;
  142. // insert at front of list (before fragment we're looking at)
  143. pFragNew->pNext = (void*)(*ppFrag);
  144. (*ppFrag) = pFragNew;
  145. // done with this pixel
  146. return TRUE;
  147. }
  148. // not done with this pixel
  149. return FALSE;
  150. }
  151. //-----------------------------------------------------------------------------
  152. //
  153. // DoFragmentBufferFixup - Routine to free fragments which are behind
  154. // fully covered sample just written into the pixel buffer. This minimizes
  155. // the total number of fragment needed for a scene. This step involves walking
  156. // the linked list and freeing fragments behind the pixel about to be written.
  157. // This also simplifies the fragment resolve since the Z buffer is not needed
  158. // (all fragments are known to be in front of the fully-covered sample in the
  159. // color/Z buffer).
  160. //
  161. //-----------------------------------------------------------------------------
  162. void
  163. ReferenceRasterizer::DoFragmentBufferFixup( const RRPixel& Pixel )
  164. {
  165. // get pointer to fragment list for this pixel location - may be NULL due to
  166. // deferred allocation of fragment buffer
  167. RRFRAGMENT** ppFrag = (NULL == m_ppFragBuf)
  168. ? (NULL)
  169. : (m_ppFragBuf + (m_pRenderTarget->m_iWidth*Pixel.iY) + Pixel.iX);
  170. //
  171. // walk fragment array to free fragments behind covered sample
  172. //
  173. if ( NULL != ppFrag )
  174. {
  175. while ( NULL != (*ppFrag) )
  176. {
  177. if ( DepthCloser( Pixel.Depth, (*ppFrag)->Depth ) )
  178. {
  179. // covered sample is closer than fragment, so free the frag
  180. RRFRAGMENT* pFragFree = (*ppFrag); // keep ptr to frag to free
  181. (*ppFrag) = (RRFRAGMENT*)(*ppFrag)->pNext; // remove from list
  182. // ppFrag now points to a pointer to the next frag
  183. FragFree( pFragFree );
  184. }
  185. else
  186. {
  187. // advance pointer to point to pointer to next frag
  188. ppFrag = (RRFRAGMENT **)&((*ppFrag)->pNext);
  189. }
  190. }
  191. }
  192. }
  193. ///////////////////////////////////////////////////////////////////////////////
  194. // //
  195. // Fragment Allocation Methods //
  196. // //
  197. ///////////////////////////////////////////////////////////////////////////////
  198. //
  199. // These methods are used by the pixel engine and fragment resolver to
  200. // allocate and free fragments.
  201. //
  202. //-----------------------------------------------------------------------------
  203. //
  204. // Allocates a single fragment record, returning pointer
  205. //
  206. //-----------------------------------------------------------------------------
  207. RRFRAGMENT*
  208. ReferenceRasterizer::FragAlloc( void )
  209. {
  210. RRFRAGMENT* pFrag = (RRFRAGMENT*)MEMALLOC( sizeof(RRFRAGMENT) );
  211. _ASSERTa( NULL != pFrag, "malloc failed on RRFRAGMENT", return NULL; );
  212. // update stats
  213. m_pStt->cFragsAllocd++;
  214. if (m_pStt->cFragsAllocd > m_pStt->cMaxFragsAllocd ) { m_pStt->cMaxFragsAllocd = m_pStt->cFragsAllocd; }
  215. return pFrag;
  216. }
  217. //-----------------------------------------------------------------------------
  218. //
  219. // Frees a single fragment record
  220. //
  221. //-----------------------------------------------------------------------------
  222. void
  223. ReferenceRasterizer::FragFree( RRFRAGMENT* pFrag )
  224. {
  225. MEMFREE( pFrag );
  226. // update stats
  227. m_pStt->cFragsAllocd--;
  228. }
  229. ///////////////////////////////////////////////////////////////////////////////
  230. // end