|
|
//----------------------------------------------------------------------------
//
// walk.cpp
//
// TriProcessor edge walking methods.
//
// Copyright (C) Microsoft Corporation, 1997.
//
//----------------------------------------------------------------------------
#include "rgb_pch.h"
#pragma hdrstop
#include "d3dutil.h"
#include "setup.hpp"
#include "attrs_mh.h"
#include "tstp_mh.h"
#include "walk_mh.h"
#include "rsdbg.hpp"
DBG_DECLARE_FILE();
//----------------------------------------------------------------------------
//
// WalkTrapEitherSpans_Any_Clip
//
// Walks the given number of spans, using edge 0 - 2 as the attribute
// edge and the given X and DXDY for the other edge.
// Spans are clipped in X against the current clip rect.
//
// The spans can be split into subspans if required. cPixSplit indicates
// the maximum length span that should be recorded. Any longer spans will
// be cut into multiple span segments.
//
// Calls attribute handler functions so all attributes are supported.
// Attributes are never touched directly so both fixed and float are supported.
//
//----------------------------------------------------------------------------
HRESULT FASTCALL WalkTrapEitherSpans_Any_Clip(UINT uSpans, PINTCARRYVAL pXOther, PSETUPCTX pStpCtx, BOOL bAdvanceLast) { PD3DI_RASTSPAN pSpan; HRESULT hr; INT cTotalPix; INT cPix; INT uX, uXO; BOOL b20Valid; UINT uSpansAvail;
RSASSERT(uSpans > 0); hr = DD_OK; uSpansAvail = 0; for (;;) { //
// Clip span and compute length. No attributes need to be
// updated here because attributes have already been moved
// inside the clip boundary.
//
uX = pStpCtx->X20.iV; uXO = pXOther->iV; b20Valid = TRUE;
RSDPFM((RSM_WALK, "Full span at Y %d, %d - %d\n", pStpCtx->iY, uX, (pStpCtx->uFlags & TRIF_X_DEC) ? uXO + 1 : uXO - 1)); if (pStpCtx->uFlags & TRIF_X_DEC) { if (uX >= pStpCtx->pCtx->Clip.right) { b20Valid = FALSE; uX = pStpCtx->pCtx->Clip.right - 1; } else if (uX < pStpCtx->pCtx->Clip.left && pStpCtx->X20.iCY <= 0) { // Right edge has crossed the left clip boundary
// travelling left so the remainder of the triangle
// will not be visible.
goto EH_Exit; }
// -1 because this edge is displaced by one.
if (uXO < pStpCtx->pCtx->Clip.left - 1) { uXO = pStpCtx->pCtx->Clip.left - 1; }
cTotalPix = uX - uXO; } else { if (uX < pStpCtx->pCtx->Clip.left) { b20Valid = FALSE; uX = pStpCtx->pCtx->Clip.left; } else if (uX >= pStpCtx->pCtx->Clip.right && pStpCtx->X20.iCY >= 0) { // Left edge has crossed the right clip boundary
// travelling right so the remainder of the triangle
// will not be visible.
goto EH_Exit; }
if (uXO > pStpCtx->pCtx->Clip.right) { uXO = pStpCtx->pCtx->Clip.right; }
cTotalPix = uXO - uX; }
if (cTotalPix > 0) { ATTRSET Attr; PATTRSET pAttr;
// Start without PWL support since the first iteration doesn't
// have precomputed values.
pStpCtx->uPwlFlags = 0; pAttr = &pStpCtx->Attr; for (;;) { if (uSpansAvail == 0) { // We don't really have a good number to request
// since uSpans could result in any number of span
// fragments after dicing. Using uSpans is OK
// as long as uSpans is relatively large, but if
// uSpans gets small and there's a lot of dicing then
// it would result in excessive AllocSpans calls.
// Try to avoid this problem by lower-bounding the
// request. Any excess spans will be given back
// at the end.
uSpansAvail = min< UINT>(8, uSpans); hr = ALLOC_SPANS(pStpCtx, &uSpansAvail, &pSpan); if (hr != DD_OK) { // uSpansAvail is set to zero on failure.
goto EH_Exit; } } else { pSpan++; } uSpansAvail--; pStpCtx->pPrim->uSpans++;
// Split up remaining pixels if necessary.
cPix = min(cTotalPix, pStpCtx->cMaxSpan);
pSpan->uPix = (UINT16)cPix; pSpan->uX = (UINT16)uX; pSpan->uY = (UINT16)pStpCtx->iY;
RSDPFM((RSM_WALK, " Seg at Y %d, X %d, %c%d pix (%d, %d)\n", pStpCtx->iY, uX, (pStpCtx->uFlags & TRIF_X_DEC) ? '-' : '+', cPix, cTotalPix, pStpCtx->cMaxSpan));
pStpCtx->pfnFillSpanAttrs(pAttr, pSpan, pStpCtx, cPix);
cTotalPix -= cPix; if (cTotalPix <= 0) { break; }
// There are still pixels left in the span so the loop's
// going to go around again. Update all the attribute
// values by cPix dX steps.
//
// We don't want to update the real edge attributes so we
// need to work with a copy. We do this lazily to
// avoid the data movement for the normal case where
// the span isn't split.
if (pAttr == &pStpCtx->Attr) { Attr = pStpCtx->Attr; pAttr = &Attr; }
if (pStpCtx->uFlags & TRIF_X_DEC) { uX -= cPix; } else { uX += cPix; } pStpCtx->pfnAddScaledAttrs(pAttr, &pStpCtx->DAttrDX, pStpCtx, cPix); } }
uSpans--;
// If this is truly the last span of the triangle then we can stop,
// but if it's just the last span of the top trapezoid then we
// still need to advance the attributes on the long edge so
// they're correct for the next trapzoid's first span.
if (!bAdvanceLast && uSpans == 0) { break; }
//
// Advance long edge and all attributes.
//
pStpCtx->iY++; PATTRSET pDelta;
pStpCtx->X20.iFrac += pStpCtx->X20.iDFrac; if (pStpCtx->X20.iFrac < 0) { // Carry step.
pStpCtx->X20.iV += pStpCtx->X20.iCY; pStpCtx->X20.iFrac &= 0x7fffffff; pDelta = &pStpCtx->DAttrCY; } else { // No-carry step.
pStpCtx->X20.iV += pStpCtx->X20.iNC; pDelta = &pStpCtx->DAttrNC; }
// See if the edge has crossed a clip boundary.
cPix = 0; if (b20Valid) { // Always take a normal step.
pStpCtx->pfnAddAttrs(&pStpCtx->Attr, pDelta, pStpCtx);
// See if the edge crossed out of the clip rect and if so,
// how far.
if (pStpCtx->uFlags & TRIF_X_DEC) { if (pStpCtx->X20.iV >= pStpCtx->pCtx->Clip.right) { cPix = pStpCtx->X20.iV - (pStpCtx->pCtx->Clip.right - 1); } } else { if (pStpCtx->X20.iV < pStpCtx->pCtx->Clip.left) { cPix = pStpCtx->pCtx->Clip.left - pStpCtx->X20.iV; } } } else { // Always step in Y.
pStpCtx->pfnAddAttrs(&pStpCtx->Attr, &pStpCtx->DAttrDY, pStpCtx);
// See if the edge crossed into validity and if so,
// how far.
if (pStpCtx->uFlags & TRIF_X_DEC) { if (pStpCtx->X20.iV < pStpCtx->pCtx->Clip.right - 1) { cPix = (pStpCtx->pCtx->Clip.right - 1) - pStpCtx->X20.iV; } } else { if (pStpCtx->X20.iV > pStpCtx->pCtx->Clip.left) { cPix = pStpCtx->X20.iV - pStpCtx->pCtx->Clip.left; } } }
if (cPix > 0) { // The edge made a validity transition. Either the
// attributes are sitting back at the edge of validity and
// need to move forward or they've left the clip rect and
// need to move back. Either way, cPix has the
// number of pixels to move in X.
// No precomputed values.
pStpCtx->uPwlFlags = 0; pStpCtx->pfnAddScaledAttrs(&pStpCtx->Attr, &pStpCtx->DAttrDX, pStpCtx, cPix); }
// Long edge updating is done so we can always stop here if we're out
// of spans.
if (uSpans == 0) { break; }
// Advance other edge.
pXOther->iFrac += pXOther->iDFrac; if (pXOther->iFrac < 0) { // Carry step.
pXOther->iV += pXOther->iCY; pXOther->iFrac &= 0x7fffffff; } else { // No-carry step.
pXOther->iV += pXOther->iNC; } }
EH_Exit: if (uSpansAvail > 0) { FREE_SPANS(pStpCtx, uSpansAvail); } return hr; }
//----------------------------------------------------------------------------
//
// WalkTrapEitherSpans_Any_NoClip
//
// WalkTrapSpans specialized for the trivial-accept clipping case.
// Span dicing is also unsupported.
// Calls attribute handler functions so all attributes are supported.
// Attributes are never touched directly so both fixed and float are supported.
//
//----------------------------------------------------------------------------
HRESULT FASTCALL WalkTrapEitherSpans_Any_NoClip(UINT uSpans, PINTCARRYVAL pXOther, PSETUPCTX pStpCtx, BOOL bAdvanceLast) { PD3DI_RASTSPAN pSpan; HRESULT hr; PINTCARRYVAL pXLeft, pXRight; UINT uSpansAvail;
RSASSERT(uSpans > 0); hr = DD_OK;
if (pStpCtx->uFlags & TRIF_X_DEC) { pXLeft = pXOther; pXRight = &pStpCtx->X20; } else { pXLeft = &pStpCtx->X20; pXRight = pXOther; }
uSpansAvail = 0;
for (;;) { if (pXRight->iV > pXLeft->iV) { if (uSpansAvail == 0) { uSpansAvail = uSpans; hr = ALLOC_SPANS(pStpCtx, &uSpansAvail, &pSpan); if (hr != DD_OK) { // uSpansAvail is set to zero on failure.
goto EH_Exit; } } else { pSpan++; } uSpansAvail--; pStpCtx->pPrim->uSpans++;
pSpan->uPix = (UINT16)(pXRight->iV - pXLeft->iV); pSpan->uX = (UINT16)pStpCtx->X20.iV; pSpan->uY = (UINT16)pStpCtx->iY;
RSDPFM((RSM_WALK, "Span at Y %d, X %d, %c%d pix\n", pStpCtx->iY, pSpan->uX, (pStpCtx->uFlags & TRIF_X_DEC) ? '-' : '+', pSpan->uPix));
pStpCtx->uPwlFlags = 0; pStpCtx->pfnFillSpanAttrs(&pStpCtx->Attr, pSpan, pStpCtx, 1); }
uSpans--;
// If this is truly the last span of the triangle then we can stop,
// but if it's just the last span of the top trapezoid then we
// still need to advance the attributes on the long edge so
// they're correct for the next trapzoid's first span.
if (!bAdvanceLast && uSpans == 0) { break; }
//
// Advance long edge and all attributes.
//
pStpCtx->iY++; PATTRSET pDelta;
pStpCtx->X20.iFrac += pStpCtx->X20.iDFrac; if (pStpCtx->X20.iFrac < 0) { // Carry step.
pStpCtx->X20.iV += pStpCtx->X20.iCY; pStpCtx->X20.iFrac &= 0x7fffffff; pDelta = &pStpCtx->DAttrCY; } else { // No-carry step.
pStpCtx->X20.iV += pStpCtx->X20.iNC; pDelta = &pStpCtx->DAttrNC; }
pStpCtx->pfnAddAttrs(&pStpCtx->Attr, pDelta, pStpCtx);
// Long edge updating is done so we can always stop here if we're out
// of spans.
if (uSpans == 0) { break; }
// Advance other edge.
pXOther->iFrac += pXOther->iDFrac; if (pXOther->iFrac < 0) { // Carry step.
pXOther->iV += pXOther->iCY; pXOther->iFrac &= 0x7fffffff; } else { // No-carry step.
pXOther->iV += pXOther->iNC; } }
EH_Exit: if (uSpansAvail > 0) { FREE_SPANS(pStpCtx, uSpansAvail); } return hr; }
//
// Tables of edge walkers.
// Indexing is with the low four TRISF_*_USED bits.
//
#if !defined(_X86_) || defined(X86_CPP_WALKTRAPSPANS)
#define WalkTrapFloatSpans_Z_Diff_NoClip WalkTrapEitherSpans_Any_NoClip
#define WalkTrapFloatSpans_Z_Diff_Spec_NoClip WalkTrapEitherSpans_Any_NoClip
#define WalkTrapFloatSpans_Z_Diff_Tex_NoClip WalkTrapEitherSpans_Any_NoClip
#define WalkTrapFloatSpans_Z_Diff_Spec_Tex_NoClip \
WalkTrapEitherSpans_Any_NoClip #define WalkTrapFloatSpans_Z_Tex_NoClip WalkTrapEitherSpans_Any_NoClip
#define WalkTrapFloatSpans_Z_DIdx_NoClip WalkTrapEitherSpans_Any_NoClip
#define WalkTrapFloatSpans_Z_DIdx_Tex_NoClip WalkTrapEitherSpans_Any_NoClip
#define WalkTrapFloatSpans_Z_Tex_NoClip WalkTrapEitherSpans_Any_NoClip
#define WalkTrapFixedSpans_Z_Diff_NoClip WalkTrapEitherSpans_Any_NoClip
#define WalkTrapFixedSpans_Z_Diff_Spec_NoClip WalkTrapEitherSpans_Any_NoClip
#define WalkTrapFixedSpans_Z_Diff_Tex_NoClip WalkTrapEitherSpans_Any_NoClip
#define WalkTrapFixedSpans_Z_Diff_Spec_Tex_NoClip \
WalkTrapEitherSpans_Any_NoClip #define WalkTrapFixedSpans_Z_Tex_NoClip WalkTrapEitherSpans_Any_NoClip
#define WalkTrapFixedSpans_Z_DIdx_NoClip WalkTrapEitherSpans_Any_NoClip
#define WalkTrapFixedSpans_Z_DIdx_Tex_NoClip WalkTrapEitherSpans_Any_NoClip
#define WalkTrapFixedSpans_Z_Tex_NoClip WalkTrapEitherSpans_Any_NoClip
#endif
// Trivial accept walkers.
PFN_WALKTRAPSPANS g_pfnWalkTrapFloatSpansNoClipTable[] = { (PFN_WALKTRAPSPANS)DebugBreakFn, /* 0: -2 -1 -S -D */ WalkTrapFloatSpans_Z_Diff_NoClip, /* 1: -2 -1 -S +D */ (PFN_WALKTRAPSPANS)DebugBreakFn, /* 2: -2 -1 +S -D */ WalkTrapFloatSpans_Z_Diff_Spec_NoClip, /* 3: -2 -1 +S +D */ (PFN_WALKTRAPSPANS)DebugBreakFn, /* 4: -2 +1 -S -D */ WalkTrapFloatSpans_Z_Diff_Tex_NoClip, /* 5: -2 +1 -S +D */ (PFN_WALKTRAPSPANS)DebugBreakFn, /* 6: -2 +1 +S -D */ WalkTrapFloatSpans_Z_Diff_Spec_Tex_NoClip, /* 7: -2 +1 +S +D */ (PFN_WALKTRAPSPANS)DebugBreakFn, /* 8: +2 -1 -S -D */ (PFN_WALKTRAPSPANS)DebugBreakFn, /* 9: +2 -1 -S +D */ (PFN_WALKTRAPSPANS)DebugBreakFn, /* A: +2 -1 +S -D */ (PFN_WALKTRAPSPANS)DebugBreakFn, /* B: +2 -1 +S +D */ WalkTrapFloatSpans_Z_Tex_NoClip, /* C: +2 +1 -S -D */ (PFN_WALKTRAPSPANS)DebugBreakFn, /* D: +2 +1 -S +D */ (PFN_WALKTRAPSPANS)DebugBreakFn, /* E: +2 +1 +S -D */ (PFN_WALKTRAPSPANS)DebugBreakFn, /* F: +2 +1 +S +D */ }; #ifdef STEP_FIXED
PFN_WALKTRAPSPANS g_pfnWalkTrapFixedSpansNoClipTable[] = { (PFN_WALKTRAPSPANS)DebugBreakFn, /* 0: -2 -1 -S -D */ WalkTrapFixedSpans_Z_Diff_NoClip, /* 1: -2 -1 -S +D */ (PFN_WALKTRAPSPANS)DebugBreakFn, /* 2: -2 -1 +S -D */ WalkTrapFixedSpans_Z_Diff_Spec_NoClip, /* 3: -2 -1 +S +D */ (PFN_WALKTRAPSPANS)DebugBreakFn, /* 4: -2 +1 -S -D */ WalkTrapFixedSpans_Z_Diff_Tex_NoClip, /* 5: -2 +1 -S +D */ (PFN_WALKTRAPSPANS)DebugBreakFn, /* 6: -2 +1 +S -D */ WalkTrapFixedSpans_Z_Diff_Spec_Tex_NoClip, /* 7: -2 +1 +S +D */ (PFN_WALKTRAPSPANS)DebugBreakFn, /* 8: +2 -1 -S -D */ (PFN_WALKTRAPSPANS)DebugBreakFn, /* 9: +2 -1 -S +D */ (PFN_WALKTRAPSPANS)DebugBreakFn, /* A: +2 -1 +S -D */ (PFN_WALKTRAPSPANS)DebugBreakFn, /* B: +2 -1 +S +D */ WalkTrapFixedSpans_Z_Tex_NoClip, /* C: +2 +1 -S -D */ (PFN_WALKTRAPSPANS)DebugBreakFn, /* D: +2 +1 -S +D */ (PFN_WALKTRAPSPANS)DebugBreakFn, /* E: +2 +1 +S -D */ (PFN_WALKTRAPSPANS)DebugBreakFn, /* F: +2 +1 +S +D */ }; #endif
// Ramp mode trivial accept walkers.
PFN_WALKTRAPSPANS g_pfnRampWalkTrapFloatSpansNoClipTable[] = { (PFN_WALKTRAPSPANS)DebugBreakFn, /* 0: -I -1 */ WalkTrapFloatSpans_Z_Tex_NoClip, /* 1: -I +1 */ WalkTrapFloatSpans_Z_DIdx_NoClip, /* 2: +I -1 */ WalkTrapFloatSpans_Z_DIdx_Tex_NoClip, /* 3: +I +1 */ };
|