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.
1352 lines
46 KiB
1352 lines
46 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: mcdutil.c
|
|
*
|
|
* Contains various utility routines for the Cirrus Logic 546X MCD driver such as
|
|
* rendering-procedure picking functionality and buffer management.
|
|
*
|
|
* (based on mcdutil.c from NT4.0 DDK)
|
|
*
|
|
* Copyright (c) 1996 Microsoft Corporation
|
|
* Copyright (c) 1997 Cirrus Logic, Inc.
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#include "mcdhw.h"
|
|
#include "mcdutil.h"
|
|
#include "mcdmath.h"
|
|
#include "stdio.h"
|
|
|
|
#ifdef B4_CIRRUS
|
|
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
|
|
};
|
|
#endif // B4_CIRRUS
|
|
|
|
// Function prototypes:
|
|
|
|
VOID FASTCALL HWSetupClipping(DEVRC *pRc, RECTL *pClip);
|
|
|
|
#define MCD_ALLOC_TAG 'dDCM'
|
|
|
|
#if DBG
|
|
|
|
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);
|
|
|
|
//MCDBG_PRINT("MCDFree: %x bytes in use.", MCDrvAllocMemSize);
|
|
|
|
EngFreeMem((VOID *)pMem);
|
|
}
|
|
|
|
|
|
#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 MCDrvDebugPrint(char *pMessage, ...)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, pMessage);
|
|
|
|
EngDebugPrint("[MCD DRIVER] ", pMessage, ap);
|
|
EngDebugPrint("", "\n", ap);
|
|
|
|
va_end(ap);
|
|
}
|
|
|
|
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)
|
|
{
|
|
#ifdef B4_CIRRUS
|
|
HW_WAIT_DRAWING_DONE(pRc);
|
|
#endif // B4_CIRRUS
|
|
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 (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;
|
|
}
|
|
|
|
// 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)
|
|
return FALSE;
|
|
|
|
if (pRc->MCDState.lineWidth > __MCDONE)
|
|
return FALSE;
|
|
|
|
// First, get high-level rendering functions:
|
|
|
|
if (pRc->MCDState.drawBuffer != GL_FRONT_AND_BACK) {
|
|
pRc->renderLine = __MCDRenderLine;
|
|
} else {
|
|
pRc->renderLine = __MCDRenderGenLine;
|
|
}
|
|
|
|
// Handle any lower-level rendering if needed:
|
|
|
|
pRc->drawLine = pRc->renderLine;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL PickTriangleFuncs(DEVRC *pRc)
|
|
{
|
|
ULONG enables = pRc->MCDState.enables;
|
|
|
|
//MCD_NOTE: MGA checked here if should punt on stipple - 546x does that in PickRendering
|
|
//MCD_NOTE: before this proc is called
|
|
|
|
if (enables & (MCD_POLYGON_SMOOTH_ENABLE |
|
|
MCD_COLOR_LOGIC_OP_ENABLE))
|
|
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->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
|
|
|
|
// FUTURE: Sort out 2-sided support
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
// Handle lower-level triangle rendering:
|
|
|
|
//FUTURE: add ability to configure different parameterization procs?
|
|
if (pRc->privateEnables & __MCDENABLE_PERSPECTIVE)
|
|
pRc->drawTri = __MCDPerspTxtTriangle;
|
|
else
|
|
pRc->drawTri = __MCDFillTriangle;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID __MCDPickRenderingFuncs(DEVRC *pRc, DEVWND *pDevWnd)
|
|
{
|
|
BOOL bSupportedZFunc = TRUE;
|
|
unsigned int z_mode, z_comp_mode;
|
|
unsigned int punt_all_points = FALSE;
|
|
unsigned int punt_all_lines = FALSE;
|
|
unsigned int punt_all_polys = FALSE;
|
|
PDEV *ppdev = pRc->ppdev;
|
|
DWORD *pdwNext = ppdev->LL_State.pDL->pdwNext;
|
|
int control0_set=FALSE;
|
|
ULONG _MCDStateenables = pRc->MCDState.enables; // copy we can modify
|
|
int const_alpha_mode=FALSE;
|
|
int frame_scale=FALSE;
|
|
|
|
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;
|
|
|
|
// normal mode for all conditions except NEVER and ALWAYS
|
|
z_mode = LL_Z_MODE_NORMAL;
|
|
|
|
switch (pRc->MCDState.depthTestFunc) {
|
|
default:
|
|
case GL_NEVER:
|
|
z_mode = LL_Z_MODE_MASK;
|
|
// comp mode is don't care, but set to default anyway
|
|
z_comp_mode = LL_Z_WRITE_GREATER_EQUAL;
|
|
break;
|
|
case GL_LESS:
|
|
z_comp_mode = LL_Z_WRITE_LESS;
|
|
break;
|
|
case GL_EQUAL:
|
|
z_comp_mode = LL_Z_WRITE_EQUAL;
|
|
break;
|
|
case GL_LEQUAL:
|
|
z_comp_mode = LL_Z_WRITE_LESS_EQUAL;
|
|
break;
|
|
case GL_GREATER:
|
|
z_comp_mode = LL_Z_WRITE_GREATER;
|
|
break;
|
|
case GL_NOTEQUAL:
|
|
z_comp_mode = LL_Z_WRITE_NOT_EQUAL;
|
|
break;
|
|
case GL_GEQUAL:
|
|
z_comp_mode = LL_Z_WRITE_GREATER_EQUAL;
|
|
break;
|
|
case GL_ALWAYS:
|
|
z_mode = LL_Z_MODE_ALWAYS;
|
|
// comp mode is don't care, but set to default anyway
|
|
z_comp_mode = LL_Z_WRITE_GREATER_EQUAL;
|
|
break;
|
|
}
|
|
|
|
// Set up the privateEnables flags:
|
|
pRc->privateEnables = 0;
|
|
|
|
if ((pRc->MCDState.twoSided) &&
|
|
(_MCDStateenables & MCD_LIGHTING_ENABLE))
|
|
pRc->privateEnables |= __MCDENABLE_TWOSIDED;
|
|
if (pDevWnd->bValidZBuffer &&
|
|
(_MCDStateenables & MCD_DEPTH_TEST_ENABLE))
|
|
{
|
|
pRc->privateEnables |= __MCDENABLE_Z;
|
|
if (z_mode == LL_Z_MODE_MASK)
|
|
{
|
|
// GL_NEVER depth test, so ignore all primitives
|
|
pRc->allPrimFail = TRUE;
|
|
return;
|
|
}
|
|
|
|
// Z enabled, so if draw to front (which is full screen and requires coords relative
|
|
// to screen origin) and z is windowed (which requires coords relative to window origin),
|
|
// punt
|
|
if (pRc->MCDState.drawBuffer == GL_FRONT)
|
|
{
|
|
if (pRc->ppdev->pohZBuffer != pDevWnd->pohZBuffer)
|
|
{
|
|
pRc->allPrimFail = TRUE;
|
|
pRc->punt_front_w_windowed_z=TRUE;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// reset global punt due to front buf draw with window-size z buffer
|
|
pRc->punt_front_w_windowed_z = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pRc->punt_front_w_windowed_z)
|
|
{
|
|
// Drawing to backbuffer after drawing to front was punted.
|
|
// Need to punt back draws as well since pixel-to-pixel compares
|
|
// of punted front and non-punted back will fail conformance test,
|
|
// since punted result and non-punted are visually equivalent, but not
|
|
// always exactly identical.
|
|
|
|
// FUTURE2 : how to fix need to punt when full-screen front and windowed Z:
|
|
// instead of making z buffer exact size as window, make larger such
|
|
// that it starts at a y=16, x=64 boundary - where x/y offsets of
|
|
// the 0,0 location of the window are same as the offsets of the window
|
|
// from the nearest 16/64 location on the fullscreen buffer.
|
|
// See MCD notes, p 267 for details
|
|
pRc->allPrimFail = TRUE;
|
|
return;
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// reset global punt due to front buf draw with window-size z buffer
|
|
pRc->punt_front_w_windowed_z = FALSE;
|
|
}
|
|
|
|
if (pRc->MCDState.shadeModel == GL_SMOOTH)
|
|
pRc->privateEnables |= __MCDENABLE_SMOOTH;
|
|
|
|
// MCD_NOTE: if stipple and dither active at same time, may need to fail all lines/polys
|
|
// MCD_NOTE: - for now, we let stipple take precedence (see code in __MCDFillTriangle, etc)
|
|
if (_MCDStateenables & MCD_DITHER_ENABLE)
|
|
pRc->privateEnables |= __MCDENABLE_DITHER;
|
|
|
|
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 doing any of the following...
|
|
// - culling everything
|
|
// - not updating any of our buffers
|
|
// - zmode says never update
|
|
// - alpha test says never pass
|
|
//...just return for all primitives:
|
|
|
|
if (((_MCDStateenables & MCD_CULL_FACE_ENABLE) &&
|
|
(pRc->MCDState.cullFaceMode == GL_FRONT_AND_BACK)) ||
|
|
|
|
((pRc->MCDState.drawBuffer == GL_NONE) &&
|
|
((!pRc->MCDState.depthWritemask) || (!pDevWnd->bValidZBuffer))) ||
|
|
|
|
((pRc->privateEnables & __MCDENABLE_Z) && (z_mode == LL_Z_MODE_MASK)) ||
|
|
|
|
((_MCDStateenables & MCD_ALPHA_TEST_ENABLE) && (pRc->MCDState.alphaTestFunc == GL_NEVER))
|
|
|
|
) {
|
|
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 (_MCDStateenables & 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;
|
|
|
|
// see comment in mcd.hlp on MCDVERTEX - disable fog if texture mapping or gouraud shading
|
|
if (!pRc->MCDState.textureEnabled && (pRc->MCDState.shadeModel == GL_SMOOTH))
|
|
{
|
|
_MCDStateenables &= ~MCD_FOG_ENABLE;
|
|
}
|
|
|
|
|
|
if ((_MCDStateenables & MCD_FOG_ENABLE) &&
|
|
((pRc->MCDState.fogMode != GL_LINEAR) || (pRc->MCDState.fogHint == GL_NICEST)))
|
|
{
|
|
// 546x only does linear fog, so punt otherwise
|
|
// QST2 - if linear fog mode, do we have to punt if foghint GL_NICEST?
|
|
MCDFREE_PRINT("__MCDPick...non linear fog - punt");
|
|
return;
|
|
}
|
|
|
|
if (_MCDStateenables & (MCD_COLOR_LOGIC_OP_ENABLE |
|
|
MCD_INDEX_LOGIC_OP_ENABLE |
|
|
MCD_SCISSOR_TEST_ENABLE |
|
|
MCD_STENCIL_TEST_ENABLE))
|
|
{
|
|
MCDFREE_PRINT(".. will punt...logic ops or stencil ");
|
|
return;
|
|
}
|
|
|
|
if (_MCDStateenables & (MCD_ALPHA_TEST_ENABLE))
|
|
{
|
|
if (pRc->MCDState.alphaTestFunc == GL_ALWAYS)
|
|
{
|
|
// if GL_ALWAYS, it's the same as no alpha test, so turn it off
|
|
_MCDStateenables &= ~MCD_ALPHA_TEST_ENABLE;
|
|
}
|
|
else
|
|
{
|
|
if ((pRc->MCDState.alphaTestFunc == GL_GREATER) &&
|
|
pRc->MCDState.textureEnabled)
|
|
{
|
|
// only have alpha test support when textured - and even then it's limited
|
|
// store ref scaled by 8 bits for compare to 8 bit alpha in BGRA textures
|
|
pRc->bAlphaTestRef = (BYTE)(pRc->MCDState.alphaTestRef * (float)255.0);
|
|
pRc->privateEnables |= __MCDENABLE_TEXTUREMASKING;
|
|
}
|
|
else
|
|
{
|
|
MCDFREE_PRINT("AlphaTest, but not ALWAYS,NEVER, or GREATER (or not textured) - punt");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// if both blend and fog active, punt all since only one set of interpolators on 546x
|
|
if ( (_MCDStateenables & (MCD_BLEND_ENABLE|MCD_FOG_ENABLE)) ==
|
|
(MCD_BLEND_ENABLE|MCD_FOG_ENABLE))
|
|
{
|
|
MCDFREE_PRINT(".. will punt...fog and blend ");
|
|
return;
|
|
}
|
|
|
|
if (_MCDStateenables & MCD_BLEND_ENABLE)
|
|
{
|
|
MCDFREE_PRINT("BLENDS: Src=%x Dst=%x",pRc->MCDState.blendSrc,pRc->MCDState.blendDst);
|
|
|
|
if ((pRc->MCDState.blendSrc == GL_ONE) &&
|
|
(pRc->MCDState.blendDst == GL_ZERO))
|
|
{
|
|
// equivalent to no blending, so shut it off
|
|
_MCDStateenables &= ~MCD_BLEND_ENABLE;
|
|
}
|
|
else if ((pRc->MCDState.blendSrc == GL_ZERO) &&
|
|
(pRc->MCDState.blendDst == GL_ONE_MINUS_SRC_COLOR))
|
|
{
|
|
// one of GLQuake's favorite modes - requires HW's "Frame Scaling" function
|
|
frame_scale=TRUE;
|
|
}
|
|
else if ((pRc->MCDState.blendSrc == GL_ONE) &&
|
|
(pRc->MCDState.blendDst == GL_ONE))
|
|
{
|
|
// one of GLQuake's favorite modes - will use CONST blend (set later in this proc)
|
|
const_alpha_mode=TRUE;
|
|
// lines and points don't yet support CONST blend - a simple matter of
|
|
// programming to make points and lines work like polys in this regard
|
|
punt_all_points=TRUE;
|
|
punt_all_lines=TRUE;
|
|
}
|
|
else if ((pRc->MCDState.blendSrc != GL_SRC_ALPHA) ||
|
|
(pRc->MCDState.blendDst != GL_ONE_MINUS_SRC_ALPHA))
|
|
{
|
|
// unsupported mode
|
|
MCDFREE_PRINT("unsupported blendSrc/blendDest");
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
// FUTURE2: now punting if colorWriteMask not 1,1,1,X - should implement w/ color compare func
|
|
if (!(pRc->MCDState.colorWritemask[0] &&
|
|
pRc->MCDState.colorWritemask[1] &&
|
|
pRc->MCDState.colorWritemask[2]))
|
|
{
|
|
MCDFREE_PRINT(".. will punt...write mask ");
|
|
return;
|
|
}
|
|
|
|
|
|
// WARNING ........
|
|
// WARNING ........
|
|
// WARNING ........
|
|
// Code below MAY set state in shadow regs, so be careful about early return early to punt
|
|
// FROM THIS POINT ON...
|
|
|
|
if (pRc->MCDState.textureEnabled)
|
|
{
|
|
// parameterization code for lines/points not done yet
|
|
punt_all_points=TRUE;
|
|
punt_all_lines=TRUE;
|
|
|
|
MCDFREE_PRINT("__MCDPick...textures, envmode=%x ",pRc->MCDTexEnvState.texEnvMode);
|
|
|
|
// punt if blending and alphatest both enabled - framescale part of blending,
|
|
// so this covers punt needed for alphatest and framescaling
|
|
if ((_MCDStateenables & (MCD_BLEND_ENABLE|MCD_ALPHA_TEST_ENABLE)) ==
|
|
(MCD_BLEND_ENABLE|MCD_ALPHA_TEST_ENABLE))
|
|
{
|
|
MCDFREE_PRINT("__MCDPick...textures, punt since blend & alphatest");
|
|
return;
|
|
}
|
|
|
|
if (pRc->MCDState.perspectiveCorrectionHint!=GL_FASTEST)
|
|
pRc->privateEnables |= (__MCDENABLE_TEXTURE|__MCDENABLE_PERSPECTIVE);
|
|
else
|
|
pRc->privateEnables |= __MCDENABLE_TEXTURE;
|
|
|
|
// if both 1d and 2d bits same state, 2d is done (or if only 2d bit is on)
|
|
if ((_MCDStateenables & (MCD_TEXTURE_1D_ENABLE|MCD_TEXTURE_2D_ENABLE)) == MCD_TEXTURE_1D_ENABLE)
|
|
{
|
|
pRc->privateEnables |= __MCDENABLE_1D_TEXTURE;
|
|
}
|
|
|
|
if (pRc->MCDTexEnvState.texEnvMode == GL_BLEND)
|
|
{
|
|
// MCD_NOTE2: the following works only for GL_LUMINANCE, GL_LUMINANCE_ALPHA, and
|
|
// GL_INTENSITY textures. GL_RGB and GL_RGBA textures will punt (later).
|
|
|
|
// if normal blending or fog on and texture blend environment, then must punt since
|
|
// this requires 2 sets of alpha equations and hw only has 1
|
|
if (_MCDStateenables & (MCD_BLEND_ENABLE|MCD_FOG_ENABLE|MCD_ALPHA_TEST_ENABLE))
|
|
{
|
|
MCDFREE_PRINT("__MCDPick...textures, GL_BLEND and fog|blend|alphatest");
|
|
return;
|
|
}
|
|
|
|
// set alpha mode and dest color regs for GL_BLEND texture environment
|
|
if( pRc->Control0.Alpha_Mode != LL_ALPHA_TEXTURE )
|
|
{
|
|
pRc->Control0.Alpha_Mode = LL_ALPHA_TEXTURE;
|
|
control0_set=TRUE;
|
|
}
|
|
|
|
if( pRc->Control0.Alpha_Dest_Color_Sel != LL_ALPHA_DEST_CONST )
|
|
{
|
|
pRc->Control0.Alpha_Dest_Color_Sel = LL_ALPHA_DEST_CONST;
|
|
control0_set=TRUE;
|
|
}
|
|
|
|
// load texture env color into color0 register
|
|
pRc->dwColor0 = (FTOL(pRc->MCDTexEnvState.texEnvColor.r * pRc->rScale) & 0xff0000);
|
|
pRc->dwColor0 |= (FTOL(pRc->MCDTexEnvState.texEnvColor.g * pRc->gScale) & 0xff0000) >> 8;
|
|
pRc->dwColor0 |= (FTOL(pRc->MCDTexEnvState.texEnvColor.b * pRc->bScale) & 0xff0000) >> 16;
|
|
|
|
*pdwNext++ = write_register( COLOR0_3D, 1 );
|
|
*pdwNext++ = pRc->dwColor0;
|
|
|
|
if (!pRc->Control0.Alpha_Blending_Enable)
|
|
{
|
|
pRc->Control0.Alpha_Blending_Enable = TRUE;
|
|
control0_set=TRUE;
|
|
}
|
|
|
|
}
|
|
else if (pRc->MCDTexEnvState.texEnvMode == GL_MODULATE)
|
|
{
|
|
if (frame_scale)
|
|
{
|
|
MCDFREE_PRINT("__MCDPick...textures, GL_MODULATE and framescaling");
|
|
return;
|
|
}
|
|
|
|
pRc->privateEnables |= __MCDENABLE_LIGHTING;
|
|
|
|
if( pRc->Control0.Light_Src_Sel != LL_LIGHTING_INTERP_RGB )
|
|
{
|
|
pRc->Control0.Light_Src_Sel = LL_LIGHTING_INTERP_RGB;
|
|
control0_set=TRUE;
|
|
}
|
|
}
|
|
// if texEnvMod not blend or modulate, it's either replace or decal - some settings
|
|
// req'd at runtime, but not here
|
|
|
|
// set so that first primitive will force setup of texture control regs
|
|
pRc->pLastTexture = TEXTURE_NOT_LOADED;
|
|
|
|
}
|
|
else
|
|
{
|
|
// if texture not enabled, make sure texture mask disabled
|
|
// this is a bug in 5464 and 5465 hardware
|
|
// Texture enable/disable done only by state change (outside of DrvDraw)
|
|
// so we don't have to check this per primitive
|
|
|
|
if (_MCDStateenables & MCD_ALPHA_TEST_ENABLE)
|
|
{
|
|
pRc->privateEnables &= ~__MCDENABLE_TEXTUREMASKING;
|
|
|
|
#ifdef STRICT_CONFORMANCE
|
|
MCDFREE_PRINT("__MCDPick...alphatest but not textured - punt");
|
|
return;
|
|
#else
|
|
MCDFREE_PRINT("__MCDPick...alphatest but not textured - SHOULD PUNT, BUT WON'T");
|
|
#endif
|
|
|
|
}
|
|
|
|
if (frame_scale)
|
|
{
|
|
MCDFREE_PRINT("__MCDPick...framescale but not textured - punt");
|
|
return;
|
|
}
|
|
|
|
if (pRc->dwTxControl0 & TEX_MASK_EN)
|
|
{
|
|
pRc->dwTxControl0 &= ~TEX_MASK_EN;
|
|
*pdwNext++ = write_register( TX_CTL0_3D, 1 );
|
|
*pdwNext++ = pRc->dwTxControl0;
|
|
}
|
|
}
|
|
|
|
if (_MCDStateenables & MCD_LINE_STIPPLE_ENABLE)
|
|
{
|
|
if ( (_MCDStateenables & (MCD_BLEND_ENABLE|MCD_FOG_ENABLE)) ||
|
|
(pRc->MCDState.lineStippleRepeat > 2) )
|
|
{
|
|
// if stipple active and alpha (via blend or fog), punt all lines
|
|
// since 5464 has very limited support for this
|
|
// also punt if factor > 2, since pattern is > 32 bits in such cases
|
|
// NOTE that even though stipple and blend won't work as desired, dither and blend
|
|
// should. DanW says 5464 has bug so this doesn't look too hot but this should
|
|
// be fixed in 5465 and following.
|
|
punt_all_lines = TRUE;
|
|
}
|
|
else
|
|
{
|
|
DWORD linestipple;
|
|
|
|
if (pRc->MCDState.lineStippleRepeat == 1)
|
|
{
|
|
// repeat 16bit stipple twice,
|
|
linestipple = (pRc->MCDState.lineStipplePattern<<16) | pRc->MCDState.lineStipplePattern;
|
|
}
|
|
else
|
|
{
|
|
// double each bit, so 16 bit original becomes 32 bit
|
|
int i;
|
|
linestipple = 0;
|
|
|
|
for (i=0; i<16; i++)
|
|
{
|
|
linestipple |= (((pRc->MCDState.lineStipplePattern>>i) & 1) * 3) << (i*2);
|
|
}
|
|
|
|
}
|
|
|
|
pRc->line_style.pat[0] = linestipple;
|
|
|
|
pRc->privateEnables |= __MCDENABLE_LINE_STIPPLE;
|
|
|
|
}
|
|
pRc->ppdev->LL_State.pattern_ram_state = PATTERN_RAM_INVALID;
|
|
}
|
|
|
|
|
|
if (_MCDStateenables & MCD_POLYGON_STIPPLE_ENABLE)
|
|
{
|
|
if (_MCDStateenables & (MCD_BLEND_ENABLE|MCD_FOG_ENABLE))
|
|
{
|
|
// if stipple active and alpha (via blend or fog), punt all polygons
|
|
// since 5464 has very limited support for this
|
|
punt_all_polys = TRUE;
|
|
}
|
|
else
|
|
{
|
|
|
|
BYTE *pStipple = pRc->MCDState.polygonStipple;
|
|
int i,j;
|
|
|
|
for (i=0; i<64; ) {
|
|
|
|
// 546x stipple is 16x16, OpenGL's is 32x32, so unless 32x32 pattern
|
|
// is really a 16x16 pattern repeated 4 times, we have to punt.
|
|
|
|
// for 32 bit row of OpenGL pattern, check if byte0=byte2 and byte1=byte3
|
|
if (pStipple[i] != pStipple[i+2]) break;
|
|
if (pStipple[i+1] != pStipple[i+3]) break;
|
|
|
|
// now check if 4 bytes of 32bit row match 4bytes 32 bit row 16 rows down
|
|
if (pStipple[i] != pStipple[i+(16*4)]) break;
|
|
if (pStipple[i+1] != pStipple[i+(16*4)+1]) break;
|
|
if (pStipple[i+2] != pStipple[i+(16*4)+2]) break;
|
|
if (pStipple[i+3] != pStipple[i+(16*4)+3]) break;
|
|
|
|
i+=4;
|
|
|
|
}
|
|
|
|
// if we broke out before all 32 rows processed, HW can't support the pattern
|
|
if (i<64)
|
|
{
|
|
punt_all_polys=TRUE;
|
|
}
|
|
else
|
|
{
|
|
// pattern is OK - convert to format 546x needs
|
|
unsigned int *pat = (unsigned int *)pRc->fill_pattern.pat;
|
|
|
|
// Recall that we already verified that 32x32 pattern is really 4 identical
|
|
// 16x16 blocks. So take the upper left block and convert to 546x 16x16 pattern
|
|
// NOTE that pattern is loaded such that first byte is lower left
|
|
// therefore, we start at top of 16x16 section and work down
|
|
i=0;
|
|
j=124;
|
|
|
|
#define MIRROR_2(val) (( ((val)&0x1)<<1) | ((val)>>1))
|
|
#define MIRROR_4(val) ((MIRROR_2((val)&0x3)<<2) | MIRROR_2((val)>>2))
|
|
#define MIRROR_8(val) ((MIRROR_4((val)&0xf)<<4) | MIRROR_4((val)>>4))
|
|
|
|
while (i < 8)
|
|
{
|
|
// row N, in lower half of word
|
|
// compute mirror image of row, so 0th bit is LSB instead of MSB
|
|
// therefore we put upper byte in lower and vice versa, and mirror those bytes
|
|
pat[i] = (MIRROR_8(pStipple[j+1])<<8) | (MIRROR_8(pStipple[j]));
|
|
j-=4;
|
|
|
|
// row N+1, in upper half of word
|
|
// compute mirror image of row, so 0th bit is LSB instead of MSB
|
|
// therefore we put upper byte in lower and vice versa, and mirror those bytes
|
|
pat[i] |= (MIRROR_8(pStipple[j+1])<<24) | (MIRROR_8(pStipple[j])<<16);
|
|
j-=4;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
pRc->privateEnables |= __MCDENABLE_PG_STIPPLE;
|
|
|
|
}
|
|
pRc->ppdev->LL_State.pattern_ram_state = PATTERN_RAM_INVALID;
|
|
}
|
|
|
|
if ((z_comp_mode != pRc->Control0.Z_Compare_Mode) ||
|
|
(z_mode != pRc->Control0.Z_Mode))
|
|
{
|
|
pRc->Control0.Z_Compare_Mode = z_comp_mode;
|
|
pRc->Control0.Z_Mode = z_mode;
|
|
control0_set=TRUE;
|
|
}
|
|
|
|
if (_MCDStateenables & MCD_BLEND_ENABLE)
|
|
{
|
|
|
|
// recall alpha mode only meaningful when alpha opcode bit set for primitive being rendered
|
|
|
|
if (frame_scale)
|
|
{
|
|
// "frame scale" type of blend - select light source, and don't enable normal blend
|
|
if( pRc->Control0.Light_Src_Sel != LL_LIGHTING_TEXTURE )
|
|
{
|
|
pRc->Control0.Light_Src_Sel = LL_LIGHTING_TEXTURE;
|
|
control0_set=TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pRc->privateEnables |= __MCDENABLE_BLEND;
|
|
}
|
|
|
|
if( pRc->Control0.Alpha_Dest_Color_Sel != LL_ALPHA_DEST_FRAME )
|
|
{
|
|
pRc->Control0.Alpha_Dest_Color_Sel = LL_ALPHA_DEST_FRAME;
|
|
control0_set=TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// for fog dest_color is const and alpha values are coord's "fog" value
|
|
if (_MCDStateenables & MCD_FOG_ENABLE)
|
|
{
|
|
// FUTURE: determine when to punt on fog
|
|
|
|
pRc->privateEnables |= __MCDENABLE_FOG;
|
|
if( pRc->Control0.Alpha_Dest_Color_Sel != LL_ALPHA_DEST_CONST )
|
|
{
|
|
pRc->Control0.Alpha_Dest_Color_Sel = LL_ALPHA_DEST_CONST;
|
|
control0_set=TRUE;
|
|
}
|
|
|
|
// load fog color into color0 register
|
|
|
|
// QST - is fog density applied to fog color, or to fog values(start,end,etc.)?
|
|
pRc->dwColor0 = (FTOL(pRc->MCDState.fogColor.r * pRc->rScale) & 0xff0000);
|
|
pRc->dwColor0 |= (FTOL(pRc->MCDState.fogColor.g * pRc->gScale) & 0xff0000) >> 8;
|
|
pRc->dwColor0 |= (FTOL(pRc->MCDState.fogColor.b * pRc->bScale) & 0xff0000) >> 16;
|
|
|
|
*pdwNext++ = write_register( COLOR0_3D, 1 );
|
|
*pdwNext++ = pRc->dwColor0;
|
|
}
|
|
}
|
|
|
|
if (pRc->privateEnables & (__MCDENABLE_BLEND|__MCDENABLE_FOG))
|
|
{
|
|
// texture blend may change alpha_mode and alpha_dest_color
|
|
// Note that we will punt before this point if texture blend with normal (blend|fog)
|
|
// since HW can't do both - if we make it here, we just need normal blend|fog
|
|
if (!const_alpha_mode)
|
|
{
|
|
if( pRc->Control0.Alpha_Mode != LL_ALPHA_INTERP )
|
|
{
|
|
pRc->Control0.Alpha_Mode = LL_ALPHA_INTERP;
|
|
control0_set=TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( pRc->Control0.Alpha_Mode != LL_ALPHA_CONST )
|
|
{
|
|
pRc->Control0.Alpha_Mode = LL_ALPHA_CONST;
|
|
control0_set=TRUE;
|
|
|
|
// always SRC=DST=1.0
|
|
*pdwNext++ = write_register( DA_MAIN_3D, 2 );
|
|
*pdwNext++ = 0xff0000;
|
|
*pdwNext++ = 0xff0000;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( (pRc->privateEnables & (__MCDENABLE_BLEND|__MCDENABLE_FOG)) ||
|
|
((pRc->privateEnables & __MCDENABLE_TEXTURE) &&
|
|
(pRc->MCDTexEnvState.texEnvMode == GL_BLEND)) )
|
|
{
|
|
if (!pRc->Control0.Alpha_Blending_Enable)
|
|
{
|
|
pRc->Control0.Alpha_Blending_Enable = TRUE;
|
|
control0_set=TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// alpha blend not used, so turn off if currently on
|
|
if (pRc->Control0.Alpha_Blending_Enable)
|
|
{
|
|
pRc->Control0.Alpha_Blending_Enable = FALSE;
|
|
control0_set=TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
if (frame_scale)
|
|
{
|
|
if(!pRc->Control0.Frame_Scaling_Enable )
|
|
{
|
|
pRc->Control0.Frame_Scaling_Enable = TRUE;
|
|
control0_set=TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( pRc->Control0.Frame_Scaling_Enable )
|
|
{
|
|
pRc->Control0.Frame_Scaling_Enable = FALSE;
|
|
control0_set=TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
// setup for alpha test here...
|
|
// setup for alpha test here...
|
|
// setup for alpha test here...
|
|
// setup for alpha test here...
|
|
// setup for alpha test here...
|
|
// setup for alpha test here...
|
|
|
|
// setup polygon opcode
|
|
pRc->dwPolyOpcode = POLY | 6 | WARP_MODE;
|
|
if (pRc->privateEnables & __MCDENABLE_PG_STIPPLE)
|
|
{
|
|
pRc->dwPolyOpcode |= pRc->privateEnables &
|
|
(__MCDENABLE_SMOOTH | __MCDENABLE_Z |
|
|
__MCDENABLE_TEXTURE | __MCDENABLE_PERSPECTIVE |
|
|
__MCDENABLE_LIGHTING |
|
|
__MCDENABLE_PG_STIPPLE);
|
|
}
|
|
else
|
|
{
|
|
// can dither only if no stipple
|
|
pRc->dwPolyOpcode |= pRc->privateEnables &
|
|
(__MCDENABLE_SMOOTH | __MCDENABLE_Z |
|
|
__MCDENABLE_TEXTURE | __MCDENABLE_PERSPECTIVE |
|
|
__MCDENABLE_LIGHTING |
|
|
__MCDENABLE_DITHER);
|
|
}
|
|
|
|
// setup length and other flags in Opcode
|
|
pRc->dwPolyOpcode += 3; // rgb
|
|
|
|
// assume not flat bottom, will decrease if flat bottom at run time
|
|
pRc->dwPolyOpcode += 2;
|
|
|
|
if (pRc->privateEnables & __MCDENABLE_SMOOTH)
|
|
pRc->dwPolyOpcode += 6; // for rgb, main and ortho slopes - so 6 values
|
|
|
|
if( pRc->privateEnables & __MCDENABLE_Z)
|
|
pRc->dwPolyOpcode += 3;
|
|
|
|
// assume linear, will increase if perspective at run time
|
|
if (pRc->privateEnables & __MCDENABLE_TEXTURE)
|
|
pRc->dwPolyOpcode += 6;
|
|
|
|
// MCD_QST2 -> do we need FETCH_COLOR for Fog?
|
|
if (pRc->privateEnables & (__MCDENABLE_BLEND|__MCDENABLE_FOG))
|
|
{
|
|
if (!const_alpha_mode)
|
|
{
|
|
pRc->dwPolyOpcode += ( FETCH_COLOR | ALPHA + 3 );
|
|
}
|
|
else
|
|
{
|
|
pRc->dwPolyOpcode += ( FETCH_COLOR );
|
|
}
|
|
|
|
}
|
|
|
|
// frame scaling - must fetch frame color
|
|
if (frame_scale) pRc->dwPolyOpcode += ( FETCH_COLOR );
|
|
|
|
// setup line opcode
|
|
pRc->dwLineOpcode = LINE | 5;
|
|
pRc->dwLineOpcode |= pRc->privateEnables & (__MCDENABLE_SMOOTH|__MCDENABLE_Z);
|
|
if (pRc->privateEnables & __MCDENABLE_LINE_STIPPLE)
|
|
{
|
|
pRc->dwLineOpcode |= LL_STIPPLE;
|
|
}
|
|
else
|
|
{
|
|
// can dither only if no stipple
|
|
pRc->dwLineOpcode |= (pRc->privateEnables & __MCDENABLE_DITHER) ;
|
|
}
|
|
|
|
// setup point opcode
|
|
pRc->dwPointOpcode= POINT | 2;
|
|
pRc->dwPointOpcode |= pRc->privateEnables & (__MCDENABLE_Z|__MCDENABLE_DITHER) ;
|
|
|
|
if (control0_set)
|
|
{
|
|
*pdwNext++ = write_register( CONTROL0_3D, 1 );
|
|
*pdwNext++ = pRc->dwControl0;
|
|
}
|
|
|
|
pRc->allPrimFail = FALSE;
|
|
|
|
if (punt_all_points || !PickPointFuncs(pRc)) {
|
|
pRc->primFunc[GL_POINTS] = FailPrimDraw;
|
|
}
|
|
|
|
if (punt_all_lines || !PickLineFuncs(pRc)) {
|
|
pRc->primFunc[GL_LINES] = FailPrimDraw;
|
|
pRc->primFunc[GL_LINE_LOOP] = FailPrimDraw;
|
|
pRc->primFunc[GL_LINE_STRIP] = FailPrimDraw;
|
|
}
|
|
|
|
if (punt_all_polys || !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;
|
|
}
|
|
|
|
// don't send setup info, keep it queued and primitive rendering procs will send
|
|
ppdev->LL_State.pDL->pdwNext=pdwNext;
|
|
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Hardware-specific utility functions:
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
VOID FASTCALL HWSetupClipping(DEVRC *pRc, RECTL *pClip)
|
|
{
|
|
PDEV *ppdev = pRc->ppdev;
|
|
DWORD *pdwNext = ppdev->LL_State.pDL->pdwNext;
|
|
SET_HW_CLIP_REGS(pRc,pdwNext)
|
|
|
|
ppdev->LL_State.pDL->pdwNext = pdwNext;
|
|
|
|
}
|
|
|
|
VOID HWUpdateBufferPos(MCDWINDOW *pMCDWnd, SURFOBJ *pso, BOOL bForce)
|
|
{
|
|
}
|
|
|
|
|
|
BOOL HWAllocResources(MCDWINDOW *pMCDWnd, SURFOBJ *pso,
|
|
BOOL zBufferEnabled,
|
|
BOOL backBufferEnabled)
|
|
{
|
|
DEVWND *pDevWnd = (DEVWND *)pMCDWnd->pvUser;
|
|
PDEV *ppdev = (PDEV *)pso->dhpdev;
|
|
ULONG w, width, height;
|
|
BOOL needFullZBuffer, needFullBackBuffer, tryFullSc;
|
|
BOOL bFullScreen = FALSE;
|
|
POFMHDL pohBackBuffer = NULL;
|
|
POFMHDL pohZBuffer = NULL;
|
|
SIZEL rctsize;
|
|
ULONG alignflag;
|
|
|
|
MCDBG_PRINT("HWAllocResources");
|
|
|
|
width = min(pMCDWnd->clientRect.right - pMCDWnd->clientRect.left,
|
|
(LONG)ppdev->cxScreen);
|
|
height = min(pMCDWnd->clientRect.bottom - pMCDWnd->clientRect.top,
|
|
(LONG)ppdev->cyScreen);
|
|
|
|
// Assume failure:
|
|
|
|
pDevWnd->allocatedBufferHeight = 0;
|
|
pDevWnd->bValidBackBuffer = FALSE;
|
|
pDevWnd->bValidZBuffer = FALSE;
|
|
pDevWnd->pohBackBuffer = NULL;
|
|
pDevWnd->pohZBuffer = NULL;
|
|
|
|
if ((backBufferEnabled) && (!ppdev->cDoubleBufferRef))
|
|
needFullBackBuffer = TRUE;
|
|
else
|
|
needFullBackBuffer = FALSE;
|
|
|
|
if ((zBufferEnabled) && (!ppdev->cZBufferRef))
|
|
needFullZBuffer = TRUE;
|
|
else
|
|
needFullZBuffer = FALSE;
|
|
|
|
tryFullSc = TRUE; // assume we'll try full screen if needed
|
|
|
|
// If very little memory would be left after full screen back and z buffer allocations,
|
|
// any textures would likely be punted - so just allocate per window
|
|
if (needFullBackBuffer || needFullZBuffer)
|
|
{
|
|
// total for fullscreen buffers for front, back, z
|
|
LONG bytes_needed = 3 * ppdev->cyScreen * ppdev->lDeltaScreen;
|
|
|
|
// add space for 128 scan lines of texture memory
|
|
bytes_needed += 128 * ppdev->lDeltaScreen;
|
|
|
|
if (bytes_needed > ppdev->lTotalMem)
|
|
{
|
|
MCDBG_PRINT("HWAllocResources: FullSc alloc won't leave 128 scans for texture, will try window size alloc");
|
|
tryFullSc = FALSE;
|
|
}
|
|
}
|
|
|
|
// NOTE: No need to remove all discardable bitmaps at this point,
|
|
// AllocOffScnMem will call OFS_DiscardMem as required if more mem reqd
|
|
|
|
// If we need a back buffer, first try to allocate a fullscreen one:
|
|
|
|
if (needFullBackBuffer && tryFullSc) {
|
|
|
|
// Allocate the active video buffer space from the off screen memory
|
|
rctsize.cx = ppdev->cxScreen;
|
|
rctsize.cy = ppdev->cyScreen;
|
|
|
|
alignflag = MCD_NO_X_OFFSET; // force block to start at x=0;
|
|
alignflag |= MCD_DRAW_BUFFER_ALLOCATE; // force 32 scanline boundary
|
|
|
|
pohBackBuffer = ppdev->pAllocOffScnMem(ppdev, &rctsize, alignflag, NULL);
|
|
|
|
if (pohBackBuffer) {
|
|
ppdev->pohBackBuffer = pohBackBuffer;
|
|
ppdev->cDoubleBufferRef = 0;
|
|
} else {
|
|
ppdev->pohBackBuffer = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
// If we need a z buffer, first try to allocate a fullscreen z:
|
|
|
|
if (needFullZBuffer && tryFullSc) {
|
|
|
|
// Allocate the active video buffer space from the off screen memory
|
|
rctsize.cx = ppdev->cxScreen;
|
|
rctsize.cy = ppdev->cyScreen;
|
|
|
|
alignflag = MCD_NO_X_OFFSET; // force block to start at x=0;
|
|
alignflag |= MCD_Z_BUFFER_ALLOCATE; // force 16 bpp allocate for Z on 32 scanline boundary
|
|
pohZBuffer = ppdev->pAllocOffScnMem(ppdev, &rctsize, alignflag, NULL);
|
|
|
|
if (pohZBuffer) {
|
|
ppdev->pohZBuffer = pohZBuffer;
|
|
ppdev->cZBufferRef = 0;
|
|
} else {
|
|
ppdev->pohZBuffer = NULL;
|
|
//needFullBackBuffer = FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
// Check if one of our full-screen allocations failed
|
|
if ( (needFullZBuffer && !pohZBuffer) || // fullscreen z tried and failed OR
|
|
(needFullBackBuffer && !pohBackBuffer) ) // fullscreen back tried and failed
|
|
{
|
|
|
|
// Free any resources allocated so far:
|
|
// Note that even if full screen back allocated OK, and room for windowed Z, we
|
|
// still want to free the back and have both windowed. This is so that
|
|
// offset for both can be relative to window, not relative to screen.
|
|
// If windowed back and Z, and drawing done to front (which by definition is full-screen),
|
|
// we'll have to punt since can't do screen relative for visual (front) and window relative
|
|
// for z. Hardware has capability for unique y offsets per buffer, but only on 32
|
|
// scan line boundary. We could adjust buffers, etc. to make this work, but it is believed
|
|
// that drawing to front with windowed z is rare. In such a case, the back buffer likely
|
|
// won't exist, so fullscreen alloc for Z should usually have plenty of room.
|
|
if (pohZBuffer) {
|
|
ppdev->pFreeOffScnMem(ppdev, pohZBuffer);
|
|
ppdev->pohZBuffer = NULL;
|
|
ppdev->cZBufferRef = 0;
|
|
}
|
|
if (pohBackBuffer) {
|
|
ppdev->pFreeOffScnMem(ppdev, pohBackBuffer);
|
|
ppdev->pohBackBuffer = NULL;
|
|
ppdev->cDoubleBufferRef = 0;
|
|
}
|
|
|
|
// Now, try to allocate per-window resources:
|
|
|
|
if (backBufferEnabled) {
|
|
|
|
// MCD_NOTE - should try to use window width here?
|
|
rctsize.cx = width;
|
|
rctsize.cy = height;
|
|
|
|
// don't force block to start at x=0, will increase chance of success
|
|
alignflag = MCD_DRAW_BUFFER_ALLOCATE; // force 32 scanline boundary
|
|
pohBackBuffer = ppdev->pAllocOffScnMem(ppdev, &rctsize, alignflag, NULL);
|
|
|
|
if (!pohBackBuffer) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (zBufferEnabled) {
|
|
|
|
rctsize.cx = width;
|
|
rctsize.cy = height;
|
|
|
|
alignflag = MCD_NO_X_OFFSET; // force block to start at x=0; z buffer can't have x offset
|
|
alignflag |= MCD_Z_BUFFER_ALLOCATE; // force 16 bpp allocate for Z
|
|
pohZBuffer = ppdev->pAllocOffScnMem(ppdev, &rctsize, alignflag, NULL);
|
|
|
|
if (!pohZBuffer) {
|
|
if (pohBackBuffer)
|
|
ppdev->pFreeOffScnMem(ppdev, pohBackBuffer);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
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;
|
|
|
|
#if DBG
|
|
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->lDeltaScreen;
|
|
|
|
// Calculate back buffer variables:
|
|
|
|
if (backBufferEnabled) {
|
|
ULONG y;
|
|
ULONG offset;
|
|
|
|
// Set up base position, etc.
|
|
|
|
pDevWnd->backBufferY = pDevWnd->backBufferBaseY = pohBackBuffer->aligned_y;
|
|
pDevWnd->backBufferOffset = pDevWnd->backBufferBase =
|
|
(pohBackBuffer->aligned_y * ppdev->lDeltaScreen) + pohBackBuffer->aligned_x;
|
|
pDevWnd->backBufferPitch = ppdev->lDeltaScreen;
|
|
pDevWnd->bValidBackBuffer = TRUE;
|
|
}
|
|
|
|
if (zBufferEnabled) {
|
|
|
|
ASSERTDD(pohZBuffer->aligned_x == 0,
|
|
"Z buffer should be 0-aligned");
|
|
|
|
pDevWnd->zBufferBaseY = pohZBuffer->aligned_y;
|
|
pDevWnd->zBufferBase = pohZBuffer->aligned_y * ppdev->lDeltaScreen;
|
|
pDevWnd->zBufferOffset = pDevWnd->zBufferBase;
|
|
|
|
// QST: Possible problem - if 8 bit frame and 16 bit Z, frame pitch may be less
|
|
// QST: than needed to accomodate 16 bit z???
|
|
pDevWnd->zPitch = ppdev->lDeltaScreen;
|
|
pDevWnd->bValidZBuffer = TRUE;
|
|
}
|
|
|
|
if (bFullScreen)
|
|
{
|
|
pDevWnd->allocatedBufferWidth = ppdev->cxScreen;
|
|
pDevWnd->allocatedBufferHeight = ppdev->cyScreen;
|
|
}
|
|
else
|
|
{
|
|
pDevWnd->allocatedBufferWidth = width;
|
|
pDevWnd->allocatedBufferHeight = height;
|
|
}
|
|
|
|
MCDBG_PRINT("HWAllocResources OK");
|
|
|
|
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) {
|
|
MCDBG_PRINT("MCDrvTrackWindow: Free global z buffer");
|
|
ppdev->pFreeOffScnMem(ppdev, ppdev->pohZBuffer);
|
|
ppdev->pohZBuffer = NULL;
|
|
|
|
}
|
|
} else {
|
|
MCDBG_PRINT("MCDrvTrackWindow: Free local z buffer");
|
|
ppdev->pFreeOffScnMem(ppdev, pDevWnd->pohZBuffer);
|
|
}
|
|
}
|
|
|
|
if (pDevWnd->pohBackBuffer) {
|
|
if (ppdev->cDoubleBufferRef) {
|
|
if (!--ppdev->cDoubleBufferRef) {
|
|
MCDBG_PRINT("MCDrvTrackWindow: Free global color buffer");
|
|
ppdev->pFreeOffScnMem(ppdev, ppdev->pohBackBuffer);
|
|
ppdev->pohBackBuffer = NULL;
|
|
}
|
|
} else {
|
|
MCDBG_PRINT("MCDrvTrackWindow: Free local color buffer");
|
|
ppdev->pFreeOffScnMem(ppdev, pDevWnd->pohBackBuffer);
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID ContextSwitch(DEVRC *pRc)
|
|
|
|
{
|
|
DWORD *pdwNext = pRc->ppdev->LL_State.pDL->pdwNext;
|
|
|
|
// set control reg0
|
|
*pdwNext++ = write_register( CONTROL0_3D, 1 );
|
|
*pdwNext++ = pRc->dwControl0;
|
|
|
|
// set tx control 0, and texture xy base
|
|
*pdwNext++ = write_register( TX_CTL0_3D, 2 );
|
|
*pdwNext++ = pRc->dwTxControl0;
|
|
*pdwNext++ = pRc->dwTxXYBase;
|
|
|
|
// set color0
|
|
*pdwNext++ = write_register( COLOR0_3D, 1 );
|
|
*pdwNext++ = pRc->dwColor0;
|
|
|
|
// set to trigger next op that touches window to set base0 and base1 regs
|
|
pRc->pLastDevWnd = NULL;
|
|
pRc->pLastTexture = TEXTURE_NOT_LOADED;
|
|
pRc->ppdev->LL_State.pattern_ram_state = PATTERN_RAM_INVALID;
|
|
|
|
pRc->ppdev->pLastDevRC = (ULONG)pRc;
|
|
|
|
pRc->ppdev->LL_State.pDL->pdwNext = pdwNext;
|
|
|
|
}
|
|
|