936 lines
27 KiB
C
936 lines
27 KiB
C
/******************************Module*Header*******************************\
|
|
* Module Name: mcdutil.c
|
|
*
|
|
* Contains various utility routines for the Millenium MCD driver such as
|
|
* rendering-procedure picking functionality and buffer management.
|
|
*
|
|
* Copyright (c) 1996 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#include "mcdhw.h"
|
|
#include "mcdutil.h"
|
|
#include "mcdmath.h"
|
|
#include "stdio.h"
|
|
|
|
static ULONG xlatRop[16] = {bop_BLACKNESS, // GL_CLEAR 0
|
|
bop_MASKPEN, // GL_AND S & D
|
|
bop_MASKPENNOT, // GL_AND_REVERSE S & ~D
|
|
bop_SRCCOPY, // GL_COPY S
|
|
bop_MASKNOTPEN, // GL_AND_INVERTED ~S & D
|
|
bop_NOP, // GL_NOOP D
|
|
bop_XORPEN, // GL_XOR S ^ D
|
|
bop_MERGEPEN, // GL_OR S | D
|
|
bop_NOTMERGEPEN, // GL_NOR ~(S | D)
|
|
bop_NOTXORPEN, // GL_EQUIV ~(S ^ D)
|
|
bop_NOT, // GL_INVERT ~D
|
|
bop_MERGEPENNOT, // GL_OR_REVERSE S | ~D
|
|
bop_NOTCOPYPEN, // GL_COPY_INVERTED ~S
|
|
bop_MERGENOTPEN, // GL_OR_INVERTED ~S | D
|
|
bop_NOTMASKPEN, // GL_NAND ~(S & D)
|
|
bop_WHITENESS, // GL_SET 1
|
|
};
|
|
|
|
// Function prototypes:
|
|
|
|
VOID FASTCALL HWSetupClipping(DEVRC *pRc, RECTL *pClip);
|
|
|
|
#define MCD_ALLOC_TAG 'dDCM'
|
|
|
|
#if DBG
|
|
|
|
//#define DEVDBG
|
|
|
|
ULONG MCDrvAllocMemSize = 0;
|
|
|
|
UCHAR *MCDDbgAlloc(UINT size)
|
|
{
|
|
UCHAR *pRet;
|
|
|
|
if (pRet = (UCHAR *)EngAllocMem(FL_ZERO_MEMORY, size + sizeof(ULONG),
|
|
MCD_ALLOC_TAG)) {
|
|
MCDrvAllocMemSize += size;
|
|
*((ULONG *)pRet) = size;
|
|
return (pRet + sizeof(ULONG));
|
|
} else
|
|
return (UCHAR *)NULL;
|
|
}
|
|
|
|
VOID MCDDbgFree(UCHAR *pMem)
|
|
{
|
|
if (!pMem) {
|
|
MCDBG_PRINT("MCDFree: Attempt to free NULL pointer.");
|
|
return;
|
|
}
|
|
|
|
pMem -= sizeof(ULONG);
|
|
|
|
MCDrvAllocMemSize -= *((ULONG *)pMem);
|
|
|
|
#ifdef DEVDBG
|
|
MCDBG_PRINT("MCDFree: %x bytes in use.", MCDrvAllocMemSize);
|
|
#endif
|
|
|
|
EngFreeMem((VOID *)pMem);
|
|
}
|
|
|
|
VOID MCDrvDebugPrint(char *pMessage, ...)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, pMessage);
|
|
|
|
EngDebugPrint("[MCD DRIVER] ", pMessage, ap);
|
|
EngDebugPrint("", "\n", ap);
|
|
|
|
va_end(ap);
|
|
}
|
|
|
|
#else
|
|
|
|
|
|
UCHAR *MCDAlloc(UINT size)
|
|
{
|
|
return (UCHAR *)EngAllocMem(FL_ZERO_MEMORY, size, MCD_ALLOC_TAG);
|
|
}
|
|
|
|
|
|
VOID MCDFree(UCHAR *pMem)
|
|
{
|
|
EngFreeMem((VOID *)pMem);
|
|
}
|
|
|
|
|
|
#endif /* DBG */
|
|
|
|
VOID FASTCALL NullRenderPoint(DEVRC *pRc, MCDVERTEX *pv)
|
|
{
|
|
}
|
|
|
|
VOID FASTCALL NullRenderLine(DEVRC *pRc, MCDVERTEX *pv1, MCDVERTEX *pv2, BOOL bReset)
|
|
{
|
|
}
|
|
|
|
VOID FASTCALL NullRenderTri(DEVRC *pRc, MCDVERTEX *pv1, MCDVERTEX *pv2, MCDVERTEX *pv3)
|
|
{
|
|
}
|
|
|
|
MCDCOMMAND * FASTCALL FailPrimDraw(DEVRC *pRc, MCDCOMMAND *pCmd)
|
|
{
|
|
HW_WAIT_DRAWING_DONE(pRc);
|
|
return pCmd;
|
|
}
|
|
|
|
BOOL PickPointFuncs(DEVRC *pRc)
|
|
{
|
|
ULONG enables = pRc->MCDState.enables;
|
|
|
|
pRc->drawPoint = NULL; // assume failure
|
|
|
|
if (enables & (MCD_POINT_SMOOTH_ENABLE))
|
|
return FALSE;
|
|
|
|
if ((enables & MCD_FOG_ENABLE) && (!pRc->bCheapFog))
|
|
return FALSE;
|
|
|
|
if (pRc->MCDState.pointSize != __MCDONE)
|
|
return FALSE;
|
|
|
|
// First, get high-level rendering functions:
|
|
|
|
if (pRc->MCDState.drawBuffer != GL_FRONT_AND_BACK) {
|
|
pRc->renderPoint = __MCDRenderPoint;
|
|
} else {
|
|
pRc->renderPoint = __MCDRenderGenPoint;
|
|
}
|
|
|
|
if ((pRc->bCheapFog) && (pRc->MCDState.shadeModel != GL_SMOOTH)) {
|
|
pRc->renderPointX = pRc->renderPoint;
|
|
pRc->renderPoint = __MCDRenderFogPoint;
|
|
}
|
|
|
|
// Handle any lower-level rendering if needed:
|
|
|
|
pRc->drawPoint = pRc->renderPoint;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL PickLineFuncs(DEVRC *pRc)
|
|
{
|
|
ULONG enables = pRc->MCDState.enables;
|
|
|
|
pRc->drawLine = NULL; // assume failure
|
|
|
|
if (enables & (MCD_LINE_SMOOTH_ENABLE |
|
|
MCD_LINE_STIPPLE_ENABLE))
|
|
return FALSE;
|
|
|
|
if ((enables & MCD_FOG_ENABLE) && (!pRc->bCheapFog))
|
|
return FALSE;
|
|
|
|
if (pRc->MCDState.lineWidth != __MCDONE)
|
|
return FALSE;
|
|
|
|
// First, get high-level rendering functions:
|
|
|
|
if (pRc->MCDState.drawBuffer != GL_FRONT_AND_BACK) {
|
|
if (pRc->MCDState.shadeModel == GL_SMOOTH)
|
|
pRc->renderLine = __MCDRenderSmoothLine;
|
|
else
|
|
pRc->renderLine = __MCDRenderFlatLine;
|
|
} else {
|
|
pRc->renderLine = __MCDRenderGenLine;
|
|
}
|
|
|
|
if ((pRc->bCheapFog) && (pRc->MCDState.shadeModel != GL_SMOOTH)) {
|
|
pRc->renderLineX = __MCDRenderSmoothLine;
|
|
pRc->renderLine = __MCDRenderFlatFogLine;
|
|
}
|
|
|
|
// Handle any lower-level rendering if needed:
|
|
|
|
pRc->drawLine = pRc->renderLine;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL PickTriangleFuncs(DEVRC *pRc)
|
|
{
|
|
ULONG enables = pRc->MCDState.enables;
|
|
|
|
if (enables & MCD_POLYGON_STIPPLE_ENABLE) {
|
|
ULONG *pStipple = (ULONG *)pRc->MCDState.polygonStipple;
|
|
LONG i;
|
|
|
|
for (pRc->hwStipple = trans_2, i = 0; i < 16; i += 2) {
|
|
if ((pStipple[i] != 0xaaaaaaaa) ||
|
|
(pStipple[i+1] != 0x55555555)) {
|
|
pRc->hwStipple = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!pRc->hwStipple) {
|
|
for (pRc->hwStipple = trans_1, i = 0; i < 16; i += 2) {
|
|
if ((pStipple[i] != 0x55555555) ||
|
|
(pStipple[i+1] != 0xaaaaaaaa)) {
|
|
pRc->hwStipple = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!pRc->hwStipple)
|
|
return FALSE;
|
|
} else
|
|
pRc->hwStipple = 0;
|
|
|
|
if (enables & (MCD_POLYGON_SMOOTH_ENABLE |
|
|
MCD_COLOR_LOGIC_OP_ENABLE))
|
|
return FALSE;
|
|
|
|
if ((enables & MCD_FOG_ENABLE) && (!pRc->bCheapFog))
|
|
return FALSE;
|
|
|
|
// First, get high-level rendering functions. If we're not GL_FILL'ing
|
|
// both sides of our polygons, use the "generic" function.
|
|
|
|
if (((pRc->MCDState.polygonModeFront == GL_FILL) &&
|
|
(pRc->MCDState.polygonModeBack == GL_FILL)) &&
|
|
(pRc->MCDState.drawBuffer != GL_FRONT_AND_BACK)
|
|
) {
|
|
if ((pRc->MCDState.shadeModel == GL_SMOOTH) ||
|
|
(pRc->bCheapFog))
|
|
pRc->renderTri = __MCDRenderSmoothTriangle;
|
|
else
|
|
pRc->renderTri = __MCDRenderFlatTriangle;
|
|
} else {
|
|
pRc->renderTri = __MCDRenderGenTriangle;
|
|
|
|
// In this case, we must handle the various fill modes. We must
|
|
// fail triangle drawing if we can't handle the types of primitives
|
|
// that may have to be drawn. This logic depends on the line and
|
|
// point pick routines
|
|
|
|
if (((pRc->MCDState.polygonModeFront == GL_POINT) && (!pRc->drawPoint)) ||
|
|
((pRc->MCDState.polygonModeFront == GL_LINE) && (!pRc->drawLine)))
|
|
return FALSE;
|
|
if (pRc->privateEnables & __MCDENABLE_TWOSIDED) {
|
|
if (((pRc->MCDState.polygonModeBack == GL_POINT) && (!pRc->drawPoint)) ||
|
|
((pRc->MCDState.polygonModeBack == GL_LINE) && (!pRc->drawLine)))
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if ((pRc->bCheapFog) && (pRc->MCDState.shadeModel != GL_SMOOTH)) {
|
|
pRc->renderTriX = pRc->renderTri;
|
|
pRc->renderTri = __MCDRenderFlatFogTriangle;
|
|
}
|
|
|
|
// Handle lower-level triangle rendering:
|
|
|
|
pRc->drawTri = __MCDFillTriangle;
|
|
|
|
pRc->HWDrawTrap = __HWDrawTrap;
|
|
pRc->HWSetupDeltas = __HWSetupDeltas;
|
|
pRc->calcDeltas = __MCDCalcDeltaRGBZ;
|
|
pRc->adjustLeftEdge = __HWAdjustLeftEdgeRGBZ;
|
|
pRc->adjustRightEdge = __HWAdjustRightEdge;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID __MCDPickRenderingFuncs(DEVRC *pRc, DEVWND *pDevWnd)
|
|
{
|
|
BOOL bSupportedZFunc = TRUE;
|
|
|
|
pRc->primFunc[GL_POINTS] = __MCDPrimDrawPoints;
|
|
pRc->primFunc[GL_LINES] = __MCDPrimDrawLines;
|
|
pRc->primFunc[GL_LINE_LOOP] = __MCDPrimDrawLineLoop;
|
|
pRc->primFunc[GL_LINE_STRIP] = __MCDPrimDrawLineStrip;
|
|
pRc->primFunc[GL_TRIANGLES] = __MCDPrimDrawTriangles;
|
|
pRc->primFunc[GL_TRIANGLE_STRIP] = __MCDPrimDrawTriangleStrip;
|
|
pRc->primFunc[GL_TRIANGLE_FAN] = __MCDPrimDrawTriangleFan;
|
|
pRc->primFunc[GL_QUADS] = __MCDPrimDrawQuads;
|
|
pRc->primFunc[GL_QUAD_STRIP] = __MCDPrimDrawQuadStrip;
|
|
pRc->primFunc[GL_POLYGON] = __MCDPrimDrawPolygon;
|
|
|
|
// Set up the privateEnables flags:
|
|
|
|
switch (pRc->MCDState.depthTestFunc) {
|
|
default:
|
|
case GL_NEVER:
|
|
bSupportedZFunc = FALSE;
|
|
break;
|
|
case GL_LESS:
|
|
pRc->hwZFunc = zmode_ZLT;
|
|
break;
|
|
case GL_EQUAL:
|
|
pRc->hwZFunc = zmode_ZE;
|
|
break;
|
|
case GL_LEQUAL:
|
|
pRc->hwZFunc = zmode_ZLTE;
|
|
break;
|
|
case GL_GREATER:
|
|
pRc->hwZFunc = zmode_ZGT;
|
|
break;
|
|
case GL_NOTEQUAL:
|
|
pRc->hwZFunc = zmode_ZNE;
|
|
break;
|
|
case GL_GEQUAL:
|
|
pRc->hwZFunc = zmode_ZGTE;
|
|
break;
|
|
case GL_ALWAYS:
|
|
pRc->hwZFunc = zmode_NOZCMP;
|
|
break;
|
|
}
|
|
|
|
if (pRc->MCDState.enables & MCD_COLOR_LOGIC_OP_ENABLE) {
|
|
pRc->hwRop = xlatRop[pRc->MCDState.logicOpMode & 0xf];
|
|
} else
|
|
pRc->hwRop = bop_SRCCOPY;
|
|
|
|
HW_GET_PLANE_MASK(pRc);
|
|
|
|
pRc->privateEnables = 0;
|
|
|
|
if ((pRc->MCDState.twoSided) &&
|
|
(pRc->MCDState.enables & MCD_LIGHTING_ENABLE))
|
|
pRc->privateEnables |= __MCDENABLE_TWOSIDED;
|
|
if (pDevWnd->bValidZBuffer &&
|
|
(pRc->MCDState.enables & MCD_DEPTH_TEST_ENABLE))
|
|
pRc->privateEnables |= __MCDENABLE_Z;
|
|
if (pRc->MCDState.shadeModel == GL_SMOOTH)
|
|
pRc->privateEnables |= __MCDENABLE_SMOOTH;
|
|
|
|
// Bail out if we can't support the requested z-buffer function:
|
|
|
|
if (pRc->privateEnables & __MCDENABLE_Z) {
|
|
if (!bSupportedZFunc) {
|
|
pRc->allPrimFail = TRUE;
|
|
return;
|
|
}
|
|
|
|
if ((pRc->MCDState.depthWritemask) && (pRc->zBufEnabled)) {
|
|
pRc->hwTrapFunc = pRc->hwLineFunc = atype_ZI;
|
|
} else {
|
|
pRc->hwTrapFunc = pRc->hwLineFunc = atype_I;
|
|
}
|
|
|
|
pRc->hwTrapFunc |= opcode_TRAP | pRc->hwRop | pRc->hwZFunc;
|
|
pRc->hwLineFunc |= opcode_LINE_OPEN | pRc->hwRop | pRc->hwZFunc;
|
|
|
|
} else {
|
|
pRc->hwTrapFunc = opcode_TRAP | atype_I | bop_SRCCOPY;
|
|
pRc->hwLineFunc = opcode_LINE_OPEN | atype_I | bop_SRCCOPY;
|
|
}
|
|
|
|
pRc->HWSetupClipRect = HWSetupClipping;
|
|
|
|
// Even though we're set up to handle this in the primitive pick
|
|
// functions, we'll exit early here since we don't actually handle
|
|
// this in the primitive routines themselves:
|
|
|
|
if (pRc->MCDState.drawBuffer == GL_FRONT_AND_BACK) {
|
|
pRc->allPrimFail = TRUE;
|
|
return;
|
|
}
|
|
|
|
// If we're culling everything or not updating any of our buffers, just
|
|
// return for all primitives:
|
|
|
|
if (((pRc->MCDState.enables & MCD_CULL_FACE_ENABLE) &&
|
|
(pRc->MCDState.cullFaceMode == GL_FRONT_AND_BACK)) ||
|
|
((pRc->MCDState.drawBuffer == GL_NONE) &&
|
|
((!pRc->MCDState.depthWritemask) || (!pDevWnd->bValidZBuffer)))
|
|
) {
|
|
pRc->renderPoint = NullRenderPoint;
|
|
pRc->renderLine = NullRenderLine;
|
|
pRc->renderTri = NullRenderTri;
|
|
pRc->allPrimFail = FALSE;
|
|
return;
|
|
}
|
|
|
|
// Build lookup table for face direction
|
|
|
|
switch (pRc->MCDState.frontFace) {
|
|
case GL_CW:
|
|
pRc->polygonFace[__MCD_CW] = __MCD_BACKFACE;
|
|
pRc->polygonFace[__MCD_CCW] = __MCD_FRONTFACE;
|
|
break;
|
|
case GL_CCW:
|
|
pRc->polygonFace[__MCD_CW] = __MCD_FRONTFACE;
|
|
pRc->polygonFace[__MCD_CCW] = __MCD_BACKFACE;
|
|
break;
|
|
}
|
|
|
|
// Build lookup table for face filling modes:
|
|
|
|
pRc->polygonMode[__MCD_FRONTFACE] = pRc->MCDState.polygonModeFront;
|
|
pRc->polygonMode[__MCD_BACKFACE] = pRc->MCDState.polygonModeBack;
|
|
|
|
if (pRc->MCDState.enables & MCD_CULL_FACE_ENABLE)
|
|
pRc->cullFlag = (pRc->MCDState.cullFaceMode == GL_FRONT ? __MCD_FRONTFACE :
|
|
__MCD_BACKFACE);
|
|
else
|
|
pRc->cullFlag = __MCD_NOFACE;
|
|
|
|
// Assume that we fail everything:
|
|
|
|
pRc->allPrimFail = TRUE;
|
|
|
|
// Determine if we have "cheap" fog:
|
|
|
|
pRc->bCheapFog = FALSE;
|
|
|
|
if (pRc->MCDState.enables & MCD_FOG_ENABLE) {
|
|
if (!(pRc->MCDState.textureEnabled) &&
|
|
(pRc->MCDState.fogHint != GL_NICEST)) {
|
|
pRc->bCheapFog = TRUE;
|
|
pRc->privateEnables |= __MCDENABLE_SMOOTH;
|
|
if ((pRc->MCDState.fogColor.r == pRc->MCDState.fogColor.g) &&
|
|
(pRc->MCDState.fogColor.r == pRc->MCDState.fogColor.b))
|
|
pRc->privateEnables |= __MCDENABLE_GRAY_FOG;
|
|
}
|
|
}
|
|
|
|
if (pRc->MCDState.textureEnabled)
|
|
return;
|
|
|
|
if (pRc->MCDState.enables & (MCD_ALPHA_TEST_ENABLE |
|
|
MCD_BLEND_ENABLE |
|
|
MCD_STENCIL_TEST_ENABLE))
|
|
return;
|
|
|
|
|
|
// Get rendering functions for points:
|
|
|
|
if (!PickPointFuncs(pRc)) {
|
|
pRc->primFunc[GL_POINTS] = FailPrimDraw;
|
|
} else
|
|
pRc->allPrimFail = FALSE;
|
|
|
|
// Get rendering functions for lines:
|
|
|
|
if (!PickLineFuncs(pRc)) {
|
|
pRc->primFunc[GL_LINES] = FailPrimDraw;
|
|
pRc->primFunc[GL_LINE_LOOP] = FailPrimDraw;
|
|
pRc->primFunc[GL_LINE_STRIP] = FailPrimDraw;
|
|
} else
|
|
pRc->allPrimFail = FALSE;
|
|
|
|
// Get rendering functions for triangles:
|
|
|
|
if (!PickTriangleFuncs(pRc)) {
|
|
pRc->primFunc[GL_TRIANGLES] = FailPrimDraw;
|
|
pRc->primFunc[GL_TRIANGLE_STRIP] = FailPrimDraw;
|
|
pRc->primFunc[GL_TRIANGLE_FAN] = FailPrimDraw;
|
|
pRc->primFunc[GL_QUADS] = FailPrimDraw;
|
|
pRc->primFunc[GL_QUAD_STRIP] = FailPrimDraw;
|
|
pRc->primFunc[GL_POLYGON] = FailPrimDraw;
|
|
} else
|
|
pRc->allPrimFail = FALSE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Hardware-specific utility functions:
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
VOID FASTCALL HWSetupClipping(DEVRC *pRc, RECTL *pClip)
|
|
{
|
|
PDEV *ppdev = pRc->ppdev;
|
|
BYTE *pjBase = ppdev->pjBase;
|
|
|
|
CHECK_FIFO_FREE(pjBase, pRc->cFifo, 4);
|
|
|
|
CP_WRITE(pjBase, DWG_CYTOP,
|
|
((pClip->top + pRc->hwBufferYBias) * ppdev->cxMemory) +
|
|
ppdev->ulYDstOrg);
|
|
CP_WRITE(pjBase, DWG_CXLEFT, pClip->left);
|
|
CP_WRITE(pjBase, DWG_CXRIGHT, pClip->right - 1);
|
|
CP_WRITE(pjBase, DWG_CYBOT,
|
|
((pClip->bottom + pRc->hwBufferYBias - 1) * ppdev->cxMemory) +
|
|
ppdev->ulYDstOrg);
|
|
|
|
}
|
|
|
|
//#define DEBUG_OFFSCREEN 1
|
|
//#define DEBUG_OFFSSCREEN_PARTIAL 1
|
|
|
|
#if DEBUG_OFFSCREEN
|
|
|
|
#undef pohAllocate
|
|
#undef pohFree
|
|
#define pohAllocate
|
|
#define pohFree
|
|
|
|
#endif
|
|
|
|
VOID HWUpdateBufferPos(MCDWINDOW *pMCDWnd, SURFOBJ *pso, BOOL bForce)
|
|
{
|
|
PDEV *ppdev = (PDEV *)pso->dhpdev;
|
|
DEVWND *pDevWnd = (DEVWND *)pMCDWnd->pvUser;
|
|
ULONG height;
|
|
|
|
if (pDevWnd->pohZBuffer &&
|
|
((ppdev->pohZBuffer != pDevWnd->pohZBuffer) ||
|
|
(bForce))) {
|
|
|
|
LONG offset;
|
|
LONG offsetAdj;
|
|
ULONG y;
|
|
|
|
// First, re-adjust the z buffer so that its offset from
|
|
// the front buffer window rectangle (in z) is a multiple of 512:
|
|
|
|
if (ppdev->pohZBuffer != pDevWnd->pohZBuffer)
|
|
offset = pDevWnd->zBufferBase -
|
|
(pMCDWnd->clipBoundsRect.top * pDevWnd->zPitch);
|
|
else
|
|
offset = pDevWnd->zBufferBase;
|
|
|
|
if (offset < 0) {
|
|
|
|
offset = -offset;
|
|
|
|
for (y = 0, offsetAdj = 0;
|
|
(y < pDevWnd->numPadScans) && (offset & 0x1ff);
|
|
offset -= pDevWnd->zPitch, offsetAdj += pDevWnd->zPitch)
|
|
;
|
|
|
|
} else {
|
|
for (y = 0, offsetAdj = 0;
|
|
(y < pDevWnd->numPadScans) && (offset & 0x1ff);
|
|
offset += pDevWnd->zPitch, offsetAdj += pDevWnd->zPitch)
|
|
;
|
|
}
|
|
|
|
ASSERTDD((offset & 0x1ff) == 0, "Z scan not on a 512-byte boundary.");
|
|
ASSERTDD(y <= pDevWnd->numPadScans, "Z scan adjustment too large");
|
|
|
|
pDevWnd->zBufferOffset = pDevWnd->zBufferBase + offsetAdj;
|
|
|
|
// Now, re-adjust the back buffer so that its offset (in z) from
|
|
// the new z buffer offset is also a multiple of 512 bytes. Note
|
|
// that zBufferOffset is always a multiple of zPitch:
|
|
|
|
if (pDevWnd->pohBackBuffer) {
|
|
|
|
offset = (pDevWnd->backBufferBaseY * pDevWnd->zPitch) -
|
|
pDevWnd->zBufferOffset;
|
|
|
|
for (y = 0; (y < pDevWnd->numPadScans) && (offset & 0x1ff); y++)
|
|
offset += pDevWnd->zPitch;
|
|
|
|
ASSERTDD((offset & 0x1ff) == 0, "Scan not on a 512-byte boundary.");
|
|
ASSERTDD(y <= pDevWnd->numPadScans, "Scan adjustment too large");
|
|
|
|
pDevWnd->backBufferY = y + pDevWnd->backBufferBaseY;
|
|
pDevWnd->backBufferOffset = (pDevWnd->backBufferY * ppdev->lDelta);
|
|
}
|
|
}
|
|
|
|
height = pMCDWnd->clientRect.bottom - pMCDWnd->clientRect.top;
|
|
|
|
if (height > pDevWnd->allocatedBufferHeight) {
|
|
#ifdef DEVDBG
|
|
MCDBG_PRINT("HWUpdateBufferPos: buffers are now an invalid size.");
|
|
#endif
|
|
|
|
pDevWnd->bValidBackBuffer = FALSE;
|
|
pDevWnd->bValidZBuffer = FALSE;
|
|
}
|
|
}
|
|
|
|
BOOL HWAllocResources(MCDWINDOW *pMCDWnd, SURFOBJ *pso,
|
|
BOOL zBufferEnabled,
|
|
BOOL backBufferEnabled)
|
|
{
|
|
DEVWND *pDevWnd = (DEVWND *)pMCDWnd->pvUser;
|
|
PDEV *ppdev = (PDEV *)pso->dhpdev;
|
|
ULONG w, width, height, fullHeight, zHeight, zFullHeight;
|
|
BOOL needFullZBuffer, needFullBackBuffer;
|
|
ULONG bufferExtra;
|
|
ULONG wPow2;
|
|
ULONG zPitch;
|
|
BOOL bFullScreen = FALSE;
|
|
OH* pohBackBuffer = NULL;
|
|
OH* pohZBuffer = NULL;
|
|
#if DEBUG_OFFSCREEN
|
|
static OH fakeOh[2];
|
|
|
|
pohBackBuffer = &fakeOh[0];
|
|
pohZBuffer = &fakeOh[1];
|
|
|
|
pohBackBuffer->y = 512;
|
|
pohZBuffer->y = 256;
|
|
#endif
|
|
|
|
#ifdef DEVDBG
|
|
MCDBG_PRINT("HWAllocResources");
|
|
#endif
|
|
|
|
#if DEBUG_OFFSCREEN
|
|
width = ppdev->cxScreen;
|
|
height = 256;
|
|
#else
|
|
width = ppdev->cxScreen;
|
|
height = min(pMCDWnd->clientRect.bottom - pMCDWnd->clientRect.top,
|
|
ppdev->cyScreen);
|
|
#endif
|
|
|
|
// Assume failure:
|
|
|
|
pDevWnd->allocatedBufferHeight = 0;
|
|
pDevWnd->bValidBackBuffer = FALSE;
|
|
pDevWnd->bValidZBuffer = FALSE;
|
|
pDevWnd->pohBackBuffer = NULL;
|
|
pDevWnd->pohZBuffer = NULL;
|
|
|
|
fullHeight = ppdev->cyScreen;
|
|
|
|
switch (ppdev->iBitmapFormat) {
|
|
case BMF_8BPP:
|
|
zPitch = ppdev->lDelta * 2;
|
|
break;
|
|
case BMF_16BPP:
|
|
zPitch = ppdev->lDelta;
|
|
break;
|
|
case BMF_24BPP:
|
|
case BMF_32BPP:
|
|
zPitch = ppdev->lDelta / 2;
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// We have to be able to keep our buffers 512-byte aligned, so calculate
|
|
// extra scan lines needed to aligned scan on a 512-byte boundary:
|
|
|
|
for (wPow2 = 1, w = zPitch;
|
|
(w) && !(w & 1); w >>= 1, wPow2 *= 2)
|
|
;
|
|
|
|
bufferExtra = 512 / wPow2; // z buffer granularity is 512 bytes...
|
|
|
|
// Now adjust the number of extra scan lines needed for the pixel format
|
|
// we're using, since the z and color stride may be different...
|
|
|
|
switch (ppdev->iBitmapFormat) {
|
|
case BMF_8BPP:
|
|
zHeight = ((height + bufferExtra) * 2) + 1;
|
|
zFullHeight = ((fullHeight + bufferExtra) * 2) + 1;
|
|
break;
|
|
case BMF_16BPP:
|
|
zHeight = height + bufferExtra;
|
|
zFullHeight = fullHeight + bufferExtra;
|
|
break;
|
|
case BMF_24BPP:
|
|
case BMF_32BPP:
|
|
zHeight = (height + bufferExtra + 1) / 2;
|
|
zFullHeight = (fullHeight + bufferExtra + 1) / 2;
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
pDevWnd->numPadScans = bufferExtra;
|
|
|
|
// Add extra scans for alignment:
|
|
|
|
height += bufferExtra;
|
|
fullHeight += bufferExtra;
|
|
|
|
if ((backBufferEnabled) && (!ppdev->cDoubleBufferRef))
|
|
needFullBackBuffer = TRUE;
|
|
else
|
|
needFullBackBuffer = FALSE;
|
|
|
|
if ((zBufferEnabled) && (!ppdev->cZBufferRef))
|
|
needFullZBuffer = TRUE;
|
|
else
|
|
needFullZBuffer = FALSE;
|
|
|
|
// debugging - force parial window allocation
|
|
|
|
#if DEBUG_OFFSCREEN && DEBUG_OFFSCREEN_PARTIAL
|
|
pohBackBuffer = NULL;
|
|
pohZBuffer = NULL;
|
|
#endif
|
|
|
|
// Before we begin, boot all the discardable stuff from offscreen
|
|
// memory:
|
|
|
|
bMoveAllDfbsFromOffscreenToDibs(ppdev);
|
|
|
|
// If we need a back buffer, first try to allocate a fullscreen one:
|
|
|
|
if (needFullBackBuffer) {
|
|
#ifndef DEBUG_OFFSCREEN
|
|
pohBackBuffer = pohAllocate(ppdev, NULL, width, fullHeight,
|
|
FLOH_MAKE_PERMANENT);
|
|
#endif
|
|
if (pohBackBuffer) {
|
|
ppdev->pohBackBuffer = pohBackBuffer;
|
|
ppdev->cDoubleBufferRef = 0;
|
|
}
|
|
}
|
|
|
|
// If we need a z buffer, first try to allocate a fullscreen z:
|
|
|
|
if (needFullZBuffer) {
|
|
#ifndef DEBUG_OFFSCREEN
|
|
pohZBuffer = pohAllocate(ppdev, NULL, width, zFullHeight,
|
|
FLOH_MAKE_PERMANENT);
|
|
#endif
|
|
if (pohZBuffer) {
|
|
ppdev->pohZBuffer = pohZBuffer;
|
|
ppdev->cZBufferRef = 0;
|
|
} else
|
|
needFullBackBuffer = FALSE;
|
|
}
|
|
|
|
// One of our full-screen allocations failed:
|
|
|
|
if ((needFullZBuffer && !pohZBuffer) ||
|
|
(needFullBackBuffer && !pohBackBuffer)) {
|
|
|
|
// Free any resources allocated so far:
|
|
|
|
if (pohZBuffer) {
|
|
pohFree(ppdev, pohZBuffer);
|
|
ppdev->pohZBuffer = NULL;
|
|
ppdev->cZBufferRef = 0;
|
|
}
|
|
if (pohBackBuffer) {
|
|
pohFree(ppdev, pohBackBuffer);
|
|
ppdev->pohBackBuffer = NULL;
|
|
ppdev->cDoubleBufferRef = 0;
|
|
}
|
|
|
|
// Now, try to allocate per-window resources:
|
|
|
|
if (backBufferEnabled) {
|
|
#ifndef DEBUG_OFFSCREEN
|
|
pohBackBuffer = pohAllocate(ppdev, NULL, width, height,
|
|
FLOH_MAKE_PERMANENT);
|
|
#else
|
|
pohBackBuffer = &fakeOh[0];
|
|
#endif
|
|
|
|
if (!pohBackBuffer) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (zBufferEnabled) {
|
|
#ifndef DEBUG_OFFSCREEN
|
|
pohZBuffer = pohAllocate(ppdev, NULL, width, zHeight,
|
|
FLOH_MAKE_PERMANENT);
|
|
#else
|
|
pohZBuffer = &fakeOh[1];
|
|
#endif
|
|
|
|
if (!pohZBuffer) {
|
|
if (pohBackBuffer)
|
|
pohFree(ppdev, pohBackBuffer);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
#ifdef DEVDBG
|
|
if (zBufferEnabled)
|
|
MCDBG_PRINT("HWAllocResources: Allocated window-sized z buffer");
|
|
if (backBufferEnabled)
|
|
MCDBG_PRINT("HWAllocResources: Allocated window-sized back buffer");
|
|
#endif
|
|
|
|
} else {
|
|
// Our full-screen allocations worked, or the resources existed
|
|
// already:
|
|
|
|
bFullScreen = TRUE;
|
|
|
|
#ifdef DEVDBG
|
|
if (zBufferEnabled && !ppdev->cZBufferRef)
|
|
MCDBG_PRINT("HWAllocResources: Allocated full-screen z buffer");
|
|
if (backBufferEnabled && !ppdev->cDoubleBufferRef)
|
|
MCDBG_PRINT("HWAllocResources: Allocated full-screen back buffer");
|
|
#endif
|
|
|
|
if (zBufferEnabled) {
|
|
pohZBuffer = ppdev->pohZBuffer;
|
|
ppdev->cZBufferRef++;
|
|
}
|
|
|
|
if (backBufferEnabled) {
|
|
pohBackBuffer = ppdev->pohBackBuffer;
|
|
ppdev->cDoubleBufferRef++;
|
|
}
|
|
}
|
|
|
|
pDevWnd->pohBackBuffer = pohBackBuffer;
|
|
pDevWnd->pohZBuffer = pohZBuffer;
|
|
|
|
pDevWnd->frontBufferPitch = ppdev->lDelta;
|
|
|
|
// Calculate back buffer variables:
|
|
|
|
if (backBufferEnabled) {
|
|
ULONG y;
|
|
ULONG offset;
|
|
|
|
ASSERTDD(pohBackBuffer->x == 0,
|
|
"Back buffer should be 0-aligned");
|
|
|
|
// Set up base position, etc.
|
|
|
|
pDevWnd->backBufferY = pDevWnd->backBufferBaseY = pohBackBuffer->y;
|
|
pDevWnd->backBufferOffset = pDevWnd->backBufferBase =
|
|
pohBackBuffer->y * ppdev->lDelta;
|
|
pDevWnd->backBufferPitch = ppdev->lDelta;
|
|
pDevWnd->bValidBackBuffer = TRUE;
|
|
}
|
|
|
|
if (zBufferEnabled) {
|
|
ULONG y = pohZBuffer->y;
|
|
|
|
ASSERTDD(pohZBuffer->x == 0,
|
|
"Z buffer should be 0-aligned");
|
|
|
|
pDevWnd->zBufferBaseY = pohZBuffer->y;
|
|
|
|
// Make sure out z buffer starts on a valid z scan line. The only
|
|
// case where this may not happen is 8bpp, which is why we add one
|
|
// the the number if z scan lines allocated above.
|
|
|
|
if (ppdev->iBitmapFormat == BMF_8BPP)
|
|
pDevWnd->zBufferBase = (pohZBuffer->y & ~1) * ppdev->lDelta;
|
|
else
|
|
pDevWnd->zBufferBase = pohZBuffer->y * ppdev->lDelta;
|
|
|
|
pDevWnd->zPitch = zPitch;
|
|
pDevWnd->bValidZBuffer = TRUE;
|
|
}
|
|
|
|
if (bFullScreen)
|
|
pDevWnd->allocatedBufferHeight = ppdev->cyMemory;
|
|
else
|
|
pDevWnd->allocatedBufferHeight = min(pMCDWnd->clientRect.bottom - pMCDWnd->clientRect.top,
|
|
ppdev->cyScreen);
|
|
|
|
// Update position-dependant buffer information:
|
|
|
|
HWUpdateBufferPos(pMCDWnd, pso, TRUE);
|
|
|
|
#ifdef DEVDBG
|
|
MCDBG_PRINT("HWAllocResources OK");
|
|
#endif
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID HWFreeResources(MCDWINDOW *pMCDWnd, SURFOBJ *pso)
|
|
{
|
|
DEVWND *pDevWnd = (DEVWND *)pMCDWnd->pvUser;
|
|
PDEV *ppdev = (PDEV *)pso->dhpdev;
|
|
|
|
if (pDevWnd->pohZBuffer) {
|
|
if (ppdev->cZBufferRef) {
|
|
if (!--ppdev->cZBufferRef) {
|
|
#ifdef DEVDBG
|
|
MCDBG_PRINT("MCDrvTrackWindow: Free global z buffer");
|
|
#endif
|
|
pohFree(ppdev, ppdev->pohZBuffer);
|
|
ppdev->pohZBuffer = NULL;
|
|
}
|
|
} else {
|
|
#ifdef DEVDBG
|
|
MCDBG_PRINT("MCDrvTrackWindow: Free local z buffer");
|
|
#endif
|
|
pohFree(ppdev, pDevWnd->pohZBuffer);
|
|
}
|
|
}
|
|
|
|
if (pDevWnd->pohBackBuffer) {
|
|
if (ppdev->cDoubleBufferRef) {
|
|
if (!--ppdev->cDoubleBufferRef) {
|
|
#ifdef DEVDBG
|
|
MCDBG_PRINT("MCDrvTrackWindow: Free global color buffer");
|
|
#endif
|
|
pohFree(ppdev, ppdev->pohBackBuffer);
|
|
ppdev->pohBackBuffer = NULL;
|
|
}
|
|
} else {
|
|
#ifdef DEVDBG
|
|
MCDBG_PRINT("MCDrvTrackWindow: Free local color buffer");
|
|
#endif
|
|
pohFree(ppdev, pDevWnd->pohBackBuffer);
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID __MCDCalcFogColor(DEVRC *pRc, MCDVERTEX *a, MCDCOLOR *pResult,
|
|
MCDCOLOR *pColor)
|
|
{
|
|
MCDFLOAT oneMinusFog;
|
|
MCDCOLOR *pFogColor;
|
|
|
|
pFogColor = (MCDCOLOR *)&pRc->MCDState.fogColor;
|
|
oneMinusFog = (MCDFLOAT)1.0 - a->fog;
|
|
|
|
if (pRc->privateEnables & __MCDENABLE_GRAY_FOG) {
|
|
MCDFLOAT delta = oneMinusFog * pFogColor->r;
|
|
|
|
pResult->r = a->fog * pColor->r + delta;
|
|
pResult->g = a->fog * pColor->g + delta;
|
|
pResult->b = a->fog * pColor->b + delta;
|
|
} else {
|
|
pResult->r = (a->fog * pColor->r) + (oneMinusFog * pFogColor->r);
|
|
pResult->g = (a->fog * pColor->g) + (oneMinusFog * pFogColor->g);
|
|
pResult->b = (a->fog * pColor->b) + (oneMinusFog * pFogColor->b);
|
|
}
|
|
}
|