in d3d/archive/images/d3d11/tessellator.cpp [504:681]
void CHWTessellator::QuadProcessTessFactors( float tessFactor_Ueq0, float tessFactor_Veq0, float tessFactor_Ueq1, float tessFactor_Veq1,
float insideTessFactor_U, float insideTessFactor_V, PROCESSED_TESS_FACTORS_QUAD& processedTessFactors )
{
// Is the patch culled?
if( !(tessFactor_Ueq0 > 0) || // NaN will pass
!(tessFactor_Veq0 > 0) ||
!(tessFactor_Ueq1 > 0) ||
!(tessFactor_Veq1 > 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_Ueq1 = fmin( upperBound, fmax( lowerBound, tessFactor_Ueq1 ) );
tessFactor_Veq1 = fmin( upperBound, fmax( lowerBound, tessFactor_Veq1 ) );
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_Ueq1 = ceil(tessFactor_Ueq1);
tessFactor_Veq1 = ceil(tessFactor_Veq1);
}
// Clamp inside TessFactors
if(D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD == m_originalPartitioning)
{
#define EPSILON 0.0000152587890625f // 2^(-16), min positive fixed point fraction
#define MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON (D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR + EPSILON/2)
// If any TessFactor will end up > 1 after floatToFixed conversion later,
// then force the inside TessFactors to be > 1 so there is a picture frame.
if( (tessFactor_Ueq0 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||
(tessFactor_Veq0 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||
(tessFactor_Ueq1 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||
(tessFactor_Veq1 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||
(insideTessFactor_U > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||
(insideTessFactor_V > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) )
{
// Force picture frame
lowerBound = D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR + EPSILON;
}
}
insideTessFactor_U = fmin( upperBound, fmax( lowerBound, insideTessFactor_U ) );
insideTessFactor_V = fmin( upperBound, fmax( lowerBound, insideTessFactor_V ) );
// 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_U = ceil(insideTessFactor_U);
insideTessFactor_V = ceil(insideTessFactor_V);
}
// Reset our vertex and index buffers. We have enough storage for the max tessFactor.
m_NumPoints = 0;
m_NumIndices = 0;
// Process tessFactors
float outsideTessFactor[QUAD_EDGES] = {tessFactor_Ueq0, tessFactor_Veq0, tessFactor_Ueq1, tessFactor_Veq1};
float insideTessFactor[QUAD_AXES] = {insideTessFactor_U,insideTessFactor_V};
int edge, axis;
if( HWIntegerPartitioning() )
{
for( edge = 0; edge < QUAD_EDGES; edge++ )
{
int edgeEven = isEven(outsideTessFactor[edge]);
processedTessFactors.outsideTessFactorParity[edge] = edgeEven ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
}
for( axis = 0; axis < QUAD_AXES; axis++ )
{
processedTessFactors.insideTessFactorParity[axis] =
(isEven(insideTessFactor[axis]) || (FLOAT_ONE == insideTessFactor[axis]) )
? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
}
}
else
{
for( edge = 0; edge < QUAD_EDGES; edge++ )
{
processedTessFactors.outsideTessFactorParity[edge] = m_originalParity;
}
processedTessFactors.insideTessFactorParity[U] = processedTessFactors.insideTessFactorParity[V] = m_originalParity;
}
// Save fixed point TessFactors
for( edge = 0; edge < QUAD_EDGES; edge++ )
{
processedTessFactors.outsideTessFactor[edge] = floatToFixed(outsideTessFactor[edge]);
}
for( axis = 0; axis < QUAD_AXES; axis++ )
{
processedTessFactors.insideTessFactor[axis] = floatToFixed(insideTessFactor[axis]);
}
if( HWIntegerPartitioning() || Odd() )
{
// Special case if all TessFactors are 1
if( (FXP_ONE == processedTessFactors.insideTessFactor[U]) &&
(FXP_ONE == processedTessFactors.insideTessFactor[V]) &&
(FXP_ONE == processedTessFactors.outsideTessFactor[Ueq0]) &&
(FXP_ONE == processedTessFactors.outsideTessFactor[Veq0]) &&
(FXP_ONE == processedTessFactors.outsideTessFactor[Ueq1]) &&
(FXP_ONE == processedTessFactors.outsideTessFactor[Veq1]) )
{
processedTessFactors.bJustDoMinimumTessFactor = true;
return;
}
}
processedTessFactors.bJustDoMinimumTessFactor = false;
// Compute TessFactor-specific metadata
for(int edge = 0; edge < QUAD_EDGES; edge++ )
{
SetTessellationParity(processedTessFactors.outsideTessFactorParity[edge]);
ComputeTessFactorContext(processedTessFactors.outsideTessFactor[edge], processedTessFactors.outsideTessFactorCtx[edge]);
}
for(int axis = 0; axis < QUAD_AXES; axis++)
{
SetTessellationParity(processedTessFactors.insideTessFactorParity[axis]);
ComputeTessFactorContext(processedTessFactors.insideTessFactor[axis], processedTessFactors.insideTessFactorCtx[axis]);
}
// Compute some initial data.
// outside edge offsets and storage
for(int edge = 0; edge < QUAD_EDGES; edge++ )
{
SetTessellationParity(processedTessFactors.outsideTessFactorParity[edge]);
processedTessFactors.numPointsForOutsideEdge[edge] = NumPointsForTessFactor(processedTessFactors.outsideTessFactor[edge]);
m_NumPoints += processedTessFactors.numPointsForOutsideEdge[edge];
}
m_NumPoints -= 4;
// inside edge offsets
for(int axis = 0; axis < QUAD_AXES; axis++)
{
SetTessellationParity(processedTessFactors.insideTessFactorParity[axis]);
processedTessFactors.numPointsForInsideTessFactor[axis] = NumPointsForTessFactor(processedTessFactors.insideTessFactor[axis]);
int pointCountMin = ( TESSELLATOR_PARITY_ODD == processedTessFactors.insideTessFactorParity[axis] ) ? 4 : 3;
// max() allows degenerate transition regions when inside TessFactor == 1
processedTessFactors.numPointsForInsideTessFactor[axis] = max(pointCountMin,processedTessFactors.numPointsForInsideTessFactor[axis]);
}
processedTessFactors.insideEdgePointBaseOffset = m_NumPoints;
// inside storage, including interior edges above
int numInteriorPoints = (processedTessFactors.numPointsForInsideTessFactor[U] - 2)*(processedTessFactors.numPointsForInsideTessFactor[V]-2);
m_NumPoints += numInteriorPoints;
}