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.
550 lines
19 KiB
550 lines
19 KiB
/*==========================================================================;
|
|
*
|
|
* Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: vwport.c
|
|
* Content: Direct3D viewport functions
|
|
*
|
|
***************************************************************************/
|
|
|
|
#include "pch.cpp"
|
|
#pragma hdrstop
|
|
|
|
/*
|
|
* Create an api for the Direct3DViewport object
|
|
*/
|
|
|
|
#include "d3dfei.h"
|
|
#include "drawprim.hpp"
|
|
|
|
//---------------------------------------------------------------------
|
|
// Update pre-computed constants related to viewport
|
|
//
|
|
// This functions should be called every time the viewport parameters are
|
|
// changed
|
|
//
|
|
// Notes:
|
|
// 1. scaleY and offsetY are computed to flip Y axes from up to down.
|
|
// 2. Mclip matrix is computed multiplied by Mshift matrix
|
|
//
|
|
const D3DVALUE SMALL_NUMBER = 0.000001f;
|
|
// Maximum number of clear rectangles considered legal.
|
|
// This limit is set by NT kernel for Clear2 callback
|
|
const DWORD MAX_CLEAR_RECTS = 0x1000;
|
|
|
|
void
|
|
UpdateViewportCache(LPDIRECT3DDEVICEI device, D3DVIEWPORT7 *data)
|
|
{
|
|
#if DBG
|
|
// Bail if we are going to cause any divide by zero exceptions.
|
|
// The likely reason is that we have a bogus viewport set by
|
|
// TLVertex execute buffer app.
|
|
if (data->dwWidth == 0 || data->dwHeight == 0)
|
|
{
|
|
D3D_ERR("Viewport width or height is zero");
|
|
throw DDERR_INVALIDPARAMS;
|
|
}
|
|
if (data->dvMaxZ < 0 ||
|
|
data->dvMinZ < 0 ||
|
|
data->dvMaxZ > 1 ||
|
|
data->dvMinZ > 1)
|
|
{
|
|
D3D_ERR("dvMaxZ and dvMinZ should be between 0 and 1");
|
|
throw DDERR_INVALIDPARAMS;
|
|
}
|
|
if (data->dvMaxZ < data->dvMinZ)
|
|
{
|
|
D3D_ERR("dvMaxZ should not be smaller than dvMinZ");
|
|
throw DDERR_INVALIDPARAMS;
|
|
}
|
|
#endif // DBG
|
|
const D3DVALUE eps = 0.001f;
|
|
if (data->dvMaxZ - data->dvMinZ < eps)
|
|
{
|
|
// When we clip, we transform vertices from the screen space to the
|
|
// clipping space. With the above condition it is impossible. So we do
|
|
// a little hack here by setting dvMinZ and dvMaxZ to different values
|
|
if (data->dvMaxZ >= 0.5f)
|
|
data->dvMinZ = data->dvMaxZ - eps;
|
|
else
|
|
data->dvMaxZ = data->dvMinZ + eps;
|
|
}
|
|
D3DFE_VIEWPORTCACHE *cache = &device->vcache;
|
|
cache->dvX = D3DVAL(data->dwX);
|
|
cache->dvY = D3DVAL(data->dwY);
|
|
cache->dvWidth = D3DVAL(data->dwWidth);
|
|
cache->dvHeight = D3DVAL(data->dwHeight);
|
|
|
|
cache->scaleX = cache->dvWidth;
|
|
cache->scaleY = - cache->dvHeight;
|
|
cache->scaleZ = D3DVAL(data->dvMaxZ - data->dvMinZ);
|
|
cache->offsetX = cache->dvX;
|
|
cache->offsetY = cache->dvY + cache->dvHeight;
|
|
cache->offsetZ = D3DVAL(data->dvMinZ);
|
|
// Small offset is added to prevent generation of negative screen
|
|
// coordinates (this could happen because of precision errors).
|
|
cache->offsetX += SMALL_NUMBER;
|
|
cache->offsetY += SMALL_NUMBER;
|
|
|
|
cache->scaleXi = D3DVAL(1) / cache->scaleX;
|
|
cache->scaleYi = D3DVAL(1) / cache->scaleY;
|
|
cache->scaleZi = D3DVAL(1) / cache->scaleZ;
|
|
cache->minX = cache->dvX;
|
|
cache->maxX = cache->dvX + cache->dvWidth;
|
|
cache->minY = cache->dvY;
|
|
cache->maxY = cache->dvY + cache->dvHeight;
|
|
cache->minXi = FTOI(cache->minX);
|
|
cache->maxXi = FTOI(cache->maxX);
|
|
cache->minYi = FTOI(cache->minY);
|
|
cache->maxYi = FTOI(cache->maxY);
|
|
if (device->dwDeviceFlags & D3DDEV_GUARDBAND)
|
|
{
|
|
LPD3DHAL_D3DEXTENDEDCAPS lpCaps = device->lpD3DExtendedCaps;
|
|
|
|
// Because we clip by guard band window we have to use its extents
|
|
cache->minXgb = lpCaps->dvGuardBandLeft;
|
|
cache->maxXgb = lpCaps->dvGuardBandRight;
|
|
cache->minYgb = lpCaps->dvGuardBandTop;
|
|
cache->maxYgb = lpCaps->dvGuardBandBottom;
|
|
|
|
D3DVALUE w = 2.0f / cache->dvWidth;
|
|
D3DVALUE h = 2.0f / cache->dvHeight;
|
|
D3DVALUE ax1 = -(lpCaps->dvGuardBandLeft - cache->dvX) * w + 1.0f;
|
|
D3DVALUE ax2 = (lpCaps->dvGuardBandRight - cache->dvX) * w - 1.0f;
|
|
D3DVALUE ay1 = (lpCaps->dvGuardBandBottom - cache->dvY) * h - 1.0f;
|
|
D3DVALUE ay2 = -(lpCaps->dvGuardBandTop - cache->dvY) * h + 1.0f;
|
|
cache->gb11 = 2.0f / (ax1 + ax2);
|
|
cache->gb41 = cache->gb11 * (ax1 - 1.0f) * 0.5f;
|
|
cache->gb22 = 2.0f / (ay1 + ay2);
|
|
cache->gb42 = cache->gb22 * (ay1 - 1.0f) * 0.5f;
|
|
|
|
cache->Kgbx1 = 0.5f * (1.0f - ax1);
|
|
cache->Kgbx2 = 0.5f * (1.0f + ax2);
|
|
cache->Kgby1 = 0.5f * (1.0f - ay1);
|
|
cache->Kgby2 = 0.5f * (1.0f + ay2);
|
|
}
|
|
else
|
|
{
|
|
cache->minXgb = cache->minX;
|
|
cache->maxXgb = cache->maxX;
|
|
cache->minYgb = cache->minY;
|
|
cache->maxYgb = cache->maxY;
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------
|
|
DWORD
|
|
ProcessRects(LPDIRECT3DDEVICEI pDevI, DWORD dwCount, LPD3DRECT rects)
|
|
{
|
|
RECT vwport;
|
|
DWORD i,j;
|
|
|
|
/*
|
|
* Rip through the rects and validate that they
|
|
* are within the viewport.
|
|
*/
|
|
|
|
if(dwCount == 0 && rects == NULL)
|
|
{
|
|
dwCount = 1;
|
|
}
|
|
#if DBG
|
|
else if(rects == NULL)
|
|
{
|
|
D3D_ERR("invalid clear rectangle parameter rects == NULL");
|
|
throw DDERR_INVALIDPARAMS;
|
|
}
|
|
#endif
|
|
|
|
if (dwCount > pDevI->clrCount) {
|
|
if (D3DRealloc((void**)&pDevI->clrRects, dwCount * sizeof(D3DRECT)) != DD_OK)
|
|
{
|
|
pDevI->clrCount = 0;
|
|
pDevI->clrRects = NULL;
|
|
D3D_ERR("failed to allocate space for rects");
|
|
throw DDERR_OUTOFMEMORY;
|
|
}
|
|
}
|
|
pDevI->clrCount = dwCount;
|
|
|
|
// If nothing is specified, assume the viewport needs to be cleared
|
|
if (!rects)
|
|
{
|
|
pDevI->clrRects[0].x1 = pDevI->m_Viewport.dwX;
|
|
pDevI->clrRects[0].y1 = pDevI->m_Viewport.dwY;
|
|
pDevI->clrRects[0].x2 = pDevI->m_Viewport.dwX + pDevI->m_Viewport.dwWidth;
|
|
pDevI->clrRects[0].y2 = pDevI->m_Viewport.dwY + pDevI->m_Viewport.dwHeight;
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
vwport.left = pDevI->m_Viewport.dwX;
|
|
vwport.top = pDevI->m_Viewport.dwY;
|
|
vwport.right = pDevI->m_Viewport.dwX + pDevI->m_Viewport.dwWidth;
|
|
vwport.bottom = pDevI->m_Viewport.dwY + pDevI->m_Viewport.dwHeight;
|
|
|
|
j=0;
|
|
for (i = 0; i < dwCount; i++)
|
|
{
|
|
if (IntersectRect((LPRECT)(pDevI->clrRects + j), &vwport, (LPRECT)(rects + i)))
|
|
j++;
|
|
}
|
|
return j;
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DIRECT3DDEVICEI::SetViewportI"
|
|
|
|
void DIRECT3DDEVICEI::SetViewportI(LPD3DVIEWPORT7 lpData)
|
|
{
|
|
// We have to check parameters here, because viewport could be changed
|
|
// after creating a state set
|
|
DWORD uSurfWidth,uSurfHeight;
|
|
LPDIRECTDRAWSURFACE lpDDS = this->lpDDSTarget;
|
|
|
|
uSurfWidth= ((LPDDRAWI_DDRAWSURFACE_INT) lpDDS)->lpLcl->lpGbl->wWidth;
|
|
uSurfHeight= ((LPDDRAWI_DDRAWSURFACE_INT) lpDDS)->lpLcl->lpGbl->wHeight;
|
|
|
|
if (lpData->dwX > uSurfWidth ||
|
|
lpData->dwY > uSurfHeight ||
|
|
lpData->dwX + lpData->dwWidth > uSurfWidth ||
|
|
lpData->dwY + lpData->dwHeight > uSurfHeight)
|
|
{
|
|
D3D_ERR("Viewport outside the render target surface");
|
|
throw DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
this->m_Viewport = *lpData;
|
|
|
|
// Update front-end data
|
|
UpdateViewportCache(this, &this->m_Viewport);
|
|
|
|
if (!(this->dwFEFlags & D3DFE_EXECUTESTATEMODE))
|
|
{
|
|
// Download viewport data
|
|
this->UpdateDrvViewInfo(&this->m_Viewport);
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DIRECT3DDEVICEI::SetViewport"
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::SetViewport(LPD3DVIEWPORT7 lpData)
|
|
{
|
|
if (!VALID_D3DVIEWPORT_PTR(lpData))
|
|
{
|
|
D3D_ERR( "Invalid D3DVIEWPORT7 pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
try
|
|
{
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
|
|
if (this->dwFEFlags & D3DFE_RECORDSTATEMODE)
|
|
m_pStateSets->InsertViewport(lpData);
|
|
else
|
|
SetViewportI(lpData);
|
|
return D3D_OK;
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DIRECT3DDEVICEI::GetViewport"
|
|
|
|
HRESULT
|
|
D3DAPI DIRECT3DDEVICEI::GetViewport(LPD3DVIEWPORT7 lpData)
|
|
{
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
|
|
if (!VALID_D3DVIEWPORT_PTR(lpData))
|
|
{
|
|
D3D_ERR( "Invalid D3DVIEWPORT2 pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
*lpData = this->m_Viewport;
|
|
|
|
return (D3D_OK);
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DIRECT3DDEVICEI::Clear"
|
|
extern void BltFillRects(LPDIRECT3DDEVICEI, DWORD, LPD3DRECT, D3DCOLOR);
|
|
extern void BltFillZRects(LPDIRECT3DDEVICEI, unsigned long,DWORD, LPD3DRECT, DWORD);
|
|
|
|
#define bDoRGBClear ((dwFlags & D3DCLEAR_TARGET)!=0)
|
|
#define bDoZClear ((dwFlags & D3DCLEAR_ZBUFFER)!=0)
|
|
#define bDoStencilClear ((dwFlags & D3DCLEAR_STENCIL)!=0)
|
|
|
|
|
|
HRESULT
|
|
D3DAPI DIRECT3DDEVICEI::Clear(DWORD dwCount, LPD3DRECT rects, DWORD dwFlags,
|
|
D3DCOLOR dwColor, D3DVALUE dvZ, DWORD dwStencil)
|
|
{
|
|
#if DBG
|
|
if (IsBadWritePtr(rects, dwCount * sizeof(D3DRECT)))
|
|
{
|
|
D3D_ERR( "Invalid rects pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
#endif
|
|
try
|
|
{
|
|
HRESULT err;
|
|
LPDDPIXELFORMAT pZPixFmt=NULL;
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
|
|
if (dwCount > MAX_CLEAR_RECTS)
|
|
{
|
|
D3D_ERR("Cannot support more than 64K rectangles");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (!(lpD3DHALGlobalDriverData->hwCaps.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR))
|
|
{
|
|
if (bDoStencilClear||bDoZClear)
|
|
{
|
|
if(lpDDSZBuffer==NULL)
|
|
{
|
|
// unlike Clear(), specifying a Zbuffer-clearing flag without a zbuffer will
|
|
// be considered an error
|
|
#if DBG
|
|
if(bDoZClear)
|
|
{
|
|
D3D_ERR("Invalid flag D3DCLEAR_ZBUFFER: no zbuffer is associated with device");
|
|
}
|
|
if(bDoStencilClear)
|
|
{
|
|
D3D_ERR("Invalid flag D3DCLEAR_STENCIL: no zbuffer is associated with device");
|
|
}
|
|
#endif
|
|
return D3DERR_ZBUFFER_NOTPRESENT;
|
|
}
|
|
pZPixFmt=&((LPDDRAWI_DDRAWSURFACE_INT) lpDDSZBuffer)->lpLcl->lpGbl->ddpfSurface;
|
|
if(bDoStencilClear)
|
|
{
|
|
if(!(pZPixFmt->dwFlags & DDPF_STENCILBUFFER))
|
|
{
|
|
D3D_ERR("Invalid flag D3DCLEAR_STENCIL; current zbuffer's pixel format doesnt support stencil bits");
|
|
return D3DERR_STENCILBUFFER_NOTPRESENT;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!(dwFlags & (D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL)))
|
|
{
|
|
D3D_ERR("No valid flags passed to Clear");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
// bad clear values just cause wacky results but no crashes, so OK to allow in retail bld
|
|
|
|
DDASSERT(!bDoZClear || ((dvZ>=0.0) && (dvZ<=1.0)));
|
|
DDASSERT(!bDoStencilClear || !pZPixFmt || (dwStencil <= (DWORD)((1<<pZPixFmt->dwStencilBitDepth)-1)));
|
|
|
|
dwCount = ProcessRects(this, dwCount, rects);
|
|
|
|
// Call DDI specific Clear routine
|
|
ClearI(dwFlags, dwCount, dwColor, dvZ, dwStencil);
|
|
return D3D_OK;
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
void DIRECT3DDEVICEI::ClearI(DWORD dwFlags, DWORD clrCount, D3DCOLOR dwColor, D3DVALUE dvZ, DWORD dwStencil)
|
|
{
|
|
HRESULT err;
|
|
// Flush any outstanding geometry to put framebuffer/Zbuffer in a known state for Clears that
|
|
// don't use tris (i.e. HAL Clears and Blts). Note this doesn't work for tiled architectures
|
|
// outside of Begin/EndScene, this will be fixed later
|
|
|
|
|
|
if ((err = FlushStates()) != D3D_OK)
|
|
{
|
|
D3D_ERR("Error trying to render batched commands in D3DFE_Clear2");
|
|
throw err;
|
|
}
|
|
|
|
if (lpD3DHALCallbacks3->Clear2)
|
|
{
|
|
// Clear2 HAL Callback exists
|
|
D3DHAL_CLEAR2DATA Clear2Data;
|
|
Clear2Data.dwhContext = dwhContext;
|
|
Clear2Data.dwFlags = dwFlags;
|
|
// Here I will follow the ClearData.dwFillColor convention that
|
|
// color word is raw 32bit ARGB, unadjusted for surface bit depth
|
|
Clear2Data.dwFillColor = dwColor;
|
|
// depth/stencil values both passed straight from user args
|
|
Clear2Data.dvFillDepth = dvZ;
|
|
Clear2Data.dwFillStencil= dwStencil;
|
|
Clear2Data.lpRects = clrRects;
|
|
Clear2Data.dwNumRects = clrCount;
|
|
Clear2Data.ddrval = D3D_OK;
|
|
#ifndef WIN95
|
|
if((err = CheckContextSurface(this)) != D3D_OK)
|
|
{
|
|
throw err;
|
|
}
|
|
#endif
|
|
CALL_HAL3ONLY(err, this, Clear2, &Clear2Data);
|
|
if (err != DDHAL_DRIVER_HANDLED)
|
|
{
|
|
throw DDERR_UNSUPPORTED;
|
|
}
|
|
else if (Clear2Data.ddrval != DD_OK)
|
|
{
|
|
throw Clear2Data.ddrval;
|
|
}
|
|
else
|
|
return;
|
|
}
|
|
|
|
|
|
if (lpD3DHALGlobalDriverData->hwCaps.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR)
|
|
{
|
|
if (bDoStencilClear)
|
|
{
|
|
D3D_ERR("Invalid flag D3DCLEAR_STENCIL: this ZBUFFERLESSHSR device doesn't support Clear2()");
|
|
throw D3DERR_ZBUFFER_NOTPRESENT;
|
|
}
|
|
if (bDoZClear)
|
|
{
|
|
if (!(lpD3DHALCallbacks2->Clear) || (dvZ!=1.0))
|
|
{
|
|
D3D_WARN(3,"Ignoring D3DCLEAR_ZBUFFER since this ZBUFFERLESSHSR device doesn't even support Clear() or Z!=1");
|
|
dwFlags &= ~(D3DCLEAR_ZBUFFER);
|
|
}
|
|
}
|
|
}
|
|
LPDDPIXELFORMAT pZPixFmt;
|
|
if (NULL != lpDDSZBuffer)
|
|
{
|
|
pZPixFmt = &((LPDDRAWI_DDRAWSURFACE_INT) lpDDSZBuffer)->lpLcl->lpGbl->ddpfSurface;
|
|
}
|
|
else
|
|
{
|
|
pZPixFmt = NULL;
|
|
}
|
|
if (lpD3DHALCallbacks2->Clear)
|
|
{
|
|
if(bDoZClear || bDoStencilClear)
|
|
{
|
|
if((pZPixFmt!=NULL) && //PowerVR need no Zbuffer
|
|
(DDPF_STENCILBUFFER & pZPixFmt->dwFlags)
|
|
)
|
|
{
|
|
// if surface has stencil bits, must verify either Clear2 callback exists or
|
|
// we're using SW rasterizers (which require the special WriteMask DDHEL blt)
|
|
// This case should not be hit since we check right at the
|
|
// driver initialization time if the driver doesnt report Clear2
|
|
// yet it supports stencils
|
|
if(((LPDDRAWI_DDRAWSURFACE_INT)lpDDSZBuffer)->lpLcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
|
|
{
|
|
goto Emulateclear;
|
|
}
|
|
else
|
|
{
|
|
D3D_ERR("Driver HAL doesn't provide Clear2 callback, cannot use Clear2 with HW stencil surfaces");
|
|
throw DDERR_INVALIDPIXELFORMAT;
|
|
}
|
|
}
|
|
// if Clear2 callback doesnt exist and it's a z-only surface and not doing zclear to
|
|
// non-max value then Clear2 is attempting to do no more than Clear could do, so it's
|
|
// safe to call Clear() instead of Clear2(), which will take advantage of older
|
|
// drivers that implement Clear but not Clear2
|
|
|
|
dwFlags &= ~D3DCLEAR_STENCIL; // Device cannot do stencil
|
|
}
|
|
D3DHAL_CLEARDATA ClearData;
|
|
if (bDoZClear && dvZ != 1.0)
|
|
{
|
|
ClearData.dwFlags = dwFlags & ~D3DCLEAR_ZBUFFER;
|
|
dwFlags = D3DCLEAR_ZBUFFER;
|
|
}
|
|
else
|
|
{
|
|
ClearData.dwFlags = dwFlags;
|
|
dwFlags = 0;
|
|
}
|
|
if (ClearData.dwFlags)
|
|
{
|
|
ClearData.dwhContext = dwhContext;
|
|
// Here I will follow the ClearData.dwFillColor convention that
|
|
// color word is raw 32bit ARGB, unadjusted for surface bit depth
|
|
ClearData.dwFillColor = dwColor;
|
|
// must clear to 0xffffffff because legacy drivers expect this
|
|
ClearData.dwFillDepth = 0xffffffff;
|
|
ClearData.lpRects = clrRects;
|
|
ClearData.dwNumRects = clrCount;
|
|
ClearData.ddrval = D3D_OK;
|
|
#ifndef WIN95
|
|
if((err = CheckContextSurface(this)) != D3D_OK)
|
|
{
|
|
throw err;
|
|
}
|
|
#endif
|
|
CALL_HAL2ONLY(err, this, Clear, &ClearData);
|
|
if (err != DDHAL_DRIVER_HANDLED)
|
|
{
|
|
throw DDERR_UNSUPPORTED;
|
|
}
|
|
}
|
|
}
|
|
Emulateclear:
|
|
// Fall back to Emulation using Blt
|
|
|
|
if(bDoRGBClear)
|
|
{
|
|
BltFillRects(this, clrCount, clrRects, dwColor);
|
|
//ok to not return possible errors from Blt?
|
|
}
|
|
|
|
if ((bDoZClear || bDoStencilClear) && NULL != pZPixFmt)
|
|
{
|
|
DWORD dwZbufferClearValue=0;
|
|
DWORD dwZbufferClearMask=0;
|
|
DDASSERT(pZPixFmt->dwZBufferBitDepth<=32);
|
|
DDASSERT(pZPixFmt->dwStencilBitDepth<32);
|
|
DDASSERT(pZPixFmt->dwZBitMask!=0x0);
|
|
DDASSERT((0xFFFFFFFF == (pZPixFmt->dwZBitMask | pZPixFmt->dwStencilBitMask)) |
|
|
((DWORD)((1<<pZPixFmt->dwZBufferBitDepth)-1) == (pZPixFmt->dwZBitMask | pZPixFmt->dwStencilBitMask)));
|
|
DDASSERT(0==(pZPixFmt->dwZBitMask & pZPixFmt->dwStencilBitMask));
|
|
if(bDoZClear)
|
|
{
|
|
dwZbufferClearMask = pZPixFmt->dwZBitMask;
|
|
// special case the common cases
|
|
if(dvZ==1.0)
|
|
{
|
|
dwZbufferClearValue=pZPixFmt->dwZBitMask;
|
|
}
|
|
else if(dvZ > 0.0)
|
|
{
|
|
dwZbufferClearValue=((DWORD)((dvZ*(pZPixFmt->dwZBitMask >> zmask_shift))+0.5)) << zmask_shift;
|
|
}
|
|
}
|
|
if(bDoStencilClear)
|
|
{
|
|
DDASSERT(pZPixFmt->dwStencilBitMask!=0x0);
|
|
DDASSERT(pZPixFmt->dwFlags & DDPF_STENCILBUFFER);
|
|
dwZbufferClearMask |= pZPixFmt->dwStencilBitMask;
|
|
// special case the common case
|
|
if(dwStencil!=0)
|
|
{
|
|
dwZbufferClearValue |=(dwStencil << stencilmask_shift) & pZPixFmt->dwStencilBitMask;
|
|
}
|
|
}
|
|
if (dwZbufferClearMask == (pZPixFmt->dwStencilBitMask | pZPixFmt->dwZBitMask))
|
|
{
|
|
// do Stencil & Z Blt together, using regular DepthFill blt which will be faster
|
|
// than the writemask blt because its write-only, instead of read-modify-write
|
|
dwZbufferClearMask = 0;
|
|
}
|
|
BltFillZRects(this, dwZbufferClearValue, clrCount, clrRects, dwZbufferClearMask);
|
|
}
|
|
}
|