in d3d/archive/images/d3d11/tessellator.cpp [1023:1187]
void CHWTessellator::TriProcessTessFactors( float tessFactor_Ueq0, float tessFactor_Veq0, float tessFactor_Weq0,
float insideTessFactor, PROCESSED_TESS_FACTORS_TRI& processedTessFactors )
{
// Is the patch culled?
if( !(tessFactor_Ueq0 > 0) || // NaN will pass
!(tessFactor_Veq0 > 0) ||
!(tessFactor_Weq0 > 0) )
{
processedTessFactors.bPatchCulled = true;
return;
}
else
{
processedTessFactors.bPatchCulled = false;
}
// Clamp edge TessFactors
float lowerBound, upperBound;
switch(m_originalPartitioning)
{
case D3D11_TESSELLATOR_PARTITIONING_INTEGER:
case D3D11_TESSELLATOR_PARTITIONING_POW2: // don�t care about pow2 distinction for validation, just treat as integer
lowerBound = D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR;
upperBound = D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR;
break;
case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN:
lowerBound = D3D11_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR;
upperBound = D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR;
break;
case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD:
lowerBound = D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR;
upperBound = D3D11_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR;
break;
}
tessFactor_Ueq0 = fmin( upperBound, fmax( lowerBound, tessFactor_Ueq0 ) );
tessFactor_Veq0 = fmin( upperBound, fmax( lowerBound, tessFactor_Veq0 ) );
tessFactor_Weq0 = fmin( upperBound, fmax( lowerBound, tessFactor_Weq0 ) );
if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)
{
tessFactor_Ueq0 = ceil(tessFactor_Ueq0);
tessFactor_Veq0 = ceil(tessFactor_Veq0);
tessFactor_Weq0 = ceil(tessFactor_Weq0);
}
// Clamp inside TessFactors
if(D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD == m_originalPartitioning)
{
if( (tessFactor_Ueq0 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||
(tessFactor_Veq0 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||
(tessFactor_Weq0 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON))
// Don't need the same check for insideTessFactor for tri patches,
// since there is only one insideTessFactor, as opposed to quad
// patches which have 2 insideTessFactors.
{
// Force picture frame
lowerBound = D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR + EPSILON;
}
}
insideTessFactor = fmin( upperBound, fmax( lowerBound, insideTessFactor ) );
// Note the above clamps map NaN to lowerBound
if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)
{
insideTessFactor = ceil(insideTessFactor);
}
// Reset our vertex and index buffers. We have enough storage for the max tessFactor.
m_NumPoints = 0;
m_NumIndices = 0;
// Process tessFactors
float outsideTessFactor[TRI_EDGES] = {tessFactor_Ueq0, tessFactor_Veq0, tessFactor_Weq0};
int edge;
if( HWIntegerPartitioning() )
{
for( edge = 0; edge < TRI_EDGES; edge++ )
{
int edgeEven = isEven(outsideTessFactor[edge]);
processedTessFactors.outsideTessFactorParity[edge] = edgeEven ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
}
processedTessFactors.insideTessFactorParity = (isEven(insideTessFactor) || (FLOAT_ONE == insideTessFactor))
? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
}
else
{
for( edge = 0; edge < TRI_EDGES; edge++ )
{
processedTessFactors.outsideTessFactorParity[edge] = m_originalParity;
}
processedTessFactors.insideTessFactorParity = m_originalParity;
}
// Save fixed point TessFactors
for( edge = 0; edge < TRI_EDGES; edge++ )
{
processedTessFactors.outsideTessFactor[edge] = floatToFixed(outsideTessFactor[edge]);
}
processedTessFactors.insideTessFactor = floatToFixed(insideTessFactor);
if( HWIntegerPartitioning() || Odd() )
{
// Special case if all TessFactors are 1
if( (FXP_ONE == processedTessFactors.insideTessFactor) &&
(FXP_ONE == processedTessFactors.outsideTessFactor[Ueq0]) &&
(FXP_ONE == processedTessFactors.outsideTessFactor[Veq0]) &&
(FXP_ONE == processedTessFactors.outsideTessFactor[Weq0]) )
{
processedTessFactors.bJustDoMinimumTessFactor = true;
return;
}
}
processedTessFactors.bJustDoMinimumTessFactor = false;
// Compute per-TessFactor metadata
for(edge = 0; edge < TRI_EDGES; edge++ )
{
SetTessellationParity(processedTessFactors.outsideTessFactorParity[edge]);
ComputeTessFactorContext(processedTessFactors.outsideTessFactor[edge], processedTessFactors.outsideTessFactorCtx[edge]);
}
SetTessellationParity(processedTessFactors.insideTessFactorParity);
ComputeTessFactorContext(processedTessFactors.insideTessFactor, processedTessFactors.insideTessFactorCtx);
// Compute some initial data.
// outside edge offsets and storage
for(edge = 0; edge < TRI_EDGES; edge++ )
{
SetTessellationParity(processedTessFactors.outsideTessFactorParity[edge]);
processedTessFactors.numPointsForOutsideEdge[edge] = NumPointsForTessFactor(processedTessFactors.outsideTessFactor[edge]);
m_NumPoints += processedTessFactors.numPointsForOutsideEdge[edge];
}
m_NumPoints -= 3;
// inside edge offsets
SetTessellationParity(processedTessFactors.insideTessFactorParity);
processedTessFactors.numPointsForInsideTessFactor = NumPointsForTessFactor(processedTessFactors.insideTessFactor);
{
int pointCountMin = Odd() ? 4 : 3;
// max() allows degenerate transition regions when inside TessFactor == 1
processedTessFactors.numPointsForInsideTessFactor = max(pointCountMin,processedTessFactors.numPointsForInsideTessFactor);
}
processedTessFactors.insideEdgePointBaseOffset = m_NumPoints;
// inside storage, including interior edges above
{
int numInteriorRings = (processedTessFactors.numPointsForInsideTessFactor >> 1) - 1;
int numInteriorPoints;
if( Odd() )
{
numInteriorPoints = TRI_EDGES*(numInteriorRings*(numInteriorRings+1) - numInteriorRings);
}
else
{
numInteriorPoints = TRI_EDGES*(numInteriorRings*(numInteriorRings+1)) + 1;
}
m_NumPoints += numInteriorPoints;
}
}