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.

549 lines
19 KiB

  1. /*==========================================================================;
  2. *
  3. * Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: vwport.c
  6. * Content: Direct3D viewport functions
  7. *
  8. ***************************************************************************/
  9. #include "pch.cpp"
  10. #pragma hdrstop
  11. /*
  12. * Create an api for the Direct3DViewport object
  13. */
  14. #include "d3dfei.h"
  15. #include "drawprim.hpp"
  16. //---------------------------------------------------------------------
  17. // Update pre-computed constants related to viewport
  18. //
  19. // This functions should be called every time the viewport parameters are
  20. // changed
  21. //
  22. // Notes:
  23. // 1. scaleY and offsetY are computed to flip Y axes from up to down.
  24. // 2. Mclip matrix is computed multiplied by Mshift matrix
  25. //
  26. const D3DVALUE SMALL_NUMBER = 0.000001f;
  27. // Maximum number of clear rectangles considered legal.
  28. // This limit is set by NT kernel for Clear2 callback
  29. const DWORD MAX_CLEAR_RECTS = 0x1000;
  30. void
  31. UpdateViewportCache(LPDIRECT3DDEVICEI device, D3DVIEWPORT7 *data)
  32. {
  33. #if DBG
  34. // Bail if we are going to cause any divide by zero exceptions.
  35. // The likely reason is that we have a bogus viewport set by
  36. // TLVertex execute buffer app.
  37. if (data->dwWidth == 0 || data->dwHeight == 0)
  38. {
  39. D3D_ERR("Viewport width or height is zero");
  40. throw DDERR_INVALIDPARAMS;
  41. }
  42. if (data->dvMaxZ < 0 ||
  43. data->dvMinZ < 0 ||
  44. data->dvMaxZ > 1 ||
  45. data->dvMinZ > 1)
  46. {
  47. D3D_ERR("dvMaxZ and dvMinZ should be between 0 and 1");
  48. throw DDERR_INVALIDPARAMS;
  49. }
  50. if (data->dvMaxZ < data->dvMinZ)
  51. {
  52. D3D_ERR("dvMaxZ should not be smaller than dvMinZ");
  53. throw DDERR_INVALIDPARAMS;
  54. }
  55. #endif // DBG
  56. const D3DVALUE eps = 0.001f;
  57. if (data->dvMaxZ - data->dvMinZ < eps)
  58. {
  59. // When we clip, we transform vertices from the screen space to the
  60. // clipping space. With the above condition it is impossible. So we do
  61. // a little hack here by setting dvMinZ and dvMaxZ to different values
  62. if (data->dvMaxZ >= 0.5f)
  63. data->dvMinZ = data->dvMaxZ - eps;
  64. else
  65. data->dvMaxZ = data->dvMinZ + eps;
  66. }
  67. D3DFE_VIEWPORTCACHE *cache = &device->vcache;
  68. cache->dvX = D3DVAL(data->dwX);
  69. cache->dvY = D3DVAL(data->dwY);
  70. cache->dvWidth = D3DVAL(data->dwWidth);
  71. cache->dvHeight = D3DVAL(data->dwHeight);
  72. cache->scaleX = cache->dvWidth;
  73. cache->scaleY = - cache->dvHeight;
  74. cache->scaleZ = D3DVAL(data->dvMaxZ - data->dvMinZ);
  75. cache->offsetX = cache->dvX;
  76. cache->offsetY = cache->dvY + cache->dvHeight;
  77. cache->offsetZ = D3DVAL(data->dvMinZ);
  78. // Small offset is added to prevent generation of negative screen
  79. // coordinates (this could happen because of precision errors).
  80. cache->offsetX += SMALL_NUMBER;
  81. cache->offsetY += SMALL_NUMBER;
  82. cache->scaleXi = D3DVAL(1) / cache->scaleX;
  83. cache->scaleYi = D3DVAL(1) / cache->scaleY;
  84. cache->scaleZi = D3DVAL(1) / cache->scaleZ;
  85. cache->minX = cache->dvX;
  86. cache->maxX = cache->dvX + cache->dvWidth;
  87. cache->minY = cache->dvY;
  88. cache->maxY = cache->dvY + cache->dvHeight;
  89. cache->minXi = FTOI(cache->minX);
  90. cache->maxXi = FTOI(cache->maxX);
  91. cache->minYi = FTOI(cache->minY);
  92. cache->maxYi = FTOI(cache->maxY);
  93. if (device->dwDeviceFlags & D3DDEV_GUARDBAND)
  94. {
  95. LPD3DHAL_D3DEXTENDEDCAPS lpCaps = device->lpD3DExtendedCaps;
  96. // Because we clip by guard band window we have to use its extents
  97. cache->minXgb = lpCaps->dvGuardBandLeft;
  98. cache->maxXgb = lpCaps->dvGuardBandRight;
  99. cache->minYgb = lpCaps->dvGuardBandTop;
  100. cache->maxYgb = lpCaps->dvGuardBandBottom;
  101. D3DVALUE w = 2.0f / cache->dvWidth;
  102. D3DVALUE h = 2.0f / cache->dvHeight;
  103. D3DVALUE ax1 = -(lpCaps->dvGuardBandLeft - cache->dvX) * w + 1.0f;
  104. D3DVALUE ax2 = (lpCaps->dvGuardBandRight - cache->dvX) * w - 1.0f;
  105. D3DVALUE ay1 = (lpCaps->dvGuardBandBottom - cache->dvY) * h - 1.0f;
  106. D3DVALUE ay2 = -(lpCaps->dvGuardBandTop - cache->dvY) * h + 1.0f;
  107. cache->gb11 = 2.0f / (ax1 + ax2);
  108. cache->gb41 = cache->gb11 * (ax1 - 1.0f) * 0.5f;
  109. cache->gb22 = 2.0f / (ay1 + ay2);
  110. cache->gb42 = cache->gb22 * (ay1 - 1.0f) * 0.5f;
  111. cache->Kgbx1 = 0.5f * (1.0f - ax1);
  112. cache->Kgbx2 = 0.5f * (1.0f + ax2);
  113. cache->Kgby1 = 0.5f * (1.0f - ay1);
  114. cache->Kgby2 = 0.5f * (1.0f + ay2);
  115. }
  116. else
  117. {
  118. cache->minXgb = cache->minX;
  119. cache->maxXgb = cache->maxX;
  120. cache->minYgb = cache->minY;
  121. cache->maxYgb = cache->maxY;
  122. }
  123. }
  124. //---------------------------------------------------------------------
  125. DWORD
  126. ProcessRects(LPDIRECT3DDEVICEI pDevI, DWORD dwCount, LPD3DRECT rects)
  127. {
  128. RECT vwport;
  129. DWORD i,j;
  130. /*
  131. * Rip through the rects and validate that they
  132. * are within the viewport.
  133. */
  134. if(dwCount == 0 && rects == NULL)
  135. {
  136. dwCount = 1;
  137. }
  138. #if DBG
  139. else if(rects == NULL)
  140. {
  141. D3D_ERR("invalid clear rectangle parameter rects == NULL");
  142. throw DDERR_INVALIDPARAMS;
  143. }
  144. #endif
  145. if (dwCount > pDevI->clrCount) {
  146. if (D3DRealloc((void**)&pDevI->clrRects, dwCount * sizeof(D3DRECT)) != DD_OK)
  147. {
  148. pDevI->clrCount = 0;
  149. pDevI->clrRects = NULL;
  150. D3D_ERR("failed to allocate space for rects");
  151. throw DDERR_OUTOFMEMORY;
  152. }
  153. }
  154. pDevI->clrCount = dwCount;
  155. // If nothing is specified, assume the viewport needs to be cleared
  156. if (!rects)
  157. {
  158. pDevI->clrRects[0].x1 = pDevI->m_Viewport.dwX;
  159. pDevI->clrRects[0].y1 = pDevI->m_Viewport.dwY;
  160. pDevI->clrRects[0].x2 = pDevI->m_Viewport.dwX + pDevI->m_Viewport.dwWidth;
  161. pDevI->clrRects[0].y2 = pDevI->m_Viewport.dwY + pDevI->m_Viewport.dwHeight;
  162. return 1;
  163. }
  164. else
  165. {
  166. vwport.left = pDevI->m_Viewport.dwX;
  167. vwport.top = pDevI->m_Viewport.dwY;
  168. vwport.right = pDevI->m_Viewport.dwX + pDevI->m_Viewport.dwWidth;
  169. vwport.bottom = pDevI->m_Viewport.dwY + pDevI->m_Viewport.dwHeight;
  170. j=0;
  171. for (i = 0; i < dwCount; i++)
  172. {
  173. if (IntersectRect((LPRECT)(pDevI->clrRects + j), &vwport, (LPRECT)(rects + i)))
  174. j++;
  175. }
  176. return j;
  177. }
  178. }
  179. //---------------------------------------------------------------------
  180. #undef DPF_MODNAME
  181. #define DPF_MODNAME "DIRECT3DDEVICEI::SetViewportI"
  182. void DIRECT3DDEVICEI::SetViewportI(LPD3DVIEWPORT7 lpData)
  183. {
  184. // We have to check parameters here, because viewport could be changed
  185. // after creating a state set
  186. DWORD uSurfWidth,uSurfHeight;
  187. LPDIRECTDRAWSURFACE lpDDS = this->lpDDSTarget;
  188. uSurfWidth= ((LPDDRAWI_DDRAWSURFACE_INT) lpDDS)->lpLcl->lpGbl->wWidth;
  189. uSurfHeight= ((LPDDRAWI_DDRAWSURFACE_INT) lpDDS)->lpLcl->lpGbl->wHeight;
  190. if (lpData->dwX > uSurfWidth ||
  191. lpData->dwY > uSurfHeight ||
  192. lpData->dwX + lpData->dwWidth > uSurfWidth ||
  193. lpData->dwY + lpData->dwHeight > uSurfHeight)
  194. {
  195. D3D_ERR("Viewport outside the render target surface");
  196. throw DDERR_INVALIDPARAMS;
  197. }
  198. this->m_Viewport = *lpData;
  199. // Update front-end data
  200. UpdateViewportCache(this, &this->m_Viewport);
  201. if (!(this->dwFEFlags & D3DFE_EXECUTESTATEMODE))
  202. {
  203. // Download viewport data
  204. this->UpdateDrvViewInfo(&this->m_Viewport);
  205. }
  206. }
  207. //---------------------------------------------------------------------
  208. #undef DPF_MODNAME
  209. #define DPF_MODNAME "DIRECT3DDEVICEI::SetViewport"
  210. HRESULT D3DAPI DIRECT3DDEVICEI::SetViewport(LPD3DVIEWPORT7 lpData)
  211. {
  212. if (!VALID_D3DVIEWPORT_PTR(lpData))
  213. {
  214. D3D_ERR( "Invalid D3DVIEWPORT7 pointer" );
  215. return DDERR_INVALIDPARAMS;
  216. }
  217. try
  218. {
  219. CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
  220. if (this->dwFEFlags & D3DFE_RECORDSTATEMODE)
  221. m_pStateSets->InsertViewport(lpData);
  222. else
  223. SetViewportI(lpData);
  224. return D3D_OK;
  225. }
  226. catch(HRESULT ret)
  227. {
  228. return ret;
  229. }
  230. }
  231. //---------------------------------------------------------------------
  232. #undef DPF_MODNAME
  233. #define DPF_MODNAME "DIRECT3DDEVICEI::GetViewport"
  234. HRESULT
  235. D3DAPI DIRECT3DDEVICEI::GetViewport(LPD3DVIEWPORT7 lpData)
  236. {
  237. CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
  238. if (!VALID_D3DVIEWPORT_PTR(lpData))
  239. {
  240. D3D_ERR( "Invalid D3DVIEWPORT2 pointer" );
  241. return DDERR_INVALIDPARAMS;
  242. }
  243. *lpData = this->m_Viewport;
  244. return (D3D_OK);
  245. }
  246. //---------------------------------------------------------------------
  247. #undef DPF_MODNAME
  248. #define DPF_MODNAME "DIRECT3DDEVICEI::Clear"
  249. extern void BltFillRects(LPDIRECT3DDEVICEI, DWORD, LPD3DRECT, D3DCOLOR);
  250. extern void BltFillZRects(LPDIRECT3DDEVICEI, unsigned long,DWORD, LPD3DRECT, DWORD);
  251. #define bDoRGBClear ((dwFlags & D3DCLEAR_TARGET)!=0)
  252. #define bDoZClear ((dwFlags & D3DCLEAR_ZBUFFER)!=0)
  253. #define bDoStencilClear ((dwFlags & D3DCLEAR_STENCIL)!=0)
  254. HRESULT
  255. D3DAPI DIRECT3DDEVICEI::Clear(DWORD dwCount, LPD3DRECT rects, DWORD dwFlags,
  256. D3DCOLOR dwColor, D3DVALUE dvZ, DWORD dwStencil)
  257. {
  258. #if DBG
  259. if (IsBadWritePtr(rects, dwCount * sizeof(D3DRECT)))
  260. {
  261. D3D_ERR( "Invalid rects pointer" );
  262. return DDERR_INVALIDPARAMS;
  263. }
  264. #endif
  265. try
  266. {
  267. HRESULT err;
  268. LPDDPIXELFORMAT pZPixFmt=NULL;
  269. CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
  270. if (dwCount > MAX_CLEAR_RECTS)
  271. {
  272. D3D_ERR("Cannot support more than 64K rectangles");
  273. return DDERR_INVALIDPARAMS;
  274. }
  275. if (!(lpD3DHALGlobalDriverData->hwCaps.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR))
  276. {
  277. if (bDoStencilClear||bDoZClear)
  278. {
  279. if(lpDDSZBuffer==NULL)
  280. {
  281. // unlike Clear(), specifying a Zbuffer-clearing flag without a zbuffer will
  282. // be considered an error
  283. #if DBG
  284. if(bDoZClear)
  285. {
  286. D3D_ERR("Invalid flag D3DCLEAR_ZBUFFER: no zbuffer is associated with device");
  287. }
  288. if(bDoStencilClear)
  289. {
  290. D3D_ERR("Invalid flag D3DCLEAR_STENCIL: no zbuffer is associated with device");
  291. }
  292. #endif
  293. return D3DERR_ZBUFFER_NOTPRESENT;
  294. }
  295. pZPixFmt=&((LPDDRAWI_DDRAWSURFACE_INT) lpDDSZBuffer)->lpLcl->lpGbl->ddpfSurface;
  296. if(bDoStencilClear)
  297. {
  298. if(!(pZPixFmt->dwFlags & DDPF_STENCILBUFFER))
  299. {
  300. D3D_ERR("Invalid flag D3DCLEAR_STENCIL; current zbuffer's pixel format doesnt support stencil bits");
  301. return D3DERR_STENCILBUFFER_NOTPRESENT;
  302. }
  303. }
  304. }
  305. }
  306. if (!(dwFlags & (D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL)))
  307. {
  308. D3D_ERR("No valid flags passed to Clear");
  309. return DDERR_INVALIDPARAMS;
  310. }
  311. // bad clear values just cause wacky results but no crashes, so OK to allow in retail bld
  312. DDASSERT(!bDoZClear || ((dvZ>=0.0) && (dvZ<=1.0)));
  313. DDASSERT(!bDoStencilClear || !pZPixFmt || (dwStencil <= (DWORD)((1<<pZPixFmt->dwStencilBitDepth)-1)));
  314. dwCount = ProcessRects(this, dwCount, rects);
  315. // Call DDI specific Clear routine
  316. ClearI(dwFlags, dwCount, dwColor, dvZ, dwStencil);
  317. return D3D_OK;
  318. }
  319. catch(HRESULT ret)
  320. {
  321. return ret;
  322. }
  323. }
  324. void DIRECT3DDEVICEI::ClearI(DWORD dwFlags, DWORD clrCount, D3DCOLOR dwColor, D3DVALUE dvZ, DWORD dwStencil)
  325. {
  326. HRESULT err;
  327. // Flush any outstanding geometry to put framebuffer/Zbuffer in a known state for Clears that
  328. // don't use tris (i.e. HAL Clears and Blts). Note this doesn't work for tiled architectures
  329. // outside of Begin/EndScene, this will be fixed later
  330. if ((err = FlushStates()) != D3D_OK)
  331. {
  332. D3D_ERR("Error trying to render batched commands in D3DFE_Clear2");
  333. throw err;
  334. }
  335. if (lpD3DHALCallbacks3->Clear2)
  336. {
  337. // Clear2 HAL Callback exists
  338. D3DHAL_CLEAR2DATA Clear2Data;
  339. Clear2Data.dwhContext = dwhContext;
  340. Clear2Data.dwFlags = dwFlags;
  341. // Here I will follow the ClearData.dwFillColor convention that
  342. // color word is raw 32bit ARGB, unadjusted for surface bit depth
  343. Clear2Data.dwFillColor = dwColor;
  344. // depth/stencil values both passed straight from user args
  345. Clear2Data.dvFillDepth = dvZ;
  346. Clear2Data.dwFillStencil= dwStencil;
  347. Clear2Data.lpRects = clrRects;
  348. Clear2Data.dwNumRects = clrCount;
  349. Clear2Data.ddrval = D3D_OK;
  350. #ifndef WIN95
  351. if((err = CheckContextSurface(this)) != D3D_OK)
  352. {
  353. throw err;
  354. }
  355. #endif
  356. CALL_HAL3ONLY(err, this, Clear2, &Clear2Data);
  357. if (err != DDHAL_DRIVER_HANDLED)
  358. {
  359. throw DDERR_UNSUPPORTED;
  360. }
  361. else if (Clear2Data.ddrval != DD_OK)
  362. {
  363. throw Clear2Data.ddrval;
  364. }
  365. else
  366. return;
  367. }
  368. if (lpD3DHALGlobalDriverData->hwCaps.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR)
  369. {
  370. if (bDoStencilClear)
  371. {
  372. D3D_ERR("Invalid flag D3DCLEAR_STENCIL: this ZBUFFERLESSHSR device doesn't support Clear2()");
  373. throw D3DERR_ZBUFFER_NOTPRESENT;
  374. }
  375. if (bDoZClear)
  376. {
  377. if (!(lpD3DHALCallbacks2->Clear) || (dvZ!=1.0))
  378. {
  379. D3D_WARN(3,"Ignoring D3DCLEAR_ZBUFFER since this ZBUFFERLESSHSR device doesn't even support Clear() or Z!=1");
  380. dwFlags &= ~(D3DCLEAR_ZBUFFER);
  381. }
  382. }
  383. }
  384. LPDDPIXELFORMAT pZPixFmt;
  385. if (NULL != lpDDSZBuffer)
  386. {
  387. pZPixFmt = &((LPDDRAWI_DDRAWSURFACE_INT) lpDDSZBuffer)->lpLcl->lpGbl->ddpfSurface;
  388. }
  389. else
  390. {
  391. pZPixFmt = NULL;
  392. }
  393. if (lpD3DHALCallbacks2->Clear)
  394. {
  395. if(bDoZClear || bDoStencilClear)
  396. {
  397. if((pZPixFmt!=NULL) && //PowerVR need no Zbuffer
  398. (DDPF_STENCILBUFFER & pZPixFmt->dwFlags)
  399. )
  400. {
  401. // if surface has stencil bits, must verify either Clear2 callback exists or
  402. // we're using SW rasterizers (which require the special WriteMask DDHEL blt)
  403. // This case should not be hit since we check right at the
  404. // driver initialization time if the driver doesnt report Clear2
  405. // yet it supports stencils
  406. if(((LPDDRAWI_DDRAWSURFACE_INT)lpDDSZBuffer)->lpLcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
  407. {
  408. goto Emulateclear;
  409. }
  410. else
  411. {
  412. D3D_ERR("Driver HAL doesn't provide Clear2 callback, cannot use Clear2 with HW stencil surfaces");
  413. throw DDERR_INVALIDPIXELFORMAT;
  414. }
  415. }
  416. // if Clear2 callback doesnt exist and it's a z-only surface and not doing zclear to
  417. // non-max value then Clear2 is attempting to do no more than Clear could do, so it's
  418. // safe to call Clear() instead of Clear2(), which will take advantage of older
  419. // drivers that implement Clear but not Clear2
  420. dwFlags &= ~D3DCLEAR_STENCIL; // Device cannot do stencil
  421. }
  422. D3DHAL_CLEARDATA ClearData;
  423. if (bDoZClear && dvZ != 1.0)
  424. {
  425. ClearData.dwFlags = dwFlags & ~D3DCLEAR_ZBUFFER;
  426. dwFlags = D3DCLEAR_ZBUFFER;
  427. }
  428. else
  429. {
  430. ClearData.dwFlags = dwFlags;
  431. dwFlags = 0;
  432. }
  433. if (ClearData.dwFlags)
  434. {
  435. ClearData.dwhContext = dwhContext;
  436. // Here I will follow the ClearData.dwFillColor convention that
  437. // color word is raw 32bit ARGB, unadjusted for surface bit depth
  438. ClearData.dwFillColor = dwColor;
  439. // must clear to 0xffffffff because legacy drivers expect this
  440. ClearData.dwFillDepth = 0xffffffff;
  441. ClearData.lpRects = clrRects;
  442. ClearData.dwNumRects = clrCount;
  443. ClearData.ddrval = D3D_OK;
  444. #ifndef WIN95
  445. if((err = CheckContextSurface(this)) != D3D_OK)
  446. {
  447. throw err;
  448. }
  449. #endif
  450. CALL_HAL2ONLY(err, this, Clear, &ClearData);
  451. if (err != DDHAL_DRIVER_HANDLED)
  452. {
  453. throw DDERR_UNSUPPORTED;
  454. }
  455. }
  456. }
  457. Emulateclear:
  458. // Fall back to Emulation using Blt
  459. if(bDoRGBClear)
  460. {
  461. BltFillRects(this, clrCount, clrRects, dwColor);
  462. //ok to not return possible errors from Blt?
  463. }
  464. if ((bDoZClear || bDoStencilClear) && NULL != pZPixFmt)
  465. {
  466. DWORD dwZbufferClearValue=0;
  467. DWORD dwZbufferClearMask=0;
  468. DDASSERT(pZPixFmt->dwZBufferBitDepth<=32);
  469. DDASSERT(pZPixFmt->dwStencilBitDepth<32);
  470. DDASSERT(pZPixFmt->dwZBitMask!=0x0);
  471. DDASSERT((0xFFFFFFFF == (pZPixFmt->dwZBitMask | pZPixFmt->dwStencilBitMask)) |
  472. ((DWORD)((1<<pZPixFmt->dwZBufferBitDepth)-1) == (pZPixFmt->dwZBitMask | pZPixFmt->dwStencilBitMask)));
  473. DDASSERT(0==(pZPixFmt->dwZBitMask & pZPixFmt->dwStencilBitMask));
  474. if(bDoZClear)
  475. {
  476. dwZbufferClearMask = pZPixFmt->dwZBitMask;
  477. // special case the common cases
  478. if(dvZ==1.0)
  479. {
  480. dwZbufferClearValue=pZPixFmt->dwZBitMask;
  481. }
  482. else if(dvZ > 0.0)
  483. {
  484. dwZbufferClearValue=((DWORD)((dvZ*(pZPixFmt->dwZBitMask >> zmask_shift))+0.5)) << zmask_shift;
  485. }
  486. }
  487. if(bDoStencilClear)
  488. {
  489. DDASSERT(pZPixFmt->dwStencilBitMask!=0x0);
  490. DDASSERT(pZPixFmt->dwFlags & DDPF_STENCILBUFFER);
  491. dwZbufferClearMask |= pZPixFmt->dwStencilBitMask;
  492. // special case the common case
  493. if(dwStencil!=0)
  494. {
  495. dwZbufferClearValue |=(dwStencil << stencilmask_shift) & pZPixFmt->dwStencilBitMask;
  496. }
  497. }
  498. if (dwZbufferClearMask == (pZPixFmt->dwStencilBitMask | pZPixFmt->dwZBitMask))
  499. {
  500. // do Stencil & Z Blt together, using regular DepthFill blt which will be faster
  501. // than the writemask blt because its write-only, instead of read-modify-write
  502. dwZbufferClearMask = 0;
  503. }
  504. BltFillZRects(this, dwZbufferClearValue, clrCount, clrRects, dwZbufferClearMask);
  505. }
  506. }