void CHWTessellator::QuadProcessTessFactors()

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;
}