1/*
2    Copyright (c) Microsoft Corporation
3
4    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
5    associated documentation files (the "Software"), to deal in the Software without restriction,
6    including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7    and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8    subject to the following conditions:
9
10    The above copyright notice and this permission notice shall be included in all copies or substantial
11    portions of the Software.
12
13    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
14    NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
15    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
16    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
17    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18*/
19
20#include "tessellator.hpp"
21#include "util/macros.h"
22#if defined(_MSC_VER)
23#include <math.h> // ceil
24#else
25#include <cmath>
26#endif
27#define min(x,y) (x < y ? x : y)
28#define max(x,y) (x > y ? x : y)
29
30//=================================================================================================================================
31// Some D3D Compliant Float Math (reference rasterizer implements these in RefALU class)
32//=================================================================================================================================
33//
34//---------------------------------------------------------------------------------------------------------------------------------
35// isNaN
36//---------------------------------------------------------------------------------------------------------------------------------
37
38union fiu {
39    float f;
40    int i;
41};
42
43static bool tess_isNaN( float a )
44{
45    static const int exponentMask = 0x7f800000;
46    static const int mantissaMask = 0x007fffff;
47    union fiu fiu;
48    fiu.f = a;
49    return ( ( ( fiu.i & exponentMask ) == exponentMask ) && ( fiu.i & mantissaMask ) ); // NaN
50}
51
52//---------------------------------------------------------------------------------------------------------------------------------
53// flush (denorm)
54//---------------------------------------------------------------------------------------------------------------------------------
55static float tess_flush( float a )
56{
57    static const int minNormalizedFloat = 0x00800000;
58    static const int signBit = 0x80000000;
59    static const int signBitComplement = 0x7fffffff;
60    union fiu fiu, uif;
61    fiu.f = a;
62    int b = fiu.i & signBitComplement; // fabs()
63    if( b < minNormalizedFloat ) // UINT comparison. NaN/INF do test false here
64    {
65        b = signBit & (fiu.i);
66        uif.i = b;
67        return uif.f;
68    }
69    return a;
70}
71
72//---------------------------------------------------------------------------------------------------------------------------------
73// IEEE754R min
74//---------------------------------------------------------------------------------------------------------------------------------
75static float tess_fmin( float a, float b )
76{
77    float _a = tess_flush( a );
78    float _b = tess_flush( b );
79    if( tess_isNaN( _b ) )
80    {
81        return a;
82    }
83    else if( ( _a == 0 ) && ( _b == 0 ) )
84    {
85        union fiu fiu;
86        fiu.f = _a;
87        return ( fiu.i & 0x80000000 ) ? a : b;
88    }
89    return _a < _b ? a : b;
90}
91
92//---------------------------------------------------------------------------------------------------------------------------------
93// IEEE754R max
94//---------------------------------------------------------------------------------------------------------------------------------
95static float tess_fmax( float a, float b )
96{
97    float _a = tess_flush( a );
98    float _b = tess_flush( b );
99
100    if( tess_isNaN( _b ) )
101    {
102        return a;
103    }
104    else if( ( _a == 0 ) && ( _b == 0 ) )
105    {
106        union fiu fiu;
107        fiu.f = _b;
108        return ( fiu.i & 0x80000000 ) ? a : b;
109    }
110    return _a >= _b ? a : b;
111}
112
113//=================================================================================================================================
114// Fixed Point Math
115//=================================================================================================================================
116
117//-----------------------------------------------------------------------------------------------------------------------------
118// floatToFixedPoint
119//
120// Convert 32-bit float to 32-bit fixed point integer, using only
121// integer arithmetic + bitwise operations.
122//
123// c_uIBits:  UINT8     : Width of i (aka. integer bits)
124// c_uFBits:  UINT8     : Width of f (aka. fractional bits)
125// c_bSigned: bool      : Whether the integer bits are a 2's complement signed value
126// input:     float     : All values valid.
127// output:    INT32     : At most 24 bits from LSB are meaningful, depending
128//                        on the fixed point bit representation chosen (see
129//                        below).  Extra bits are sign extended from the most
130//                        meaningful bit.
131//
132//-----------------------------------------------------------------------------------------------------------------------------
133
134typedef unsigned char UINT8;
135typedef int INT32;
136template< const UINT8 c_uIBits, const UINT8 c_uFBits, const bool c_bSigned >
137INT32 floatToIDotF( const float& input )
138{
139    // ------------------------------------------------------------------------
140    //                                                output fixed point format
141    // 32-bit result:
142    //
143    //      [sign-extend]i.f
144    //      |              |
145    //      MSB(31)...LSB(0)
146    //
147    //      f               fractional part of the number, an unsigned
148    //                      value with _fxpFracBitCount bits (defined below)
149    //
150    //      .               implied decimal
151    //
152    //      i               integer part of the number, a 2's complement
153    //                      value with _fxpIntBitCount bits (defined below)
154    //
155    //      [sign-extend]   MSB of i conditionally replicated
156    //
157    // ------------------------------------------------------------------------
158    // Define fixed point bit counts
159    //
160
161    // Commenting out C_ASSERT below to minimise #includes:
162    // C_ASSERT( 2 <= c_uIBits && c_uIBits <= 32 && c_uFBits <= 32 && c_uIBits + c_uFBits <= 32 );
163
164    // Define most negative and most positive fixed point values
165    const INT32 c_iMinResult = (c_bSigned ? INT32( -1 ) << (c_uIBits + c_uFBits - 1) : 0);
166    const INT32 c_iMaxResult = ~c_iMinResult;
167
168    // ------------------------------------------------------------------------
169    //                                                constant float properties
170    // ------------------------------------------------------------------------
171    const UINT8 _fltMantissaBitCount = 23;
172    const UINT8 _fltExponentBitCount = 8;
173    const INT32 _fltExponentBias     = (INT32( 1 ) << (_fltExponentBitCount - 1)) - 1;
174    const INT32 _fltHiddenBit        = INT32( 1 ) << _fltMantissaBitCount;
175    const INT32 _fltMantissaMask     = _fltHiddenBit - 1;
176    const INT32 _fltExponentMask     = ((INT32( 1 ) << _fltExponentBitCount) - 1) << _fltMantissaBitCount;
177    const INT32 _fltSignBit          = INT32( 1 ) << (_fltExponentBitCount + _fltMantissaBitCount);
178
179    // ------------------------------------------------------------------------
180    //              define min and max values as floats (clamp to these bounds)
181    // ------------------------------------------------------------------------
182    INT32 _fxpMaxPosValueFloat;
183    INT32 _fxpMaxNegValueFloat;
184
185    if (c_bSigned)
186    {
187        // The maximum positive fixed point value is 2^(i-1) - 2^(-f).
188        // The following constructs the floating point bit pattern for this value,
189        // as long as i >= 2.
190        _fxpMaxPosValueFloat = (_fltExponentBias + c_uIBits - 1) <<_fltMantissaBitCount;
191        const INT32 iShift = _fltMantissaBitCount + 2 - c_uIBits - c_uFBits;
192        if (iShift >= 0)
193        {
194//            assert( iShift < 32 );
195#if defined(_MSC_VER)
196#pragma warning( push )
197#pragma warning( disable : 4293 26452 )
198#endif
199            _fxpMaxPosValueFloat -= INT32( 1 ) << iShift;
200#if defined(_MSC_VER)
201#pragma warning( pop )
202#endif
203        }
204
205        // The maximum negative fixed point value is -2^(i-1).
206        // The following constructs the floating point bit pattern for this value,
207        // as long as i >= 2.
208        // We need this number without the sign bit
209        _fxpMaxNegValueFloat = (_fltExponentBias + c_uIBits - 1) << _fltMantissaBitCount;
210    }
211    else
212    {
213        // The maximum positive fixed point value is 2^(i) - 2^(-f).
214        // The following constructs the floating point bit pattern for this value,
215        // as long as i >= 2.
216        _fxpMaxPosValueFloat = (_fltExponentBias + c_uIBits) <<_fltMantissaBitCount;
217        const INT32 iShift = _fltMantissaBitCount + 1 - c_uIBits - c_uFBits;
218        if (iShift >= 0)
219        {
220//            assert( iShift < 32 );
221#if defined(_MSC_VER)
222#pragma warning( push )
223#pragma warning( disable : 4293 26452 )
224#endif
225            _fxpMaxPosValueFloat -= INT32( 1 ) << iShift;
226#if defined(_MSC_VER)
227#pragma warning( pop )
228#endif
229        }
230
231        // The maximum negative fixed point value is 0.
232        _fxpMaxNegValueFloat = 0;
233    }
234
235    // ------------------------------------------------------------------------
236    //                                                float -> fixed conversion
237    // ------------------------------------------------------------------------
238
239    // ------------------------------------------------------------------------
240    //                                                      examine input float
241    // ------------------------------------------------------------------------
242    INT32 output              = *(INT32*)&input;
243    INT32 unbiasedExponent    = ((output & _fltExponentMask) >> _fltMantissaBitCount) - _fltExponentBias;
244    INT32 isNegative          = output & _fltSignBit;
245
246    // ------------------------------------------------------------------------
247    //                                                                      nan
248    // ------------------------------------------------------------------------
249    if (unbiasedExponent == (_fltExponentBias + 1) && (output & _fltMantissaMask))
250    {
251        // nan converts to 0
252        output = 0;
253    }
254    // ------------------------------------------------------------------------
255    //                                                       too large positive
256    // ------------------------------------------------------------------------
257    else if (!isNegative && output >= _fxpMaxPosValueFloat) // integer compare
258    {
259        output = c_iMaxResult;
260    }
261    // ------------------------------------------------------------------------
262    //                                                       too large negative
263    // ------------------------------------------------------------------------
264                                            // integer compare
265    else if (isNegative && (output & ~_fltSignBit) >= _fxpMaxNegValueFloat)
266    {
267        output = c_iMinResult;
268    }
269    // ------------------------------------------------------------------------
270    //                                                                too small
271    // ------------------------------------------------------------------------
272    else if (unbiasedExponent < -c_uFBits - 1)
273    {
274        // clamp to 0
275        output = 0;
276    }
277    // ------------------------------------------------------------------------
278    //                                                             within range
279    // ------------------------------------------------------------------------
280    else
281    {
282        // copy mantissa, add hidden bit
283        output = (output & _fltMantissaMask) | _fltHiddenBit;
284
285        INT32 extraBits = _fltMantissaBitCount - c_uFBits - unbiasedExponent;
286        if (extraBits >= 0)
287        {
288            // 2's complement if negative
289            if (isNegative)
290            {
291                output = ~output + 1;
292            }
293
294            // From the range checks that led here, it is known that
295            // unbiasedExponent < c_uIBits.  So, at most:
296            // (a) unbiasedExponent == c_uIBits - 1.
297            //
298            // From compile validation above, it is known that
299            // c_uIBits + c_uFBits <= _fltMantissaBitCount + 1).
300            // So, at minimum:
301            // (b) _fltMantissaBitCount == _fxtIntBitCount + c_uFBits - 1
302            //
303            // Substituting (a) and (b) into extraBits calculation above:
304            // extraBits >= (_fxtIntBitCount + c_uFBits - 1)
305            //              - c_uFBits - (c_uIBits - 1)
306            // extraBits >= 0
307            //
308            // Thus we only have to worry about shifting right by 0 or more
309            // bits to get the decimal to the right place, and never have
310            // to shift left.
311
312            INT32 LSB             = 1 << extraBits; // last bit being kept
313            INT32 extraBitsMask   = LSB - 1;
314            INT32 half            = LSB >> 1; // round bias
315
316            // round to nearest-even at LSB
317            if ((output & LSB) || (output & extraBitsMask) > half)
318            {
319                output += half;
320            }
321
322            // shift off the extra bits (sign extending)
323            output >>= extraBits;
324        }
325        else
326        {
327            output <<= -extraBits;
328
329            // 2's complement if negative
330            if (isNegative)
331            {
332                output = ~output + 1;
333            }
334        }
335    }
336    return output;
337}
338//-----------------------------------------------------------------------------------------------------------------------------
339
340#define FXP_INTEGER_BITS 15
341#define FXP_FRACTION_BITS 16
342#define FXP_FRACTION_MASK 0x0000ffff
343#define FXP_INTEGER_MASK 0x7fff0000
344#define FXP_THREE (3<<FXP_FRACTION_BITS)
345#define FXP_ONE (1<<FXP_FRACTION_BITS)
346#define FXP_ONE_THIRD 0x00005555
347#define FXP_TWO_THIRDS 0x0000aaaa
348#define FXP_ONE_HALF   0x00008000
349
350#define FXP_MAX_INPUT_TESS_FACTOR_BEFORE_TRIPLE_AVERAGE 0x55540000 // 1/3 of max fixed point number - 1.  Numbers less than
351                                                    // or equal to this allows avg. reduction on a tri patch
352                                                    // including rounding.
353
354#define FXP_MAX_INPUT_TESS_FACTOR_BEFORE_PAIR_AVERAGE 0x7FFF0000 // 1/2 of max fixed point number - 1.  Numbers less than
355                                                    // or equal to this allows avg. reduction on a quad patch
356                                                    // including rounding.
357
358static const FXP s_fixedReciprocal[PIPE_TESSELLATOR_MAX_TESSELLATION_FACTOR+1] =
359{
360    0xffffffff, // 1/0 is the first entry (unused)
361    0x10000, 0x8000, 0x5555, 0x4000,
362    0x3333, 0x2aab, 0x2492, 0x2000,
363    0x1c72, 0x199a, 0x1746, 0x1555,
364    0x13b1, 0x1249, 0x1111, 0x1000,
365    0xf0f, 0xe39, 0xd79, 0xccd,
366    0xc31, 0xba3, 0xb21, 0xaab,
367    0xa3d, 0x9d9, 0x97b, 0x925,
368    0x8d4, 0x889, 0x842, 0x800,
369    0x7c2, 0x788, 0x750, 0x71c,
370    0x6eb, 0x6bd, 0x690, 0x666,
371    0x63e, 0x618, 0x5f4, 0x5d1,
372    0x5b0, 0x591, 0x572, 0x555,
373    0x539, 0x51f, 0x505, 0x4ec,
374    0x4d5, 0x4be, 0x4a8, 0x492,
375    0x47e, 0x46a, 0x457, 0x444,
376    0x432, 0x421, 0x410, 0x400, // 1/64 is the last entry
377};
378
379#define FLOAT_THREE 3.0f
380#define FLOAT_ONE 1.0f
381
382//---------------------------------------------------------------------------------------------------------------------------------
383// floatToFixed
384//---------------------------------------------------------------------------------------------------------------------------------
385FXP floatToFixed(const float& input)
386{
387    return floatToIDotF< FXP_INTEGER_BITS, FXP_FRACTION_BITS, /*bSigned*/false >( input );
388}
389
390//---------------------------------------------------------------------------------------------------------------------------------
391// fixedToFloat
392//---------------------------------------------------------------------------------------------------------------------------------
393float fixedToFloat(const FXP& input)
394{
395    // not worrying about denorm flushing the float operations (the DX spec behavior for div), since the numbers will not be that small during tessellation.
396    return ((float)(input>>FXP_FRACTION_BITS) + (float)(input&FXP_FRACTION_MASK)/(1<<FXP_FRACTION_BITS));
397}
398
399//---------------------------------------------------------------------------------------------------------------------------------
400// isEven
401//---------------------------------------------------------------------------------------------------------------------------------
402bool isEven(const float& input)
403{
404    return (((int)input) & 1) ? false : true;
405}
406
407//---------------------------------------------------------------------------------------------------------------------------------
408// fxpCeil
409//---------------------------------------------------------------------------------------------------------------------------------
410FXP fxpCeil(const FXP& input)
411{
412    if( input & FXP_FRACTION_MASK )
413    {
414        return (input & FXP_INTEGER_MASK) + FXP_ONE;
415    }
416    return input;
417}
418
419//---------------------------------------------------------------------------------------------------------------------------------
420// fxpFloor
421//---------------------------------------------------------------------------------------------------------------------------------
422FXP fxpFloor(const FXP& input)
423{
424    return (input & FXP_INTEGER_MASK);
425}
426
427//=================================================================================================================================
428// CHWTessellator
429//=================================================================================================================================
430
431//---------------------------------------------------------------------------------------------------------------------------------
432// CHWTessellator::CHWTessellator
433//---------------------------------------------------------------------------------------------------------------------------------
434CHWTessellator::CHWTessellator()
435{
436    m_Point = 0;
437    m_Index = 0;
438    m_NumPoints = 0;
439    m_NumIndices = 0;
440    m_bUsingPatchedIndices = false;
441    m_bUsingPatchedIndices2 = false;
442}
443//---------------------------------------------------------------------------------------------------------------------------------
444// CHWTessellator::~CHWTessellator
445//---------------------------------------------------------------------------------------------------------------------------------
446CHWTessellator::~CHWTessellator()
447{
448    delete [] m_Point;
449    delete [] m_Index;
450}
451
452//---------------------------------------------------------------------------------------------------------------------------------
453// CHWTessellator::Init
454// User calls this.
455//---------------------------------------------------------------------------------------------------------------------------------
456void CHWTessellator::Init(
457    PIPE_TESSELLATOR_PARTITIONING       partitioning,
458    PIPE_TESSELLATOR_OUTPUT_PRIMITIVE   outputPrimitive)
459{
460    if( 0 == m_Point )
461    {
462        m_Point = new DOMAIN_POINT[MAX_POINT_COUNT];
463    }
464    if( 0 == m_Index )
465    {
466        m_Index = new int[MAX_INDEX_COUNT];
467    }
468    m_partitioning = partitioning;
469    m_originalPartitioning = partitioning;
470    switch( partitioning )
471    {
472    case PIPE_TESSELLATOR_PARTITIONING_INTEGER:
473    default:
474        break;
475    case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD:
476        m_parity = TESSELLATOR_PARITY_ODD;
477        break;
478    case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN:
479        m_parity = TESSELLATOR_PARITY_EVEN;
480        break;
481    }
482    m_originalParity = m_parity;
483    m_outputPrimitive = outputPrimitive;
484    m_NumPoints = 0;
485    m_NumIndices = 0;
486}
487//---------------------------------------------------------------------------------------------------------------------------------
488// CHWTessellator::TessellateQuadDomain
489// User calls this
490//---------------------------------------------------------------------------------------------------------------------------------
491void CHWTessellator::TessellateQuadDomain( float tessFactor_Ueq0, float tessFactor_Veq0, float tessFactor_Ueq1, float tessFactor_Veq1,
492                                         float insideTessFactor_U, float insideTessFactor_V )
493{
494    PROCESSED_TESS_FACTORS_QUAD processedTessFactors;
495    QuadProcessTessFactors(tessFactor_Ueq0,tessFactor_Veq0,tessFactor_Ueq1,tessFactor_Veq1,insideTessFactor_U,insideTessFactor_V,processedTessFactors);
496
497    if( processedTessFactors.bPatchCulled )
498    {
499        m_NumPoints = 0;
500        m_NumIndices = 0;
501        return;
502    }
503    else if( processedTessFactors.bJustDoMinimumTessFactor )
504    {
505        DefinePoint(/*U*/0,/*V*/0,/*pointStorageOffset*/0);
506        DefinePoint(/*U*/FXP_ONE,/*V*/0,/*pointStorageOffset*/1);
507        DefinePoint(/*U*/FXP_ONE,/*V*/FXP_ONE,/*pointStorageOffset*/2);
508        DefinePoint(/*U*/0,/*V*/FXP_ONE,/*pointStorageOffset*/3);
509        m_NumPoints = 4;
510
511        switch(m_outputPrimitive)
512        {
513        case PIPE_TESSELLATOR_OUTPUT_TRIANGLE_CW:
514        case PIPE_TESSELLATOR_OUTPUT_TRIANGLE_CCW:
515            // function orients them CCW if needed
516            DefineClockwiseTriangle(0,1,3,/*indexStorageOffset*/0);
517            DefineClockwiseTriangle(1,2,3,/*indexStorageOffset*/3);
518            m_NumIndices = 6;
519            break;
520        case PIPE_TESSELLATOR_OUTPUT_POINT:
521            DumpAllPoints();
522            break;
523        case PIPE_TESSELLATOR_OUTPUT_LINE:
524            DumpAllPointsAsInOrderLineList();
525            break;
526        }
527        return;
528    }
529
530    QuadGeneratePoints(processedTessFactors);
531
532    if( m_outputPrimitive == PIPE_TESSELLATOR_OUTPUT_POINT )
533    {
534        DumpAllPoints();
535        return;
536    }
537    if( m_outputPrimitive == PIPE_TESSELLATOR_OUTPUT_LINE )
538    {
539        DumpAllPointsAsInOrderLineList();
540        return;
541    }
542
543    QuadGenerateConnectivity(processedTessFactors); // can be done in parallel to QuadGeneratePoints()
544}
545
546//---------------------------------------------------------------------------------------------------------------------------------
547// CHWTessellator::QuadProcessTessFactors
548//---------------------------------------------------------------------------------------------------------------------------------
549void CHWTessellator::QuadProcessTessFactors( float tessFactor_Ueq0, float tessFactor_Veq0, float tessFactor_Ueq1, float tessFactor_Veq1,
550                      float insideTessFactor_U, float insideTessFactor_V, PROCESSED_TESS_FACTORS_QUAD& processedTessFactors )
551{
552    // Is the patch culled?
553    if( !(tessFactor_Ueq0 > 0) || // NaN will pass
554        !(tessFactor_Veq0 > 0) ||
555        !(tessFactor_Ueq1 > 0) ||
556        !(tessFactor_Veq1 > 0) )
557    {
558        processedTessFactors.bPatchCulled = true;
559        return;
560    }
561    else
562    {
563        processedTessFactors.bPatchCulled = false;
564    }
565
566    // Clamp edge TessFactors
567    float lowerBound = 0.0, upperBound = 0.0;
568    switch(m_originalPartitioning)
569    {
570        case PIPE_TESSELLATOR_PARTITIONING_INTEGER:
571        case PIPE_TESSELLATOR_PARTITIONING_POW2: // don�t care about pow2 distinction for validation, just treat as integer
572            lowerBound = PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR;
573            upperBound = PIPE_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR;
574            break;
575
576        case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN:
577            lowerBound = PIPE_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR;
578            upperBound = PIPE_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR;
579            break;
580
581        case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD:
582            lowerBound = PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR;
583            upperBound = PIPE_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR;
584            break;
585    }
586
587    tessFactor_Ueq0 = tess_fmin( upperBound, tess_fmax( lowerBound, tessFactor_Ueq0 ) );
588    tessFactor_Veq0 = tess_fmin( upperBound, tess_fmax( lowerBound, tessFactor_Veq0 ) );
589    tessFactor_Ueq1 = tess_fmin( upperBound, tess_fmax( lowerBound, tessFactor_Ueq1 ) );
590    tessFactor_Veq1 = tess_fmin( upperBound, tess_fmax( lowerBound, tessFactor_Veq1 ) );
591
592    if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)
593    {
594        tessFactor_Ueq0 = ceil(tessFactor_Ueq0);
595        tessFactor_Veq0 = ceil(tessFactor_Veq0);
596        tessFactor_Ueq1 = ceil(tessFactor_Ueq1);
597        tessFactor_Veq1 = ceil(tessFactor_Veq1);
598    }
599
600    // Clamp inside TessFactors
601    if(PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD == m_originalPartitioning)
602    {
603#define EPSILON 0.0000152587890625f // 2^(-16), min positive fixed point fraction
604#define MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON (PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR + EPSILON/2)
605        // If any TessFactor will end up > 1 after floatToFixed conversion later,
606        // then force the inside TessFactors to be > 1 so there is a picture frame.
607        if( (tessFactor_Ueq0 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||
608            (tessFactor_Veq0 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||
609            (tessFactor_Ueq1 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||
610            (tessFactor_Veq1 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||
611            (insideTessFactor_U > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||
612            (insideTessFactor_V > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) )
613        {
614            // Force picture frame
615            lowerBound = PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR + EPSILON;
616        }
617    }
618
619    insideTessFactor_U = tess_fmin( upperBound, tess_fmax( lowerBound, insideTessFactor_U ) );
620    insideTessFactor_V = tess_fmin( upperBound, tess_fmax( lowerBound, insideTessFactor_V ) );
621    // Note the above clamps map NaN to lowerBound
622
623
624    if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)
625    {
626        insideTessFactor_U = ceil(insideTessFactor_U);
627        insideTessFactor_V = ceil(insideTessFactor_V);
628    }
629
630    // Reset our vertex and index buffers.  We have enough storage for the max tessFactor.
631    m_NumPoints = 0;
632    m_NumIndices = 0;
633
634    // Process tessFactors
635    float outsideTessFactor[QUAD_EDGES] = {tessFactor_Ueq0, tessFactor_Veq0, tessFactor_Ueq1, tessFactor_Veq1};
636    float insideTessFactor[QUAD_AXES] = {insideTessFactor_U,insideTessFactor_V};
637    int edge, axis;
638    if( HWIntegerPartitioning() )
639    {
640        for( edge = 0; edge < QUAD_EDGES; edge++ )
641        {
642            int edgeEven = isEven(outsideTessFactor[edge]);
643            processedTessFactors.outsideTessFactorParity[edge] = edgeEven ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
644        }
645        for( axis = 0; axis < QUAD_AXES; axis++ )
646        {
647            processedTessFactors.insideTessFactorParity[axis] =
648                (isEven(insideTessFactor[axis]) || (FLOAT_ONE == insideTessFactor[axis]) )
649                ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
650        }
651    }
652    else
653    {
654        for( edge = 0; edge < QUAD_EDGES; edge++ )
655        {
656            processedTessFactors.outsideTessFactorParity[edge] = m_originalParity;
657        }
658        processedTessFactors.insideTessFactorParity[U] = processedTessFactors.insideTessFactorParity[V] = m_originalParity;
659    }
660
661    // Save fixed point TessFactors
662    for( edge = 0; edge < QUAD_EDGES; edge++ )
663    {
664        processedTessFactors.outsideTessFactor[edge] = floatToFixed(outsideTessFactor[edge]);
665    }
666    for( axis = 0; axis < QUAD_AXES; axis++ )
667    {
668        processedTessFactors.insideTessFactor[axis] = floatToFixed(insideTessFactor[axis]);
669    }
670
671    if( HWIntegerPartitioning() || Odd() )
672    {
673        // Special case if all TessFactors are 1
674        if( (FXP_ONE == processedTessFactors.insideTessFactor[U]) &&
675            (FXP_ONE == processedTessFactors.insideTessFactor[V]) &&
676            (FXP_ONE == processedTessFactors.outsideTessFactor[Ueq0]) &&
677            (FXP_ONE == processedTessFactors.outsideTessFactor[Veq0]) &&
678            (FXP_ONE == processedTessFactors.outsideTessFactor[Ueq1]) &&
679            (FXP_ONE == processedTessFactors.outsideTessFactor[Veq1]) )
680        {
681            processedTessFactors.bJustDoMinimumTessFactor = true;
682            return;
683        }
684    }
685    processedTessFactors.bJustDoMinimumTessFactor = false;
686
687    // Compute TessFactor-specific metadata
688    for(int edge = 0; edge < QUAD_EDGES; edge++ )
689    {
690        SetTessellationParity(processedTessFactors.outsideTessFactorParity[edge]);
691        ComputeTessFactorContext(processedTessFactors.outsideTessFactor[edge], processedTessFactors.outsideTessFactorCtx[edge]);
692    }
693
694    for(int axis = 0; axis < QUAD_AXES; axis++)
695    {
696        SetTessellationParity(processedTessFactors.insideTessFactorParity[axis]);
697        ComputeTessFactorContext(processedTessFactors.insideTessFactor[axis], processedTessFactors.insideTessFactorCtx[axis]);
698    }
699
700    // Compute some initial data.
701
702    // outside edge offsets and storage
703    for(int edge = 0; edge < QUAD_EDGES; edge++ )
704    {
705        SetTessellationParity(processedTessFactors.outsideTessFactorParity[edge]);
706        processedTessFactors.numPointsForOutsideEdge[edge] = NumPointsForTessFactor(processedTessFactors.outsideTessFactor[edge]);
707        m_NumPoints += processedTessFactors.numPointsForOutsideEdge[edge];
708    }
709    m_NumPoints -= 4;
710
711    // inside edge offsets
712    for(int axis = 0; axis < QUAD_AXES; axis++)
713    {
714        SetTessellationParity(processedTessFactors.insideTessFactorParity[axis]);
715        processedTessFactors.numPointsForInsideTessFactor[axis] = NumPointsForTessFactor(processedTessFactors.insideTessFactor[axis]);
716        int pointCountMin = ( TESSELLATOR_PARITY_ODD == processedTessFactors.insideTessFactorParity[axis] ) ? 4 : 3;
717        // max() allows degenerate transition regions when inside TessFactor == 1
718        processedTessFactors.numPointsForInsideTessFactor[axis] = max(pointCountMin,processedTessFactors.numPointsForInsideTessFactor[axis]);
719    }
720
721    processedTessFactors.insideEdgePointBaseOffset = m_NumPoints;
722
723    // inside storage, including interior edges above
724    int numInteriorPoints = (processedTessFactors.numPointsForInsideTessFactor[U] - 2)*(processedTessFactors.numPointsForInsideTessFactor[V]-2);
725    m_NumPoints += numInteriorPoints;
726}
727
728//---------------------------------------------------------------------------------------------------------------------------------
729// CHWTessellator::QuadGeneratePoints
730//---------------------------------------------------------------------------------------------------------------------------------
731void CHWTessellator::QuadGeneratePoints( const PROCESSED_TESS_FACTORS_QUAD& processedTessFactors )
732{
733    // Generate exterior ring edge points, clockwise from top-left
734    int pointOffset = 0;
735    int edge;
736    for(edge = 0; edge < QUAD_EDGES; edge++ )
737    {
738        int parity = edge&0x1;
739        int startPoint = 0;
740        int endPoint = processedTessFactors.numPointsForOutsideEdge[edge] - 1;
741        for(int p = startPoint; p < endPoint; p++,pointOffset++) // don't include end, since next edge starts with it.
742        {
743            FXP fxpParam;
744            int q = ((edge==1)||(edge==2)) ? p : endPoint - p; // reverse order
745            SetTessellationParity(processedTessFactors.outsideTessFactorParity[edge]);
746            PlacePointIn1D(processedTessFactors.outsideTessFactorCtx[edge],q,fxpParam);
747            if( parity )
748            {
749                DefinePoint(/*U*/fxpParam,
750                            /*V*/(edge == 3) ? FXP_ONE : 0,
751                            /*pointStorageOffset*/pointOffset);
752            }
753            else
754            {
755                DefinePoint(/*U*/(edge == 2) ? FXP_ONE : 0,
756                            /*V*/fxpParam,
757                            /*pointStorageOffset*/pointOffset);
758            }
759        }
760    }
761
762    // Generate interior ring points, clockwise from (U==0,V==1) (bottom-left) spiralling toward center
763    static const int startRing = 1;
764    int minNumPointsForTessFactor = min(processedTessFactors.numPointsForInsideTessFactor[U],processedTessFactors.numPointsForInsideTessFactor[V]);
765    int numRings = (minNumPointsForTessFactor >> 1);  // note for even tess we aren't counting center point here.
766    for(int ring = startRing; ring < numRings; ring++)
767    {
768        int startPoint = ring;
769        int endPoint[QUAD_AXES] = {processedTessFactors.numPointsForInsideTessFactor[U] - 1 - startPoint,
770                                   processedTessFactors.numPointsForInsideTessFactor[V] - 1 - startPoint};
771
772        for(edge = 0; edge < QUAD_EDGES; edge++ )
773        {
774            int parity[QUAD_AXES] = {edge&0x1,((edge+1)&0x1)};
775            int perpendicularAxisPoint = (edge < 2) ? startPoint : endPoint[parity[0]];
776            FXP fxpPerpParam;
777            SetTessellationParity(processedTessFactors.insideTessFactorParity[parity[0]]);
778            PlacePointIn1D(processedTessFactors.insideTessFactorCtx[parity[0]],perpendicularAxisPoint,fxpPerpParam);
779            SetTessellationParity(processedTessFactors.insideTessFactorParity[parity[1]]);
780            for(int p = startPoint; p < endPoint[parity[1]]; p++, pointOffset++) // don't include end: next edge starts with it.
781            {
782                FXP fxpParam;
783                int q = ((edge == 1)||(edge==2)) ? p : endPoint[parity[1]] - (p - startPoint);
784                PlacePointIn1D(processedTessFactors.insideTessFactorCtx[parity[1]],q,fxpParam);
785                if( parity[1] )
786                {
787                    DefinePoint(/*U*/fxpPerpParam,
788                                /*V*/fxpParam,
789                                /*pointStorageOffset*/pointOffset);
790                }
791                else
792                {
793                    DefinePoint(/*U*/fxpParam,
794                                /*V*/fxpPerpParam,
795                                /*pointStorageOffset*/pointOffset);
796                }
797            }
798        }
799    }
800    // For even tessellation, the inner "ring" is degenerate - a row of points
801    if( (processedTessFactors.numPointsForInsideTessFactor[U] > processedTessFactors.numPointsForInsideTessFactor[V]) &&
802        (TESSELLATOR_PARITY_EVEN == processedTessFactors.insideTessFactorParity[V]) )
803    {
804        int startPoint = numRings;
805        int endPoint = processedTessFactors.numPointsForInsideTessFactor[U] - 1 - startPoint;
806        SetTessellationParity(processedTessFactors.insideTessFactorParity[U]);
807        for( int p = startPoint; p <= endPoint; p++, pointOffset++ )
808        {
809            FXP fxpParam;
810            PlacePointIn1D(processedTessFactors.insideTessFactorCtx[U],p,fxpParam);
811            DefinePoint(/*U*/fxpParam,
812                        /*V*/FXP_ONE_HALF, // middle
813                        /*pointStorageOffset*/pointOffset);
814        }
815    }
816    else if( (processedTessFactors.numPointsForInsideTessFactor[V] >= processedTessFactors.numPointsForInsideTessFactor[U]) &&
817             (TESSELLATOR_PARITY_EVEN == processedTessFactors.insideTessFactorParity[U]) )
818    {
819        int startPoint = numRings;
820        int endPoint;
821        FXP fxpParam;
822        endPoint = processedTessFactors.numPointsForInsideTessFactor[V] - 1 - startPoint;
823        SetTessellationParity(processedTessFactors.insideTessFactorParity[V]);
824        for( int p = endPoint; p >= startPoint; p--, pointOffset++ )
825        {
826            PlacePointIn1D(processedTessFactors.insideTessFactorCtx[V],p,fxpParam);
827            DefinePoint(/*U*/FXP_ONE_HALF, // middle
828                        /*V*/fxpParam,
829                        /*pointStorageOffset*/pointOffset);
830        }
831    }
832}
833//---------------------------------------------------------------------------------------------------------------------------------
834// CHWTessellator::QuadGenerateConnectivity
835//---------------------------------------------------------------------------------------------------------------------------------
836void CHWTessellator::QuadGenerateConnectivity( const PROCESSED_TESS_FACTORS_QUAD& processedTessFactors )
837{
838    // Generate primitives for all the concentric rings, one side at a time for each ring
839    static const int startRing = 1;
840    int numPointRowsToCenter[QUAD_AXES] = {((processedTessFactors.numPointsForInsideTessFactor[U]+1) >> 1),
841                                            ((processedTessFactors.numPointsForInsideTessFactor[V]+1) >> 1)}; // +1 is so even tess includes the center point
842    int numRings = min(numPointRowsToCenter[U],numPointRowsToCenter[V]);
843    int degeneratePointRing[QUAD_AXES] = { // Even partitioning causes degenerate row of points,
844                                           // which results in exceptions to the point ordering conventions
845                                           // when travelling around the rings counterclockwise.
846        (TESSELLATOR_PARITY_EVEN == processedTessFactors.insideTessFactorParity[V]) ? numPointRowsToCenter[V] - 1 : -1,
847        (TESSELLATOR_PARITY_EVEN == processedTessFactors.insideTessFactorParity[U]) ? numPointRowsToCenter[U] - 1 : -1 };
848
849    const TESS_FACTOR_CONTEXT* outsideTessFactorCtx[QUAD_EDGES] = {&processedTessFactors.outsideTessFactorCtx[Ueq0],
850                                                    &processedTessFactors.outsideTessFactorCtx[Veq0],
851                                                    &processedTessFactors.outsideTessFactorCtx[Ueq1],
852                                                    &processedTessFactors.outsideTessFactorCtx[Veq1]};
853    TESSELLATOR_PARITY outsideTessFactorParity[QUAD_EDGES] = {processedTessFactors.outsideTessFactorParity[Ueq0],
854                                                        processedTessFactors.outsideTessFactorParity[Veq0],
855                                                        processedTessFactors.outsideTessFactorParity[Ueq1],
856                                                        processedTessFactors.outsideTessFactorParity[Veq1]};
857    int numPointsForOutsideEdge[QUAD_EDGES] = {processedTessFactors.numPointsForOutsideEdge[Ueq0],
858                                              processedTessFactors.numPointsForOutsideEdge[Veq0],
859                                              processedTessFactors.numPointsForOutsideEdge[Ueq1],
860                                              processedTessFactors.numPointsForOutsideEdge[Veq1]};
861
862    int insideEdgePointBaseOffset = processedTessFactors.insideEdgePointBaseOffset;
863    int outsideEdgePointBaseOffset = 0;
864    int edge;
865    for(int ring = startRing; ring < numRings; ring++)
866    {
867        int numPointsForInsideEdge[QUAD_AXES] = {processedTessFactors.numPointsForInsideTessFactor[U] - 2*ring,
868                                                 processedTessFactors.numPointsForInsideTessFactor[V] - 2*ring};
869
870        int edge0InsidePointBaseOffset = insideEdgePointBaseOffset;
871        int edge0OutsidePointBaseOffset = outsideEdgePointBaseOffset;
872
873        for(edge = 0; edge < QUAD_EDGES; edge++ )
874        {
875            int parity = (edge+1)&0x1;
876
877            int numTriangles = numPointsForInsideEdge[parity] + numPointsForOutsideEdge[edge] - 2;
878            int insideBaseOffset;
879            int outsideBaseOffset;
880            if( edge == 3 ) // We need to patch the indexing so Stitch() can think it sees
881                            // 2 sequentially increasing rows of points, even though we have wrapped around
882                            // to the end of the inner and outer ring's points, so the last point is really
883                            // the first point for the ring.
884                            // We make it so that when Stitch() calls AddIndex(), that function
885                            // will do any necessary index adjustment.
886            {
887                if( ring == degeneratePointRing[parity] )
888                {
889                    m_IndexPatchContext2.baseIndexToInvert = insideEdgePointBaseOffset + 1;
890                    m_IndexPatchContext2.cornerCaseBadValue = outsideEdgePointBaseOffset + numPointsForOutsideEdge[edge] - 1;
891                    m_IndexPatchContext2.cornerCaseReplacementValue = edge0OutsidePointBaseOffset;
892                    m_IndexPatchContext2.indexInversionEndPoint = (m_IndexPatchContext2.baseIndexToInvert << 1) - 1;
893                    insideBaseOffset = m_IndexPatchContext2.baseIndexToInvert;
894                    outsideBaseOffset = outsideEdgePointBaseOffset;
895                    SetUsingPatchedIndices2(true);
896                }
897                else
898                {
899                    m_IndexPatchContext.insidePointIndexDeltaToRealValue    = insideEdgePointBaseOffset;
900                    m_IndexPatchContext.insidePointIndexBadValue            = numPointsForInsideEdge[parity] - 1;
901                    m_IndexPatchContext.insidePointIndexReplacementValue    = edge0InsidePointBaseOffset;
902                    m_IndexPatchContext.outsidePointIndexPatchBase          = m_IndexPatchContext.insidePointIndexBadValue+1; // past inside patched index range
903                    m_IndexPatchContext.outsidePointIndexDeltaToRealValue   = outsideEdgePointBaseOffset
904                                                                                - m_IndexPatchContext.outsidePointIndexPatchBase;
905                    m_IndexPatchContext.outsidePointIndexBadValue           = m_IndexPatchContext.outsidePointIndexPatchBase
906                                                                                + numPointsForOutsideEdge[edge] - 1;
907                    m_IndexPatchContext.outsidePointIndexReplacementValue   = edge0OutsidePointBaseOffset;
908
909                    insideBaseOffset = 0;
910                    outsideBaseOffset = m_IndexPatchContext.outsidePointIndexPatchBase;
911                    SetUsingPatchedIndices(true);
912                }
913            }
914            else if( (edge == 2) && (ring == degeneratePointRing[parity]) )
915            {
916                m_IndexPatchContext2.baseIndexToInvert = insideEdgePointBaseOffset;
917                m_IndexPatchContext2.cornerCaseBadValue = -1; // unused
918                m_IndexPatchContext2.cornerCaseReplacementValue = -1; // unused
919                m_IndexPatchContext2.indexInversionEndPoint = m_IndexPatchContext2.baseIndexToInvert << 1;
920                insideBaseOffset = m_IndexPatchContext2.baseIndexToInvert;
921                outsideBaseOffset = outsideEdgePointBaseOffset;
922                SetUsingPatchedIndices2(true);
923            }
924            else
925            {
926                insideBaseOffset = insideEdgePointBaseOffset;
927                outsideBaseOffset = outsideEdgePointBaseOffset;
928            }
929            if( ring == startRing )
930            {
931                StitchTransition(/*baseIndexOffset: */m_NumIndices,
932                               insideBaseOffset,processedTessFactors.insideTessFactorCtx[parity].numHalfTessFactorPoints,processedTessFactors.insideTessFactorParity[parity],
933                               outsideBaseOffset,outsideTessFactorCtx[edge]->numHalfTessFactorPoints,outsideTessFactorParity[edge]);
934            }
935            else
936            {
937                StitchRegular(/*bTrapezoid*/true, DIAGONALS_MIRRORED,
938                              /*baseIndexOffset: */m_NumIndices,
939                              numPointsForInsideEdge[parity],
940                              insideBaseOffset,outsideBaseOffset);
941            }
942            SetUsingPatchedIndices(false);
943            SetUsingPatchedIndices2(false);
944            m_NumIndices += numTriangles*3;
945            outsideEdgePointBaseOffset += numPointsForOutsideEdge[edge] - 1;
946            if( (edge == 2) && (ring == degeneratePointRing[parity]) )
947            {
948                insideEdgePointBaseOffset -= numPointsForInsideEdge[parity] - 1;
949            }
950            else
951            {
952                insideEdgePointBaseOffset += numPointsForInsideEdge[parity] - 1;
953            }
954            numPointsForOutsideEdge[edge] = numPointsForInsideEdge[parity];
955        }
956        if( startRing == ring )
957        {
958            for(edge = 0; edge < QUAD_EDGES; edge++ )
959            {
960                outsideTessFactorCtx[edge] = &processedTessFactors.insideTessFactorCtx[edge&1];
961                outsideTessFactorParity[edge] = processedTessFactors.insideTessFactorParity[edge&1];
962            }
963        }
964    }
965
966    // Triangulate center - a row of quads if odd
967    // This triangulation may be producing diagonals that are asymmetric about
968    // the center of the patch in this region.
969    if( (processedTessFactors.numPointsForInsideTessFactor[U] > processedTessFactors.numPointsForInsideTessFactor[V]) &&
970        (TESSELLATOR_PARITY_ODD == processedTessFactors.insideTessFactorParity[V] ) )
971    {
972        SetUsingPatchedIndices2(true);
973        int stripNumQuads = (((processedTessFactors.numPointsForInsideTessFactor[U]>>1) - (processedTessFactors.numPointsForInsideTessFactor[V]>>1))<<1)+
974                            ((TESSELLATOR_PARITY_EVEN == processedTessFactors.insideTessFactorParity[U] ) ? 2 : 1);
975        m_IndexPatchContext2.baseIndexToInvert = outsideEdgePointBaseOffset + stripNumQuads + 2;
976        m_IndexPatchContext2.cornerCaseBadValue = m_IndexPatchContext2.baseIndexToInvert;
977        m_IndexPatchContext2.cornerCaseReplacementValue = outsideEdgePointBaseOffset;
978        m_IndexPatchContext2.indexInversionEndPoint = m_IndexPatchContext2.baseIndexToInvert +
979                                                      m_IndexPatchContext2.baseIndexToInvert + stripNumQuads;
980        StitchRegular(/*bTrapezoid*/false,DIAGONALS_INSIDE_TO_OUTSIDE,
981                       /*baseIndexOffset: */m_NumIndices, /*numInsideEdgePoints:*/stripNumQuads+1,
982                       /*insideEdgePointBaseOffset*/m_IndexPatchContext2.baseIndexToInvert,
983                       outsideEdgePointBaseOffset+1);
984        SetUsingPatchedIndices2(false);
985        m_NumIndices += stripNumQuads*6;
986    }
987    else if((processedTessFactors.numPointsForInsideTessFactor[V] >= processedTessFactors.numPointsForInsideTessFactor[U]) &&
988            (TESSELLATOR_PARITY_ODD == processedTessFactors.insideTessFactorParity[U]) )
989    {
990        SetUsingPatchedIndices2(true);
991        int stripNumQuads = (((processedTessFactors.numPointsForInsideTessFactor[V]>>1) - (processedTessFactors.numPointsForInsideTessFactor[U]>>1))<<1)+
992                            ((TESSELLATOR_PARITY_EVEN == processedTessFactors.insideTessFactorParity[V] ) ? 2 : 1);
993        m_IndexPatchContext2.baseIndexToInvert = outsideEdgePointBaseOffset + stripNumQuads + 1;
994        m_IndexPatchContext2.cornerCaseBadValue = -1; // unused
995        m_IndexPatchContext2.indexInversionEndPoint = m_IndexPatchContext2.baseIndexToInvert +
996                                                      m_IndexPatchContext2.baseIndexToInvert + stripNumQuads;
997		DIAGONALS diag = (TESSELLATOR_PARITY_EVEN == processedTessFactors.insideTessFactorParity[V]) ?
998							DIAGONALS_INSIDE_TO_OUTSIDE : DIAGONALS_INSIDE_TO_OUTSIDE_EXCEPT_MIDDLE;
999        StitchRegular(/*bTrapezoid*/false,diag,
1000                       /*baseIndexOffset: */m_NumIndices, /*numInsideEdgePoints:*/stripNumQuads+1,
1001                       /*insideEdgePointBaseOffset*/m_IndexPatchContext2.baseIndexToInvert,
1002                       outsideEdgePointBaseOffset);
1003        SetUsingPatchedIndices2(false);
1004        m_NumIndices += stripNumQuads*6;
1005    }
1006}
1007
1008//---------------------------------------------------------------------------------------------------------------------------------
1009// CHWTessellator::TessellateTriDomain
1010// User calls this
1011//---------------------------------------------------------------------------------------------------------------------------------
1012void CHWTessellator::TessellateTriDomain( float tessFactor_Ueq0, float tessFactor_Veq0, float tessFactor_Weq0,
1013                                        float insideTessFactor )
1014{
1015    PROCESSED_TESS_FACTORS_TRI processedTessFactors;
1016    TriProcessTessFactors(tessFactor_Ueq0,tessFactor_Veq0,tessFactor_Weq0,insideTessFactor,processedTessFactors);
1017
1018    if( processedTessFactors.bPatchCulled )
1019    {
1020        m_NumPoints = 0;
1021        m_NumIndices = 0;
1022        return;
1023    }
1024    else if( processedTessFactors.bJustDoMinimumTessFactor )
1025    {
1026        DefinePoint(/*U*/0,/*V*/FXP_ONE,/*pointStorageOffset*/0); //V=1 (beginning of Ueq0 edge VW)
1027        DefinePoint(/*U*/0,/*V*/0,/*pointStorageOffset*/1); //W=1 (beginning of Veq0 edge WU)
1028        DefinePoint(/*U*/FXP_ONE,/*V*/0,/*pointStorageOffset*/2); //U=1 (beginning of Weq0 edge UV)
1029        m_NumPoints = 3;
1030
1031        switch(m_outputPrimitive)
1032        {
1033        case PIPE_TESSELLATOR_OUTPUT_TRIANGLE_CW:
1034        case PIPE_TESSELLATOR_OUTPUT_TRIANGLE_CCW:
1035            // function orients them CCW if needed
1036            DefineClockwiseTriangle(0,1,2,/*indexStorageBaseOffset*/m_NumIndices);
1037            m_NumIndices = 3;
1038            break;
1039        case PIPE_TESSELLATOR_OUTPUT_POINT:
1040            DumpAllPoints();
1041            break;
1042        case PIPE_TESSELLATOR_OUTPUT_LINE:
1043            DumpAllPointsAsInOrderLineList();
1044            break;
1045        }
1046        return;
1047    }
1048
1049    TriGeneratePoints(processedTessFactors);
1050
1051    if( m_outputPrimitive == PIPE_TESSELLATOR_OUTPUT_POINT )
1052    {
1053        DumpAllPoints();
1054        return;
1055    }
1056    if( m_outputPrimitive == PIPE_TESSELLATOR_OUTPUT_LINE )
1057    {
1058        DumpAllPointsAsInOrderLineList();
1059        return;
1060    }
1061
1062    TriGenerateConnectivity(processedTessFactors); // can be done in parallel to TriGeneratePoints()
1063}
1064
1065//---------------------------------------------------------------------------------------------------------------------------------
1066// CHWTessellator::TriProcessTessFactors
1067//---------------------------------------------------------------------------------------------------------------------------------
1068void CHWTessellator::TriProcessTessFactors( float tessFactor_Ueq0, float tessFactor_Veq0, float tessFactor_Weq0,
1069                                            float insideTessFactor, PROCESSED_TESS_FACTORS_TRI& processedTessFactors )
1070{
1071    // Is the patch culled?
1072    if( !(tessFactor_Ueq0 > 0) || // NaN will pass
1073        !(tessFactor_Veq0 > 0) ||
1074        !(tessFactor_Weq0 > 0) )
1075    {
1076        processedTessFactors.bPatchCulled = true;
1077        return;
1078    }
1079    else
1080    {
1081        processedTessFactors.bPatchCulled = false;
1082    }
1083
1084    // Clamp edge TessFactors
1085    float lowerBound = 0.0, upperBound = 0.0;
1086    switch(m_originalPartitioning)
1087    {
1088        case PIPE_TESSELLATOR_PARTITIONING_INTEGER:
1089        case PIPE_TESSELLATOR_PARTITIONING_POW2: // don�t care about pow2 distinction for validation, just treat as integer
1090            lowerBound = PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR;
1091            upperBound = PIPE_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR;
1092            break;
1093
1094        case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN:
1095            lowerBound = PIPE_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR;
1096            upperBound = PIPE_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR;
1097            break;
1098
1099        case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD:
1100            lowerBound = PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR;
1101            upperBound = PIPE_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR;
1102            break;
1103    }
1104
1105    tessFactor_Ueq0 = tess_fmin( upperBound, tess_fmax( lowerBound, tessFactor_Ueq0 ) );
1106    tessFactor_Veq0 = tess_fmin( upperBound, tess_fmax( lowerBound, tessFactor_Veq0 ) );
1107    tessFactor_Weq0 = tess_fmin( upperBound, tess_fmax( lowerBound, tessFactor_Weq0 ) );
1108
1109    if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)
1110    {
1111        tessFactor_Ueq0 = ceil(tessFactor_Ueq0);
1112        tessFactor_Veq0 = ceil(tessFactor_Veq0);
1113        tessFactor_Weq0 = ceil(tessFactor_Weq0);
1114    }
1115
1116    // Clamp inside TessFactors
1117    if(PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD == m_originalPartitioning)
1118    {
1119        if( (tessFactor_Ueq0 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||
1120            (tessFactor_Veq0 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||
1121            (tessFactor_Weq0 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON))
1122            // Don't need the same check for insideTessFactor for tri patches,
1123            // since there is only one insideTessFactor, as opposed to quad
1124            // patches which have 2 insideTessFactors.
1125        {
1126            // Force picture frame
1127            lowerBound = PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR + EPSILON;
1128        }
1129    }
1130
1131    insideTessFactor = tess_fmin( upperBound, tess_fmax( lowerBound, insideTessFactor ) );
1132    // Note the above clamps map NaN to lowerBound
1133
1134    if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)
1135    {
1136        insideTessFactor = ceil(insideTessFactor);
1137    }
1138
1139    // Reset our vertex and index buffers.  We have enough storage for the max tessFactor.
1140    m_NumPoints = 0;
1141    m_NumIndices = 0;
1142
1143    // Process tessFactors
1144    float outsideTessFactor[TRI_EDGES] = {tessFactor_Ueq0, tessFactor_Veq0, tessFactor_Weq0};
1145    int edge;
1146    if( HWIntegerPartitioning() )
1147    {
1148        for( edge = 0; edge < TRI_EDGES; edge++ )
1149        {
1150            int edgeEven = isEven(outsideTessFactor[edge]);
1151            processedTessFactors.outsideTessFactorParity[edge] = edgeEven ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
1152        }
1153        processedTessFactors.insideTessFactorParity = (isEven(insideTessFactor) || (FLOAT_ONE == insideTessFactor))
1154                                        ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
1155    }
1156    else
1157    {
1158        for( edge = 0; edge < TRI_EDGES; edge++ )
1159        {
1160            processedTessFactors.outsideTessFactorParity[edge] = m_originalParity;
1161        }
1162        processedTessFactors.insideTessFactorParity = m_originalParity;
1163    }
1164
1165    // Save fixed point TessFactors
1166    for( edge = 0; edge < TRI_EDGES; edge++ )
1167    {
1168        processedTessFactors.outsideTessFactor[edge] = floatToFixed(outsideTessFactor[edge]);
1169    }
1170    processedTessFactors.insideTessFactor = floatToFixed(insideTessFactor);
1171
1172    if( HWIntegerPartitioning() || Odd() )
1173    {
1174        // Special case if all TessFactors are 1
1175        if( (FXP_ONE == processedTessFactors.insideTessFactor) &&
1176            (FXP_ONE == processedTessFactors.outsideTessFactor[Ueq0]) &&
1177            (FXP_ONE == processedTessFactors.outsideTessFactor[Veq0]) &&
1178            (FXP_ONE == processedTessFactors.outsideTessFactor[Weq0]) )
1179        {
1180            processedTessFactors.bJustDoMinimumTessFactor = true;
1181            return;
1182        }
1183    }
1184    processedTessFactors.bJustDoMinimumTessFactor = false;
1185
1186    // Compute per-TessFactor metadata
1187    for(edge = 0; edge < TRI_EDGES; edge++ )
1188    {
1189        SetTessellationParity(processedTessFactors.outsideTessFactorParity[edge]);
1190        ComputeTessFactorContext(processedTessFactors.outsideTessFactor[edge], processedTessFactors.outsideTessFactorCtx[edge]);
1191    }
1192    SetTessellationParity(processedTessFactors.insideTessFactorParity);
1193    ComputeTessFactorContext(processedTessFactors.insideTessFactor, processedTessFactors.insideTessFactorCtx);
1194
1195    // Compute some initial data.
1196
1197    // outside edge offsets and storage
1198    for(edge = 0; edge < TRI_EDGES; edge++ )
1199    {
1200        SetTessellationParity(processedTessFactors.outsideTessFactorParity[edge]);
1201        processedTessFactors.numPointsForOutsideEdge[edge] = NumPointsForTessFactor(processedTessFactors.outsideTessFactor[edge]);
1202        m_NumPoints += processedTessFactors.numPointsForOutsideEdge[edge];
1203    }
1204    m_NumPoints -= 3;
1205
1206    // inside edge offsets
1207    SetTessellationParity(processedTessFactors.insideTessFactorParity);
1208    processedTessFactors.numPointsForInsideTessFactor = NumPointsForTessFactor(processedTessFactors.insideTessFactor);
1209    {
1210        int pointCountMin = Odd() ? 4 : 3;
1211        // max() allows degenerate transition regions when inside TessFactor == 1
1212        processedTessFactors.numPointsForInsideTessFactor = max(pointCountMin,processedTessFactors.numPointsForInsideTessFactor);
1213    }
1214
1215    processedTessFactors.insideEdgePointBaseOffset = m_NumPoints;
1216
1217    // inside storage, including interior edges above
1218    {
1219        int numInteriorRings = (processedTessFactors.numPointsForInsideTessFactor >> 1) - 1;
1220        int numInteriorPoints;
1221        if( Odd() )
1222        {
1223            numInteriorPoints = TRI_EDGES*(numInteriorRings*(numInteriorRings+1) - numInteriorRings);
1224        }
1225        else
1226        {
1227            numInteriorPoints = TRI_EDGES*(numInteriorRings*(numInteriorRings+1)) + 1;
1228        }
1229        m_NumPoints += numInteriorPoints;
1230    }
1231
1232}
1233
1234//---------------------------------------------------------------------------------------------------------------------------------
1235// CHWTessellator::TriGeneratePoints
1236//---------------------------------------------------------------------------------------------------------------------------------
1237void CHWTessellator::TriGeneratePoints( const PROCESSED_TESS_FACTORS_TRI& processedTessFactors )
1238{
1239    // Generate exterior ring edge points, clockwise starting from point V (VW, the U==0 edge)
1240    int pointOffset = 0;
1241    int edge;
1242    for(edge = 0; edge < TRI_EDGES; edge++ )
1243    {
1244        int parity = edge&0x1;
1245        int startPoint = 0;
1246        int endPoint = processedTessFactors.numPointsForOutsideEdge[edge] - 1;
1247        for(int p = startPoint; p < endPoint; p++, pointOffset++) // don't include end, since next edge starts with it.
1248        {
1249            FXP fxpParam;
1250            int q = (parity) ? p : endPoint - p; // whether to reverse point order given we are defining V or U (W implicit):
1251                                                 // edge0, VW, has V decreasing, so reverse 1D points below
1252                                                 // edge1, WU, has U increasing, so don't reverse 1D points  below
1253                                                 // edge2, UV, has U decreasing, so reverse 1D points below
1254            SetTessellationParity(processedTessFactors.outsideTessFactorParity[edge]);
1255            PlacePointIn1D(processedTessFactors.outsideTessFactorCtx[edge],q,fxpParam);
1256            if( edge == 0 )
1257            {
1258                DefinePoint(/*U*/0,
1259                            /*V*/fxpParam,
1260                            /*pointStorageOffset*/pointOffset);
1261            }
1262            else
1263            {
1264                DefinePoint(/*U*/fxpParam,
1265                            /*V*/(edge == 2) ? FXP_ONE - fxpParam : 0,
1266                            /*pointStorageOffset*/pointOffset);
1267            }
1268        }
1269    }
1270
1271    // Generate interior ring points, clockwise spiralling in
1272    SetTessellationParity(processedTessFactors.insideTessFactorParity);
1273    static const int startRing = 1;
1274    int numRings = (processedTessFactors.numPointsForInsideTessFactor >> 1);
1275    for(int ring = startRing; ring < numRings; ring++)
1276    {
1277        int startPoint = ring;
1278        int endPoint = processedTessFactors.numPointsForInsideTessFactor - 1 - startPoint;
1279
1280        for(edge = 0; edge < TRI_EDGES; edge++ )
1281        {
1282            int parity = edge&0x1;
1283            int perpendicularAxisPoint = startPoint;
1284            FXP fxpPerpParam;
1285            PlacePointIn1D(processedTessFactors.insideTessFactorCtx,perpendicularAxisPoint,fxpPerpParam);
1286            fxpPerpParam *= FXP_TWO_THIRDS; // Map location to the right size in barycentric space.
1287                                         // I (amarp) can draw a picture to explain.
1288                                         // We know this fixed point math won't over/underflow
1289            fxpPerpParam = (fxpPerpParam+FXP_ONE_HALF/*round*/)>>FXP_FRACTION_BITS; // get back to n.16
1290            for(int p = startPoint; p < endPoint; p++, pointOffset++) // don't include end: next edge starts with it.
1291            {
1292                FXP fxpParam;
1293                int q = (parity) ? p : endPoint - (p - startPoint); // whether to reverse point given we are defining V or U (W implicit):
1294                                                         // edge0, VW, has V decreasing, so reverse 1D points below
1295                                                         // edge1, WU, has U increasing, so don't reverse 1D points  below
1296                                                         // edge2, UV, has U decreasing, so reverse 1D points below
1297                PlacePointIn1D(processedTessFactors.insideTessFactorCtx,q,fxpParam);
1298                // edge0 VW, has perpendicular parameter U constant
1299                // edge1 WU, has perpendicular parameter V constant
1300                // edge2 UV, has perpendicular parameter W constant
1301                const unsigned int deriv = 2; // reciprocal is the rate of change of edge-parallel parameters as they are pushed into the triangle
1302                switch(edge)
1303                {
1304                case 0:
1305                    DefinePoint(/*U*/fxpPerpParam,
1306                                /*V*/fxpParam - (fxpPerpParam+1/*round*/)/deriv, // we know this fixed point math won't over/underflow
1307                                /*pointStorageOffset*/pointOffset);
1308                    break;
1309                case 1:
1310                    DefinePoint(/*U*/fxpParam - (fxpPerpParam+1/*round*/)/deriv,// we know this fixed point math won't over/underflow
1311                                /*V*/fxpPerpParam,
1312                                /*pointStorageOffset*/pointOffset);
1313                    break;
1314                case 2:
1315                    DefinePoint(/*U*/fxpParam - (fxpPerpParam+1/*round*/)/deriv,// we know this fixed point math won't over/underflow
1316                                /*V*/FXP_ONE - (fxpParam - (fxpPerpParam+1/*round*/)/deriv) - fxpPerpParam,// we know this fixed point math won't over/underflow
1317                                /*pointStorageOffset*/pointOffset);
1318                    break;
1319                }
1320            }
1321        }
1322    }
1323    if( !Odd() )
1324    {
1325        // Last point is the point at the center.
1326        DefinePoint(/*U*/FXP_ONE_THIRD,
1327                    /*V*/FXP_ONE_THIRD,
1328                    /*pointStorageOffset*/pointOffset);
1329    }
1330}
1331//---------------------------------------------------------------------------------------------------------------------------------
1332// CHWTessellator::TriGenerateConnectivity
1333//---------------------------------------------------------------------------------------------------------------------------------
1334void CHWTessellator::TriGenerateConnectivity( const PROCESSED_TESS_FACTORS_TRI& processedTessFactors )
1335{
1336    // Generate primitives for all the concentric rings, one side at a time for each ring
1337    static const int startRing = 1;
1338    int numRings = ((processedTessFactors.numPointsForInsideTessFactor+1) >> 1); // +1 is so even tess includes the center point, which we want to now
1339    const TESS_FACTOR_CONTEXT* outsideTessFactorCtx[TRI_EDGES] = {&processedTessFactors.outsideTessFactorCtx[Ueq0],
1340                                            &processedTessFactors.outsideTessFactorCtx[Veq0],
1341                                            &processedTessFactors.outsideTessFactorCtx[Weq0]};
1342    TESSELLATOR_PARITY outsideTessFactorParity[TRI_EDGES] = {processedTessFactors.outsideTessFactorParity[Ueq0],
1343                                            processedTessFactors.outsideTessFactorParity[Veq0],
1344                                            processedTessFactors.outsideTessFactorParity[Weq0]};
1345    int numPointsForOutsideEdge[TRI_EDGES] = {processedTessFactors.numPointsForOutsideEdge[Ueq0],
1346                                              processedTessFactors.numPointsForOutsideEdge[Veq0],
1347                                              processedTessFactors.numPointsForOutsideEdge[Weq0]};
1348
1349    int insideEdgePointBaseOffset = processedTessFactors.insideEdgePointBaseOffset;
1350    int outsideEdgePointBaseOffset = 0;
1351    int edge;
1352    for(int ring = startRing; ring < numRings; ring++)
1353    {
1354        int numPointsForInsideEdge = processedTessFactors.numPointsForInsideTessFactor - 2*ring;
1355        int edge0InsidePointBaseOffset = insideEdgePointBaseOffset;
1356        int edge0OutsidePointBaseOffset = outsideEdgePointBaseOffset;
1357        for(edge = 0; edge < TRI_EDGES; edge++ )
1358        {
1359            int numTriangles = numPointsForInsideEdge + numPointsForOutsideEdge[edge] - 2;
1360
1361            int insideBaseOffset;
1362            int outsideBaseOffset;
1363            if( edge == 2 )
1364            {
1365                m_IndexPatchContext.insidePointIndexDeltaToRealValue    = insideEdgePointBaseOffset;
1366                m_IndexPatchContext.insidePointIndexBadValue            = numPointsForInsideEdge - 1;
1367                m_IndexPatchContext.insidePointIndexReplacementValue    = edge0InsidePointBaseOffset;
1368                m_IndexPatchContext.outsidePointIndexPatchBase          = m_IndexPatchContext.insidePointIndexBadValue+1; // past inside patched index range
1369                m_IndexPatchContext.outsidePointIndexDeltaToRealValue   = outsideEdgePointBaseOffset
1370                                                                            - m_IndexPatchContext.outsidePointIndexPatchBase;
1371                m_IndexPatchContext.outsidePointIndexBadValue           = m_IndexPatchContext.outsidePointIndexPatchBase
1372                                                                            + numPointsForOutsideEdge[edge] - 1;
1373                m_IndexPatchContext.outsidePointIndexReplacementValue   = edge0OutsidePointBaseOffset;
1374                SetUsingPatchedIndices(true);
1375                insideBaseOffset = 0;
1376                outsideBaseOffset = m_IndexPatchContext.outsidePointIndexPatchBase;
1377            }
1378            else
1379            {
1380                insideBaseOffset = insideEdgePointBaseOffset;
1381                outsideBaseOffset = outsideEdgePointBaseOffset;
1382            }
1383            if( ring == startRing )
1384            {
1385                StitchTransition(/*baseIndexOffset: */m_NumIndices,
1386                               insideBaseOffset,processedTessFactors.insideTessFactorCtx.numHalfTessFactorPoints,processedTessFactors.insideTessFactorParity,
1387                               outsideBaseOffset,outsideTessFactorCtx[edge]->numHalfTessFactorPoints,outsideTessFactorParity[edge]);
1388            }
1389            else
1390            {
1391                StitchRegular(/*bTrapezoid*/true, DIAGONALS_MIRRORED,
1392                              /*baseIndexOffset: */m_NumIndices,
1393                              numPointsForInsideEdge,
1394                              insideBaseOffset,outsideBaseOffset);
1395            }
1396            if( 2 == edge )
1397            {
1398                SetUsingPatchedIndices(false);
1399            }
1400            m_NumIndices += numTriangles*3;
1401            outsideEdgePointBaseOffset += numPointsForOutsideEdge[edge] - 1;
1402            insideEdgePointBaseOffset += numPointsForInsideEdge - 1;
1403            numPointsForOutsideEdge[edge] = numPointsForInsideEdge;
1404        }
1405        if( startRing == ring )
1406        {
1407            for(edge = 0; edge < TRI_EDGES; edge++ )
1408            {
1409                outsideTessFactorCtx[edge] = &processedTessFactors.insideTessFactorCtx;
1410                outsideTessFactorParity[edge] = processedTessFactors.insideTessFactorParity;
1411            }
1412        }
1413    }
1414    if( Odd() )
1415    {
1416        // Triangulate center (a single triangle)
1417        DefineClockwiseTriangle(outsideEdgePointBaseOffset, outsideEdgePointBaseOffset+1, outsideEdgePointBaseOffset+2,
1418                       m_NumIndices);
1419        m_NumIndices += 3;
1420    }
1421}
1422
1423//---------------------------------------------------------------------------------------------------------------------------------
1424// CHWTessellator::TessellateIsoLineDomain
1425// User calls this.
1426//---------------------------------------------------------------------------------------------------------------------------------
1427void CHWTessellator::TessellateIsoLineDomain( float TessFactor_V_LineDensity, float TessFactor_U_LineDetail )
1428{
1429    PROCESSED_TESS_FACTORS_ISOLINE processedTessFactors;
1430    IsoLineProcessTessFactors(TessFactor_V_LineDensity,TessFactor_U_LineDetail,processedTessFactors);
1431    if( processedTessFactors.bPatchCulled )
1432    {
1433        m_NumPoints = 0;
1434        m_NumIndices = 0;
1435        return;
1436    }
1437    IsoLineGeneratePoints(processedTessFactors);
1438    IsoLineGenerateConnectivity(processedTessFactors); // can be done in parallel to IsoLineGeneratePoints
1439}
1440
1441//---------------------------------------------------------------------------------------------------------------------------------
1442// CHWTessellator::IsoLineProcessTessFactors
1443//---------------------------------------------------------------------------------------------------------------------------------
1444void CHWTessellator::IsoLineProcessTessFactors( float TessFactor_V_LineDensity, float TessFactor_U_LineDetail,
1445                                                PROCESSED_TESS_FACTORS_ISOLINE& processedTessFactors )
1446{
1447    // Is the patch culled?
1448    if( !(TessFactor_V_LineDensity > 0) || // NaN will pass
1449        !(TessFactor_U_LineDetail > 0) )
1450    {
1451        processedTessFactors.bPatchCulled = true;
1452        return;
1453    }
1454    else
1455    {
1456        processedTessFactors.bPatchCulled = false;
1457    }
1458
1459    // Clamp edge TessFactors
1460    float lowerBound = 0.0, upperBound = 0.0;
1461    switch(m_originalPartitioning)
1462    {
1463        case PIPE_TESSELLATOR_PARTITIONING_INTEGER:
1464        case PIPE_TESSELLATOR_PARTITIONING_POW2: // don�t care about pow2 distinction for validation, just treat as integer
1465            lowerBound = PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR;
1466            upperBound = PIPE_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR;
1467            break;
1468
1469        case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN:
1470            lowerBound = PIPE_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR;
1471            upperBound = PIPE_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR;
1472            break;
1473
1474        case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD:
1475            lowerBound = PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR;
1476            upperBound = PIPE_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR;
1477            break;
1478    }
1479
1480    TessFactor_V_LineDensity = tess_fmin( PIPE_TESSELLATOR_MAX_ISOLINE_DENSITY_TESSELLATION_FACTOR,
1481                                    tess_fmax( PIPE_TESSELLATOR_MIN_ISOLINE_DENSITY_TESSELLATION_FACTOR, TessFactor_V_LineDensity ) );
1482    TessFactor_U_LineDetail = tess_fmin( upperBound, tess_fmax( lowerBound, TessFactor_U_LineDetail ) );
1483
1484    // Reset our vertex and index buffers.  We have enough storage for the max tessFactor.
1485    m_NumPoints = 0;
1486    m_NumIndices = 0;
1487
1488    // Process tessFactors
1489    if( HWIntegerPartitioning() )
1490    {
1491        TessFactor_U_LineDetail = ceil(TessFactor_U_LineDetail);
1492        processedTessFactors.lineDetailParity = isEven(TessFactor_U_LineDetail) ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
1493    }
1494    else
1495    {
1496        processedTessFactors.lineDetailParity = m_originalParity;
1497    }
1498
1499    FXP fxpTessFactor_U_LineDetail = floatToFixed(TessFactor_U_LineDetail);
1500
1501    SetTessellationParity(processedTessFactors.lineDetailParity);
1502
1503    ComputeTessFactorContext(fxpTessFactor_U_LineDetail, processedTessFactors.lineDetailTessFactorCtx);
1504    processedTessFactors.numPointsPerLine = NumPointsForTessFactor(fxpTessFactor_U_LineDetail);
1505
1506    OverridePartitioning(PIPE_TESSELLATOR_PARTITIONING_INTEGER);
1507
1508    TessFactor_V_LineDensity = ceil(TessFactor_V_LineDensity);
1509    processedTessFactors.lineDensityParity = isEven(TessFactor_V_LineDensity) ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
1510    SetTessellationParity(processedTessFactors.lineDensityParity);
1511    FXP fxpTessFactor_V_LineDensity = floatToFixed(TessFactor_V_LineDensity);
1512    ComputeTessFactorContext(fxpTessFactor_V_LineDensity, processedTessFactors.lineDensityTessFactorCtx);
1513
1514    processedTessFactors.numLines = NumPointsForTessFactor(fxpTessFactor_V_LineDensity) - 1; // don't draw last line at V == 1.
1515
1516    RestorePartitioning();
1517
1518    // Compute some initial data.
1519
1520    // outside edge offsets
1521    m_NumPoints = processedTessFactors.numPointsPerLine * processedTessFactors.numLines;
1522    if( m_outputPrimitive == PIPE_TESSELLATOR_OUTPUT_POINT )
1523    {
1524        m_NumIndices = m_NumPoints;
1525    }
1526    else // line
1527    {
1528        m_NumIndices = processedTessFactors.numLines*(processedTessFactors.numPointsPerLine-1)*2;
1529    }
1530}
1531
1532//---------------------------------------------------------------------------------------------------------------------------------
1533// CHWTessellator::IsoLineGeneratePoints
1534//---------------------------------------------------------------------------------------------------------------------------------
1535void CHWTessellator::IsoLineGeneratePoints( const PROCESSED_TESS_FACTORS_ISOLINE& processedTessFactors )
1536{
1537    int line, pointOffset;
1538    for(line = 0, pointOffset = 0; line < processedTessFactors.numLines; line++)
1539    {
1540        for(int point = 0; point < processedTessFactors.numPointsPerLine; point++)
1541        {
1542            FXP fxpU,fxpV;
1543            SetTessellationParity(processedTessFactors.lineDensityParity);
1544            PlacePointIn1D(processedTessFactors.lineDensityTessFactorCtx,line,fxpV);
1545
1546            SetTessellationParity(processedTessFactors.lineDetailParity);
1547            PlacePointIn1D(processedTessFactors.lineDetailTessFactorCtx,point,fxpU);
1548
1549            DefinePoint(fxpU,fxpV,pointOffset++);
1550        }
1551    }
1552}
1553
1554//---------------------------------------------------------------------------------------------------------------------------------
1555// CHWTessellator::IsoLineGenerateConnectivity
1556//---------------------------------------------------------------------------------------------------------------------------------
1557void CHWTessellator::IsoLineGenerateConnectivity( const PROCESSED_TESS_FACTORS_ISOLINE& processedTessFactors )
1558{
1559    int line, pointOffset, indexOffset;
1560    if( m_outputPrimitive == PIPE_TESSELLATOR_OUTPUT_POINT )
1561    {
1562        for(line = 0, pointOffset = 0, indexOffset = 0; line < processedTessFactors.numLines; line++)
1563        {
1564            for(int point = 0; point < processedTessFactors.numPointsPerLine; point++)
1565            {
1566                DefineIndex(pointOffset++,indexOffset++);
1567            }
1568        }
1569    }
1570    else // line
1571    {
1572        for(line = 0, pointOffset = 0, indexOffset = 0; line < processedTessFactors.numLines; line++)
1573        {
1574            for(int point = 0; point < processedTessFactors.numPointsPerLine; point++)
1575            {
1576                if( point > 0 )
1577                {
1578                    DefineIndex(pointOffset-1,indexOffset++);
1579                    DefineIndex(pointOffset,indexOffset++);
1580                }
1581                pointOffset++;
1582            }
1583        }
1584    }
1585}
1586
1587//---------------------------------------------------------------------------------------------------------------------------------
1588// CHWTessellator::GetPointCount
1589// User calls this.
1590//---------------------------------------------------------------------------------------------------------------------------------
1591int CHWTessellator::GetPointCount()
1592{
1593    return m_NumPoints;
1594}
1595
1596//---------------------------------------------------------------------------------------------------------------------------------
1597// CHWTessellator::GetIndexCount()
1598// User calls this.
1599//---------------------------------------------------------------------------------------------------------------------------------
1600int CHWTessellator::GetIndexCount()
1601{
1602    return m_NumIndices;
1603}
1604
1605//---------------------------------------------------------------------------------------------------------------------------------
1606// CHWTessellator::GetPoints()
1607// User calls this.
1608//---------------------------------------------------------------------------------------------------------------------------------
1609DOMAIN_POINT* CHWTessellator::GetPoints()
1610{
1611    return m_Point;
1612}
1613//---------------------------------------------------------------------------------------------------------------------------------
1614// CHWTessellator::GetIndices()
1615// User calls this.
1616//---------------------------------------------------------------------------------------------------------------------------------
1617int* CHWTessellator::GetIndices()
1618{
1619    return m_Index;
1620}
1621
1622//---------------------------------------------------------------------------------------------------------------------------------
1623// CHWTessellator::DefinePoint()
1624//---------------------------------------------------------------------------------------------------------------------------------
1625int CHWTessellator::DefinePoint(FXP fxpU, FXP fxpV, int pointStorageOffset)
1626{
1627//    WCHAR foo[80];
1628//    StringCchPrintf(foo,80,L"off:%d, uv=(%f,%f)\n",pointStorageOffset,fixedToFloat(fxpU),fixedToFloat(fxpV));
1629//    OutputDebugString(foo);
1630    m_Point[pointStorageOffset].u = fixedToFloat(fxpU);
1631    m_Point[pointStorageOffset].v = fixedToFloat(fxpV);
1632    return pointStorageOffset;
1633}
1634
1635//---------------------------------------------------------------------------------------------------------------------------------
1636// CHWTessellator::DefineIndex()
1637//--------------------------------------------------------------------------------------------------------------------------------
1638void CHWTessellator::DefineIndex(int index, int indexStorageOffset)
1639{
1640    index = PatchIndexValue(index);
1641//    WCHAR foo[80];
1642//    StringCchPrintf(foo,80,L"off:%d, idx=%d, uv=(%f,%f)\n",indexStorageOffset,index,m_Point[index].u,m_Point[index].v);
1643//    OutputDebugString(foo);
1644    m_Index[indexStorageOffset] = index;
1645}
1646
1647//---------------------------------------------------------------------------------------------------------------------------------
1648// CHWTessellator::DefineClockwiseTriangle()
1649//---------------------------------------------------------------------------------------------------------------------------------
1650void CHWTessellator::DefineClockwiseTriangle(int index0, int index1, int index2, int indexStorageBaseOffset)
1651{
1652    // inputs a clockwise triangle, stores a CW or CCW triangle depending on the state
1653    DefineIndex(index0,indexStorageBaseOffset);
1654    bool bWantClockwise = (m_outputPrimitive == PIPE_TESSELLATOR_OUTPUT_TRIANGLE_CW) ? true : false;
1655    if( bWantClockwise )
1656    {
1657        DefineIndex(index1,indexStorageBaseOffset+1);
1658        DefineIndex(index2,indexStorageBaseOffset+2);
1659    }
1660    else
1661    {
1662        DefineIndex(index2,indexStorageBaseOffset+1);
1663        DefineIndex(index1,indexStorageBaseOffset+2);
1664    }
1665}
1666
1667//---------------------------------------------------------------------------------------------------------------------------------
1668// CHWTessellator::DumpAllPoints()
1669//---------------------------------------------------------------------------------------------------------------------------------
1670void CHWTessellator::DumpAllPoints()
1671{
1672    for( int p = 0; p < m_NumPoints; p++ )
1673    {
1674        DefineIndex(p,m_NumIndices++);
1675    }
1676}
1677
1678//---------------------------------------------------------------------------------------------------------------------------------
1679// CHWTessellator::DumpAllPointsAsInOrderLineList()
1680//---------------------------------------------------------------------------------------------------------------------------------
1681void CHWTessellator::DumpAllPointsAsInOrderLineList()
1682{
1683    for( int p = 1; p < m_NumPoints; p++ )
1684    {
1685        DefineIndex(p-1,m_NumIndices++);
1686        DefineIndex(p,m_NumIndices++);
1687    }
1688}
1689
1690//---------------------------------------------------------------------------------------------------------------------------------
1691// RemoveMSB
1692//---------------------------------------------------------------------------------------------------------------------------------
1693int RemoveMSB(int val)
1694{
1695    int check;
1696    if( val <= 0x0000ffff ) { check = ( val <= 0x000000ff ) ? 0x00000080 : 0x00008000; }
1697    else                    { check = ( val <= 0x00ffffff ) ? 0x00800000 : 0x80000000; }
1698    for( int i = 0; i < 8; i++, check >>= 1 ) { if( val & check ) return (val & ~check); }
1699    return 0;
1700}
1701//---------------------------------------------------------------------------------------------------------------------------------
1702// GetMSB
1703//---------------------------------------------------------------------------------------------------------------------------------
1704int GetMSB(int val)
1705{
1706    int check;
1707    if( val <= 0x0000ffff ) { check = ( val <= 0x000000ff ) ? 0x00000080 : 0x00008000; }
1708    else                    { check = ( val <= 0x00ffffff ) ? 0x00800000 : 0x80000000; }
1709    for( int i = 0; i < 8; i++, check >>= 1 ) { if( val & check ) return check; }
1710    return 0;
1711}
1712
1713//---------------------------------------------------------------------------------------------------------------------------------
1714// CHWTessellator::CleanseParameter()
1715//---------------------------------------------------------------------------------------------------------------------------------
1716/* NOTHING TO DO FOR FIXED POINT ARITHMETIC!
1717void CHWTessellator::CleanseParameter(float& parameter)
1718{
1719    // Clean up [0..1] parameter to guarantee that (1 - (1 - parameter)) == parameter.
1720    parameter = 1.0f - parameter;
1721    parameter = 1.0f - parameter;
1722
1723}
1724*/
1725//---------------------------------------------------------------------------------------------------------------------------------
1726// CHWTessellator::NumPointsForTessFactor()
1727//---------------------------------------------------------------------------------------------------------------------------------
1728int CHWTessellator::NumPointsForTessFactor( FXP fxpTessFactor )
1729{
1730    int numPoints;
1731    if( Odd() )
1732    {
1733        numPoints = (fxpCeil(FXP_ONE_HALF + (fxpTessFactor+1/*round*/)/2)*2)>>FXP_FRACTION_BITS;
1734    }
1735    else
1736    {
1737        numPoints = ((fxpCeil((fxpTessFactor+1/*round*/)/2)*2)>>FXP_FRACTION_BITS)+1;
1738    }
1739    return numPoints;
1740}
1741
1742//---------------------------------------------------------------------------------------------------------------------------------
1743// CHWTessellator::ComputeTessFactorContext()
1744//---------------------------------------------------------------------------------------------------------------------------------
1745void CHWTessellator::ComputeTessFactorContext( FXP fxpTessFactor, TESS_FACTOR_CONTEXT& TessFactorCtx )
1746{
1747    FXP fxpHalfTessFactor = (fxpTessFactor+1/*round*/)/2;
1748    if( Odd() || (fxpHalfTessFactor == FXP_ONE_HALF)) // fxpHalfTessFactor == 1/2 if TessFactor is 1, but we're pretending we are even.
1749    {
1750        fxpHalfTessFactor += FXP_ONE_HALF;
1751    }
1752    FXP fxpFloorHalfTessFactor = fxpFloor(fxpHalfTessFactor);
1753    FXP fxpCeilHalfTessFactor = fxpCeil(fxpHalfTessFactor);
1754    TessFactorCtx.fxpHalfTessFactorFraction = fxpHalfTessFactor - fxpFloorHalfTessFactor;
1755    //CleanseParameter(TessFactorCtx.fxpHalfTessFactorFraction);
1756    TessFactorCtx.numHalfTessFactorPoints = (fxpCeilHalfTessFactor>>FXP_FRACTION_BITS); // for EVEN, we don't include the point always fixed at the midpoint of the TessFactor
1757    if( fxpCeilHalfTessFactor == fxpFloorHalfTessFactor )
1758    {
1759        TessFactorCtx.splitPointOnFloorHalfTessFactor =  /*pick value to cause this to be ignored*/ TessFactorCtx.numHalfTessFactorPoints+1;
1760    }
1761    else if( Odd() )
1762    {
1763        if( fxpFloorHalfTessFactor == FXP_ONE )
1764        {
1765            TessFactorCtx.splitPointOnFloorHalfTessFactor = 0;
1766        }
1767        else
1768        {
1769				TessFactorCtx.splitPointOnFloorHalfTessFactor = (RemoveMSB((fxpFloorHalfTessFactor>>FXP_FRACTION_BITS)-1)<<1) + 1;
1770        }
1771    }
1772    else
1773    {
1774			TessFactorCtx.splitPointOnFloorHalfTessFactor = (RemoveMSB(fxpFloorHalfTessFactor>>FXP_FRACTION_BITS)<<1) + 1;
1775    }
1776    int numFloorSegments = (fxpFloorHalfTessFactor * 2)>>FXP_FRACTION_BITS;
1777    int numCeilSegments = (fxpCeilHalfTessFactor * 2)>>FXP_FRACTION_BITS;
1778    if( Odd() )
1779    {
1780        numFloorSegments -= 1;
1781        numCeilSegments -= 1;
1782    }
1783    TessFactorCtx.fxpInvNumSegmentsOnFloorTessFactor = s_fixedReciprocal[numFloorSegments];
1784    TessFactorCtx.fxpInvNumSegmentsOnCeilTessFactor = s_fixedReciprocal[numCeilSegments];
1785}
1786
1787//---------------------------------------------------------------------------------------------------------------------------------
1788// CHWTessellator::PlacePointIn1D()
1789//---------------------------------------------------------------------------------------------------------------------------------
1790void CHWTessellator::PlacePointIn1D( const TESS_FACTOR_CONTEXT& TessFactorCtx, int point, FXP& fxpLocation )
1791{
1792    bool bFlip;
1793    if( point >= TessFactorCtx.numHalfTessFactorPoints )
1794    {
1795        point = (TessFactorCtx.numHalfTessFactorPoints << 1) - point;
1796        if( Odd() )
1797        {
1798            point -= 1;
1799        }
1800        bFlip = true;
1801    }
1802    else
1803    {
1804        bFlip = false;
1805    }
1806    if( point == TessFactorCtx.numHalfTessFactorPoints )
1807    {
1808        fxpLocation = FXP_ONE_HALF; // special casing middle since 16 bit fixed math below can't reproduce 0.5 exactly
1809        return;
1810    }
1811    unsigned int indexOnCeilHalfTessFactor = point;
1812    unsigned int indexOnFloorHalfTessFactor = indexOnCeilHalfTessFactor;
1813    if( point > TessFactorCtx.splitPointOnFloorHalfTessFactor )
1814    {
1815        indexOnFloorHalfTessFactor -= 1;
1816    }
1817    // For the fixed point multiplies below, we know the results are <= 16 bits because
1818    // the locations on the halfTessFactor are <= half the number of segments for the total TessFactor.
1819    // So a number divided by a number that is at least twice as big will give
1820    // a result no bigger than 0.5 (which in fixed point is 16 bits in our case)
1821    FXP fxpLocationOnFloorHalfTessFactor = indexOnFloorHalfTessFactor * TessFactorCtx.fxpInvNumSegmentsOnFloorTessFactor;
1822    FXP fxpLocationOnCeilHalfTessFactor = indexOnCeilHalfTessFactor * TessFactorCtx.fxpInvNumSegmentsOnCeilTessFactor;
1823
1824    // Since we know the numbers calculated above are <= fixed point 0.5, and the equation
1825    // below is just lerping between two values <= fixed point 0.5 (0x00008000), then we know
1826    // that the final result before shifting by 16 bits is no larger than 0x80000000.  Once we
1827    // shift that down by 16, we get the result of lerping 2 numbers <= 0.5, which is obviously
1828    // at most 0.5 (0x00008000)
1829    fxpLocation = fxpLocationOnFloorHalfTessFactor * (FXP_ONE - TessFactorCtx.fxpHalfTessFactorFraction) +
1830                  fxpLocationOnCeilHalfTessFactor * (TessFactorCtx.fxpHalfTessFactorFraction);
1831    fxpLocation = (fxpLocation + FXP_ONE_HALF/*round*/) >> FXP_FRACTION_BITS; // get back to n.16
1832    /* Commenting out floating point version.  Note the parameter cleansing it does is not needed in fixed point.
1833    if( bFlip )
1834        location = 1.0f - location; // complement produces cleansed result.
1835    else
1836        CleanseParameter(location);
1837    */
1838    if( bFlip )
1839    {
1840        fxpLocation = FXP_ONE - fxpLocation;
1841    }
1842}
1843
1844//---------------------------------------------------------------------------------------------------------------------------------
1845// CHWTessellator::StitchRegular
1846//---------------------------------------------------------------------------------------------------------------------------------
1847void CHWTessellator::StitchRegular(bool bTrapezoid,DIAGONALS diagonals,
1848                                 int baseIndexOffset, int numInsideEdgePoints,
1849                                 int insideEdgePointBaseOffset, int outsideEdgePointBaseOffset)
1850{
1851    int insidePoint = insideEdgePointBaseOffset;
1852    int outsidePoint = outsideEdgePointBaseOffset;
1853    if( bTrapezoid )
1854    {
1855        DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);
1856        baseIndexOffset += 3; outsidePoint++;
1857    }
1858    int p;
1859    switch( diagonals )
1860    {
1861    case DIAGONALS_INSIDE_TO_OUTSIDE:
1862        // Diagonals pointing from inside edge forward towards outside edge
1863        for( p = 0; p < numInsideEdgePoints-1; p++ )
1864        {
1865            DefineClockwiseTriangle(insidePoint,outsidePoint,outsidePoint+1,baseIndexOffset);
1866            baseIndexOffset += 3;
1867
1868            DefineClockwiseTriangle(insidePoint,outsidePoint+1,insidePoint+1,baseIndexOffset);
1869            baseIndexOffset += 3;
1870            insidePoint++; outsidePoint++;
1871        }
1872        break;
1873    case DIAGONALS_INSIDE_TO_OUTSIDE_EXCEPT_MIDDLE: // Assumes ODD tessellation
1874        // Diagonals pointing from outside edge forward towards inside edge
1875
1876        // First half
1877        for( p = 0; p < numInsideEdgePoints/2-1; p++ )
1878        {
1879            DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);
1880            baseIndexOffset += 3;
1881            DefineClockwiseTriangle(insidePoint,outsidePoint+1,insidePoint+1,baseIndexOffset);
1882            baseIndexOffset += 3;
1883            insidePoint++; outsidePoint++;
1884        }
1885
1886        // Middle
1887        DefineClockwiseTriangle(outsidePoint,insidePoint+1,insidePoint,baseIndexOffset);
1888        baseIndexOffset += 3;
1889        DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint+1,baseIndexOffset);
1890        baseIndexOffset += 3;
1891        insidePoint++; outsidePoint++; p+=2;
1892
1893        // Second half
1894        for( ; p < numInsideEdgePoints; p++ )
1895        {
1896            DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);
1897            baseIndexOffset += 3;
1898            DefineClockwiseTriangle(insidePoint,outsidePoint+1,insidePoint+1,baseIndexOffset);
1899            baseIndexOffset += 3;
1900            insidePoint++; outsidePoint++;
1901        }
1902        break;
1903    case DIAGONALS_MIRRORED:
1904        // First half, diagonals pointing from outside of outside edge to inside of inside edge
1905        for( p = 0; p < numInsideEdgePoints/2; p++ )
1906        {
1907            DefineClockwiseTriangle(outsidePoint,insidePoint+1,insidePoint,baseIndexOffset);
1908            baseIndexOffset += 3;
1909            DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint+1,baseIndexOffset);
1910            baseIndexOffset += 3;
1911            insidePoint++; outsidePoint++;
1912        }
1913        // Second half, diagonals pointing from inside of inside edge to outside of outside edge
1914        for( ; p < numInsideEdgePoints-1; p++ )
1915        {
1916            DefineClockwiseTriangle(insidePoint,outsidePoint,outsidePoint+1,baseIndexOffset);
1917            baseIndexOffset += 3;
1918            DefineClockwiseTriangle(insidePoint,outsidePoint+1,insidePoint+1,baseIndexOffset);
1919            baseIndexOffset += 3;
1920            insidePoint++; outsidePoint++;
1921        }
1922        break;
1923    }
1924    if( bTrapezoid )
1925    {
1926        DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);
1927        baseIndexOffset += 3;
1928    }
1929}
1930
1931//---------------------------------------------------------------------------------------------------------------------------------
1932// CHWTessellator::StitchTransition()
1933//---------------------------------------------------------------------------------------------------------------------------------
1934void CHWTessellator::StitchTransition(int baseIndexOffset,
1935                                    int insideEdgePointBaseOffset, int insideNumHalfTessFactorPoints,
1936                                    TESSELLATOR_PARITY insideEdgeTessFactorParity,
1937                                    int outsideEdgePointBaseOffset, int outsideNumHalfTessFactorPoints,
1938                                    TESSELLATOR_PARITY outsideTessFactorParity
1939)
1940{
1941    // Tables to assist in the stitching of 2 rows of points having arbitrary TessFactors.
1942    // The stitching order is governed by Ruler Function vertex split ordering (see external documentation).
1943    //
1944    // The contents of the finalPointPositionTable are where vertex i [0..33] ends up on the half-edge
1945    // at the max tessellation amount given ruler-function split order.
1946    // Recall the other half of an edge is mirrored, so we only need to deal with one half.
1947    // This table is used to decide when to advance a point on the interior or exterior.
1948    // It supports odd TessFactor up to 65 and even TessFactor up to 64.
1949    static const int finalPointPositionTable[33] =
1950            { 0, 32, 16, 8, 17, 4, 18, 9, 19, 2, 20, 10, 21, 5, 22, 11, 23,
1951              1, 24, 12, 25, 6, 26, 13, 27, 3, 28, 14, 29, 7, 30, 15, 31 };
1952
1953    // The loopStart and loopEnd tables below just provide optimal loop bounds for the
1954    // stitching algorithm further below, for any given halfTssFactor.
1955    // There is probably a better way to encode this...
1956
1957    // loopStart[halfTessFactor] encodes the FIRST entry in finalPointPositionTable[] above which is
1958    // less than halfTessFactor.  Exceptions are entry 0 and 1, which are set up to skip the loop.
1959    static const int loopStart[33] =
1960            {1,1,17,9,9,5,5,5,5,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
1961    // loopStart[halfTessFactor] encodes the LAST entry in finalPointPositionTable[] above which is
1962    // less than halfTessFactor.  Exceptions are entry 0 and 1, which are set up to skip the loop.
1963    static const int loopEnd[33] =
1964            {0,0,17,17,25,25,25,25,29,29,29,29,29,29,29,29,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,32};
1965
1966    if( TESSELLATOR_PARITY_ODD == insideEdgeTessFactorParity )
1967    {
1968        insideNumHalfTessFactorPoints -= 1;
1969    }
1970    if( TESSELLATOR_PARITY_ODD == outsideTessFactorParity )
1971    {
1972        outsideNumHalfTessFactorPoints -= 1;
1973    }
1974    // Walk first half
1975    int outsidePoint = outsideEdgePointBaseOffset;
1976    int insidePoint = insideEdgePointBaseOffset;
1977
1978    // iStart,iEnd are a small optimization so the loop below doesn't have to go from 0 up to 31
1979    int iStart = min(loopStart[insideNumHalfTessFactorPoints],loopStart[outsideNumHalfTessFactorPoints]);
1980    int iEnd = max(loopEnd[insideNumHalfTessFactorPoints],loopEnd[outsideNumHalfTessFactorPoints]);
1981
1982    if( finalPointPositionTable[0] < outsideNumHalfTessFactorPoints ) // since we dont' start the loop at 0 below, we need a special case.
1983    {
1984        // Advance outside
1985        DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);
1986        baseIndexOffset += 3; outsidePoint++;
1987    }
1988
1989    for(int i = iStart; i <= iEnd; i++)
1990    {
1991        if( /*(i>0) && <-- not needed since iStart is never 0*/(finalPointPositionTable[i] < insideNumHalfTessFactorPoints))
1992        {
1993            // Advance inside
1994            DefineClockwiseTriangle(insidePoint,outsidePoint,insidePoint+1,baseIndexOffset);
1995            baseIndexOffset += 3; insidePoint++;
1996        }
1997        if((finalPointPositionTable[i] < outsideNumHalfTessFactorPoints))
1998        {
1999            // Advance outside
2000            DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);
2001            baseIndexOffset += 3; outsidePoint++;
2002        }
2003    }
2004
2005    if( (insideEdgeTessFactorParity != outsideTessFactorParity) || (insideEdgeTessFactorParity == TESSELLATOR_PARITY_ODD))
2006    {
2007        if( insideEdgeTessFactorParity == outsideTessFactorParity )
2008        {
2009            // Quad in the middle
2010            DefineClockwiseTriangle(insidePoint,outsidePoint,insidePoint+1,baseIndexOffset);
2011            baseIndexOffset += 3;
2012            DefineClockwiseTriangle(insidePoint+1,outsidePoint,outsidePoint+1,baseIndexOffset);
2013            baseIndexOffset += 3;
2014            insidePoint++;
2015            outsidePoint++;
2016        }
2017        else if( TESSELLATOR_PARITY_EVEN == insideEdgeTessFactorParity )
2018        {
2019            // Triangle pointing inside
2020            DefineClockwiseTriangle(insidePoint,outsidePoint,outsidePoint+1,baseIndexOffset);
2021            baseIndexOffset += 3;
2022            outsidePoint++;
2023        }
2024        else
2025        {
2026            // Triangle pointing outside
2027            DefineClockwiseTriangle(insidePoint,outsidePoint,insidePoint+1,baseIndexOffset);
2028            baseIndexOffset += 3;
2029            insidePoint++;
2030        }
2031    }
2032
2033    // Walk second half.
2034    for(int i = iEnd; i >= iStart; i--)
2035    {
2036        if((finalPointPositionTable[i] < outsideNumHalfTessFactorPoints))
2037        {
2038            // Advance outside
2039            DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);
2040            baseIndexOffset += 3; outsidePoint++;
2041        }
2042        if( /*(i>0) && <-- not needed since iStart is never 0*/ (finalPointPositionTable[i] < insideNumHalfTessFactorPoints))
2043        {
2044            // Advance inside
2045            DefineClockwiseTriangle(insidePoint,outsidePoint,insidePoint+1,baseIndexOffset);
2046            baseIndexOffset += 3; insidePoint++;
2047        }
2048    }
2049    // Below case is not needed if we didn't optimize loop above and made it run from 31 down to 0.
2050    if((finalPointPositionTable[0] < outsideNumHalfTessFactorPoints))
2051    {
2052        DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);
2053        baseIndexOffset += 3; outsidePoint++;
2054    }
2055}
2056
2057//---------------------------------------------------------------------------------------------------------------------------------
2058// CHWTessellator::PatchIndexValue()
2059//--------------------------------------------------------------------------------------------------------------------------------
2060int CHWTessellator::PatchIndexValue(int index)
2061{
2062    if( m_bUsingPatchedIndices )
2063    {
2064        if( index >= m_IndexPatchContext.outsidePointIndexPatchBase ) // assumed remapped outide indices are > remapped inside vertices
2065        {
2066            if( index == m_IndexPatchContext.outsidePointIndexBadValue )
2067                index = m_IndexPatchContext.outsidePointIndexReplacementValue;
2068            else
2069                index += m_IndexPatchContext.outsidePointIndexDeltaToRealValue;
2070        }
2071        else
2072        {
2073            if( index == m_IndexPatchContext.insidePointIndexBadValue )
2074                index = m_IndexPatchContext.insidePointIndexReplacementValue;
2075            else
2076                index += m_IndexPatchContext.insidePointIndexDeltaToRealValue;
2077        }
2078    }
2079    else if( m_bUsingPatchedIndices2 )
2080    {
2081        if( index >= m_IndexPatchContext2.baseIndexToInvert )
2082        {
2083            if( index == m_IndexPatchContext2.cornerCaseBadValue )
2084            {
2085                index = m_IndexPatchContext2.cornerCaseReplacementValue;
2086            }
2087            else
2088            {
2089                index = m_IndexPatchContext2.indexInversionEndPoint - index;
2090            }
2091        }
2092        else if( index == m_IndexPatchContext2.cornerCaseBadValue )
2093        {
2094            index = m_IndexPatchContext2.cornerCaseReplacementValue;
2095        }
2096    }
2097    return index;
2098}
2099
2100
2101//=================================================================================================================================
2102// CHLSLTessellator
2103//=================================================================================================================================
2104
2105//---------------------------------------------------------------------------------------------------------------------------------
2106// CHLSLTessellator::CHLSLTessellator
2107//---------------------------------------------------------------------------------------------------------------------------------
2108CHLSLTessellator::CHLSLTessellator()
2109{
2110    m_LastComputedTessFactors[0] = m_LastComputedTessFactors[1] = m_LastComputedTessFactors[2] =
2111    m_LastComputedTessFactors[3] = m_LastComputedTessFactors[4] = m_LastComputedTessFactors[5] = 0;
2112}
2113
2114//---------------------------------------------------------------------------------------------------------------------------------
2115// CHLSLTessellator::Init
2116// User calls this.
2117//---------------------------------------------------------------------------------------------------------------------------------
2118void CHLSLTessellator::Init(
2119    PIPE_TESSELLATOR_PARTITIONING       partitioning,
2120    PIPE_TESSELLATOR_REDUCTION          insideTessFactorReduction,
2121    PIPE_TESSELLATOR_QUAD_REDUCTION_AXIS quadInsideTessFactorReductionAxis,
2122    PIPE_TESSELLATOR_OUTPUT_PRIMITIVE   outputPrimitive)
2123{
2124    CHWTessellator::Init(partitioning,outputPrimitive);
2125    m_LastComputedTessFactors[0] = m_LastComputedTessFactors[1] = m_LastComputedTessFactors[2] =
2126    m_LastComputedTessFactors[3] = m_LastComputedTessFactors[4] = m_LastComputedTessFactors[5] = 0;
2127    m_partitioning = partitioning;
2128    m_originalPartitioning = partitioning;
2129    switch( partitioning )
2130    {
2131    case PIPE_TESSELLATOR_PARTITIONING_INTEGER:
2132    default:
2133        break;
2134    case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD:
2135        m_parity = TESSELLATOR_PARITY_ODD;
2136        break;
2137    case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN:
2138        m_parity = TESSELLATOR_PARITY_EVEN;
2139        break;
2140    }
2141    m_originalParity = m_parity;
2142    m_outputPrimitive = outputPrimitive;
2143    m_insideTessFactorReduction = insideTessFactorReduction;
2144    m_quadInsideTessFactorReductionAxis = quadInsideTessFactorReductionAxis;
2145}
2146//---------------------------------------------------------------------------------------------------------------------------------
2147// CHLSLTessellator::TessellateQuadDomain
2148// User calls this
2149//---------------------------------------------------------------------------------------------------------------------------------
2150void CHLSLTessellator::TessellateQuadDomain( float tessFactor_Ueq0, float tessFactor_Veq0, float tessFactor_Ueq1, float tessFactor_Veq1,
2151                                         float insideTessFactorScaleU, float insideTessFactorScaleV )
2152{
2153    QuadHLSLProcessTessFactors(tessFactor_Ueq0,tessFactor_Veq0,tessFactor_Ueq1,tessFactor_Veq1,insideTessFactorScaleU,insideTessFactorScaleV);
2154
2155    CHWTessellator::TessellateQuadDomain(m_LastComputedTessFactors[0],m_LastComputedTessFactors[1],m_LastComputedTessFactors[2],m_LastComputedTessFactors[3],
2156                                         m_LastComputedTessFactors[4],m_LastComputedTessFactors[5]);
2157}
2158
2159//---------------------------------------------------------------------------------------------------------------------------------
2160// CHLSLTessellator::QuadHLSLProcessTessFactors
2161//---------------------------------------------------------------------------------------------------------------------------------
2162void CHLSLTessellator::QuadHLSLProcessTessFactors( float tessFactor_Ueq0, float tessFactor_Veq0, float tessFactor_Ueq1, float tessFactor_Veq1,
2163                                               float insideTessFactorScaleU, float insideTessFactorScaleV )
2164{
2165    if( !(tessFactor_Ueq0 > 0) ||// NaN will pass
2166        !(tessFactor_Veq0 > 0) ||
2167        !(tessFactor_Ueq1 > 0) ||
2168        !(tessFactor_Veq1 > 0) )
2169    {
2170        m_LastUnRoundedComputedTessFactors[0] = tessFactor_Ueq0;
2171        m_LastUnRoundedComputedTessFactors[1] = tessFactor_Veq0;
2172        m_LastUnRoundedComputedTessFactors[2] = tessFactor_Ueq1;
2173        m_LastUnRoundedComputedTessFactors[3] = tessFactor_Veq1;
2174        m_LastUnRoundedComputedTessFactors[4] = 0;
2175        m_LastUnRoundedComputedTessFactors[5] = 0;
2176        m_LastComputedTessFactors[0] =
2177        m_LastComputedTessFactors[1] =
2178        m_LastComputedTessFactors[2] =
2179        m_LastComputedTessFactors[3] =
2180        m_LastComputedTessFactors[4] =
2181        m_LastComputedTessFactors[5] = 0;
2182        return;
2183    }
2184
2185    CleanupFloatTessFactor(tessFactor_Ueq0);// clamp to [1.0f..INF], NaN->1.0f
2186    CleanupFloatTessFactor(tessFactor_Veq0);
2187    CleanupFloatTessFactor(tessFactor_Ueq1);
2188    CleanupFloatTessFactor(tessFactor_Veq1);
2189
2190    // Save off tessFactors so they can be returned to app
2191    m_LastUnRoundedComputedTessFactors[0] = tessFactor_Ueq0;
2192    m_LastUnRoundedComputedTessFactors[1] = tessFactor_Veq0;
2193    m_LastUnRoundedComputedTessFactors[2] = tessFactor_Ueq1;
2194    m_LastUnRoundedComputedTessFactors[3] = tessFactor_Veq1;
2195
2196    // Process outside tessFactors
2197    float outsideTessFactor[QUAD_EDGES] = {tessFactor_Ueq0, tessFactor_Veq0, tessFactor_Ueq1, tessFactor_Veq1};
2198    int edge, axis;
2199    TESSELLATOR_PARITY insideTessFactorParity[QUAD_AXES];
2200    if( Pow2Partitioning() || IntegerPartitioning() )
2201    {
2202        for( edge = 0; edge < QUAD_EDGES; edge++ )
2203        {
2204            RoundUpTessFactor(outsideTessFactor[edge]);
2205            ClampTessFactor(outsideTessFactor[edge]); // clamp unbounded user input based on tessellation mode
2206        }
2207    }
2208    else
2209    {
2210        SetTessellationParity(m_originalParity); // ClampTessFactor needs it
2211        for( edge = 0; edge < QUAD_EDGES; edge++ )
2212        {
2213            ClampTessFactor(outsideTessFactor[edge]); // clamp unbounded user input based on tessellation mode
2214        }
2215    }
2216
2217    // Compute inside TessFactors
2218    float insideTessFactor[QUAD_AXES];
2219    if( m_quadInsideTessFactorReductionAxis == PIPE_TESSELLATOR_QUAD_REDUCTION_1_AXIS )
2220    {
2221        switch( m_insideTessFactorReduction )
2222        {
2223        case PIPE_TESSELLATOR_REDUCTION_MIN:
2224            insideTessFactor[U] = tess_fmin(tess_fmin(tessFactor_Veq0,tessFactor_Veq1),tess_fmin(tessFactor_Ueq0,tessFactor_Ueq1));
2225            break;
2226        case PIPE_TESSELLATOR_REDUCTION_MAX:
2227            insideTessFactor[U] = tess_fmax(tess_fmax(tessFactor_Veq0,tessFactor_Veq1),tess_fmax(tessFactor_Ueq0,tessFactor_Ueq1));
2228            break;
2229        case PIPE_TESSELLATOR_REDUCTION_AVERAGE:
2230            insideTessFactor[U] = (tessFactor_Veq0 + tessFactor_Veq1 + tessFactor_Ueq0 + tessFactor_Ueq1) / 4;
2231            break;
2232        default:
2233            unreachable("impossible m_insideTessFactorReduction");
2234        }
2235        // Scale inside tessFactor based on user scale factor.
2236
2237        ClampFloatTessFactorScale(insideTessFactorScaleU); // clamp scale value to [0..1], NaN->0
2238        insideTessFactor[U] = insideTessFactor[U]*insideTessFactorScaleU;
2239
2240        // Compute inside parity
2241        if( Pow2Partitioning() || IntegerPartitioning() )
2242        {
2243            ClampTessFactor(insideTessFactor[U]); // clamp reduction + scale result that is based on unbounded user input
2244            m_LastUnRoundedComputedTessFactors[4] = m_LastUnRoundedComputedTessFactors[5] = insideTessFactor[U]; // Save off TessFactors so they can be returned to app
2245            RoundUpTessFactor(insideTessFactor[U]);
2246            insideTessFactorParity[U] =
2247            insideTessFactorParity[V] =
2248                (isEven(insideTessFactor[U]) || (FLOAT_ONE == insideTessFactor[U]) )
2249                ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
2250        }
2251        else
2252        {
2253            ClampTessFactor(insideTessFactor[U]); // clamp reduction + scale result that is based on unbounded user input
2254            m_LastUnRoundedComputedTessFactors[4] = m_LastUnRoundedComputedTessFactors[5] = insideTessFactor[U]; // Save off TessFactors so they can be returned to app
2255            // no parity changes for fractional tessellation - just use what the user requested
2256            insideTessFactorParity[U] = insideTessFactorParity[V] = m_originalParity;
2257        }
2258
2259        // To prevent snapping on edges, the "picture frame" comes
2260        // in using avg or max (and ignore inside TessFactor scaling) until it is at least 3.
2261        if( (TESSELLATOR_PARITY_ODD == insideTessFactorParity[U]) &&
2262            (insideTessFactor[U] < FLOAT_THREE) )
2263        {
2264            if(PIPE_TESSELLATOR_REDUCTION_MAX == m_insideTessFactorReduction)
2265            {
2266                insideTessFactor[U] = tess_fmin(FLOAT_THREE,tess_fmax(tess_fmax(tessFactor_Veq0,tessFactor_Veq1),tess_fmax(tessFactor_Ueq0,tessFactor_Ueq1)));
2267            }
2268            else
2269            {
2270                insideTessFactor[U] = tess_fmin(FLOAT_THREE,(tessFactor_Veq0 + tessFactor_Veq1 + tessFactor_Ueq0 + tessFactor_Ueq1) / 4);
2271            }
2272            ClampTessFactor(insideTessFactor[U]); // clamp reduction result that is based on unbounded user input
2273            m_LastUnRoundedComputedTessFactors[4] = m_LastUnRoundedComputedTessFactors[5] = insideTessFactor[U]; // Save off TessFactors so they can be returned to app
2274            if( IntegerPartitioning())
2275            {
2276                RoundUpTessFactor(insideTessFactor[U]);
2277                insideTessFactorParity[U] =
2278                insideTessFactorParity[V] = isEven(insideTessFactor[U]) ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
2279            }
2280        }
2281        insideTessFactor[V] = insideTessFactor[U];
2282    }
2283    else
2284    {
2285        switch( m_insideTessFactorReduction )
2286        {
2287        case PIPE_TESSELLATOR_REDUCTION_MIN:
2288            insideTessFactor[U] = tess_fmin(tessFactor_Veq0,tessFactor_Veq1);
2289            insideTessFactor[V] = tess_fmin(tessFactor_Ueq0,tessFactor_Ueq1);
2290            break;
2291        case PIPE_TESSELLATOR_REDUCTION_MAX:
2292            insideTessFactor[U] = tess_fmax(tessFactor_Veq0,tessFactor_Veq1);
2293            insideTessFactor[V] = tess_fmax(tessFactor_Ueq0,tessFactor_Ueq1);
2294            break;
2295        case PIPE_TESSELLATOR_REDUCTION_AVERAGE:
2296            insideTessFactor[U] = (tessFactor_Veq0 + tessFactor_Veq1) / 2;
2297            insideTessFactor[V] = (tessFactor_Ueq0 + tessFactor_Ueq1) / 2;
2298            break;
2299        default:
2300            unreachable("impossible m_insideTessFactorReduction");
2301        }
2302        // Scale inside tessFactors based on user scale factor.
2303
2304        ClampFloatTessFactorScale(insideTessFactorScaleU); // clamp scale value to [0..1], NaN->0
2305        ClampFloatTessFactorScale(insideTessFactorScaleV);
2306        insideTessFactor[U] = insideTessFactor[U]*insideTessFactorScaleU;
2307        insideTessFactor[V] = insideTessFactor[V]*insideTessFactorScaleV;
2308
2309        // Compute inside parity
2310        if( Pow2Partitioning() || IntegerPartitioning() )
2311        {
2312            for( axis = 0; axis < QUAD_AXES; axis++ )
2313            {
2314                ClampTessFactor(insideTessFactor[axis]); // clamp reduction + scale result that is based on unbounded user input
2315                m_LastUnRoundedComputedTessFactors[4+axis] = insideTessFactor[axis]; // Save off TessFactors so they can be returned to app
2316                RoundUpTessFactor(insideTessFactor[axis]);
2317                insideTessFactorParity[axis] =
2318                    (isEven(insideTessFactor[axis]) || (FLOAT_ONE == insideTessFactor[axis]) )
2319                    ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
2320            }
2321        }
2322        else
2323        {
2324            ClampTessFactor(insideTessFactor[U]); // clamp reduction + scale result that is based on unbounded user input
2325            ClampTessFactor(insideTessFactor[V]); // clamp reduction + scale result that is based on unbounded user input
2326            m_LastUnRoundedComputedTessFactors[4] = insideTessFactor[U]; // Save off TessFactors so they can be returned to app
2327            m_LastUnRoundedComputedTessFactors[5] = insideTessFactor[V]; // Save off TessFactors so they can be returned to app
2328             // no parity changes for fractional tessellation - just use what the user requested
2329            insideTessFactorParity[U] = insideTessFactorParity[V] = m_originalParity;
2330        }
2331
2332        // To prevent snapping on edges, the "picture frame" comes
2333        // in using avg or max (and ignore inside TessFactor scaling) until it is at least 3.
2334        if( (TESSELLATOR_PARITY_ODD == insideTessFactorParity[U]) &&
2335            (insideTessFactor[U] < FLOAT_THREE) )
2336        {
2337            if(PIPE_TESSELLATOR_REDUCTION_MAX == m_insideTessFactorReduction)
2338            {
2339                insideTessFactor[U] = tess_fmin(FLOAT_THREE,tess_fmax(tessFactor_Veq0,tessFactor_Veq1));
2340            }
2341            else
2342            {
2343                insideTessFactor[U] = tess_fmin(FLOAT_THREE,(tessFactor_Veq0 + tessFactor_Veq1) / 2);
2344            }
2345            ClampTessFactor(insideTessFactor[U]); // clamp reduction result that is based on unbounded user input
2346            m_LastUnRoundedComputedTessFactors[4] = insideTessFactor[U]; // Save off TessFactors so they can be returned to app
2347            if( IntegerPartitioning())
2348            {
2349                RoundUpTessFactor(insideTessFactor[U]);
2350                insideTessFactorParity[U] = isEven(insideTessFactor[U]) ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
2351            }
2352        }
2353
2354        if( (TESSELLATOR_PARITY_ODD == insideTessFactorParity[V]) &&
2355            (insideTessFactor[V] < FLOAT_THREE) )
2356        {
2357            if(PIPE_TESSELLATOR_REDUCTION_MAX == m_insideTessFactorReduction)
2358            {
2359                insideTessFactor[V] = tess_fmin(FLOAT_THREE,tess_fmax(tessFactor_Ueq0,tessFactor_Ueq1));
2360            }
2361            else
2362            {
2363                insideTessFactor[V] = tess_fmin(FLOAT_THREE,(tessFactor_Ueq0 + tessFactor_Ueq1) / 2);
2364            }
2365            ClampTessFactor(insideTessFactor[V]);// clamp reduction result that is based on unbounded user input
2366            m_LastUnRoundedComputedTessFactors[5] = insideTessFactor[V]; // Save off TessFactors so they can be returned to app
2367            if( IntegerPartitioning())
2368            {
2369                RoundUpTessFactor(insideTessFactor[V]);
2370                insideTessFactorParity[V] = isEven(insideTessFactor[V]) ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
2371            }
2372        }
2373
2374        for( axis = 0; axis < QUAD_AXES; axis++ )
2375        {
2376            if( TESSELLATOR_PARITY_ODD == insideTessFactorParity[axis] )
2377            {
2378                // Ensure the first ring ("picture frame") interpolates in on all sides
2379                // as much as the side with the minimum TessFactor.  Prevents snapping to edge.
2380                if( (insideTessFactor[axis] < FLOAT_THREE) && (insideTessFactor[axis] < insideTessFactor[(axis+1)&0x1]))
2381                {
2382                    insideTessFactor[axis] = tess_fmin(insideTessFactor[(axis+1)&0x1],FLOAT_THREE);
2383                    m_LastUnRoundedComputedTessFactors[4+axis] = insideTessFactor[axis]; // Save off TessFactors so they can be returned to app
2384                }
2385            }
2386        }
2387    }
2388
2389    // Save off TessFactors so they can be returned to app
2390    m_LastComputedTessFactors[0] = outsideTessFactor[Ueq0];
2391    m_LastComputedTessFactors[1] = outsideTessFactor[Veq0];
2392    m_LastComputedTessFactors[2] = outsideTessFactor[Ueq1];
2393    m_LastComputedTessFactors[3] = outsideTessFactor[Veq1];
2394    m_LastComputedTessFactors[4] = insideTessFactor[U];
2395    m_LastComputedTessFactors[5] = insideTessFactor[V];
2396}
2397
2398//---------------------------------------------------------------------------------------------------------------------------------
2399// CHLSLTessellator::TessellateTriDomain
2400// User calls this
2401//---------------------------------------------------------------------------------------------------------------------------------
2402void CHLSLTessellator::TessellateTriDomain( float tessFactor_Ueq0, float tessFactor_Veq0, float tessFactor_Weq0,
2403                                        float insideTessFactorScale )
2404{
2405    TriHLSLProcessTessFactors(tessFactor_Ueq0,tessFactor_Veq0,tessFactor_Weq0,insideTessFactorScale);
2406
2407    CHWTessellator::TessellateTriDomain(m_LastComputedTessFactors[0],m_LastComputedTessFactors[1],m_LastComputedTessFactors[2],m_LastComputedTessFactors[3]);
2408}
2409
2410//---------------------------------------------------------------------------------------------------------------------------------
2411// CHLSLTessellator::TriHLSLProcessTessFactors
2412//---------------------------------------------------------------------------------------------------------------------------------
2413void CHLSLTessellator::TriHLSLProcessTessFactors( float tessFactor_Ueq0, float tessFactor_Veq0, float tessFactor_Weq0,
2414                                  float insideTessFactorScale )
2415{
2416    if( !(tessFactor_Ueq0 > 0) || // NaN will pass
2417        !(tessFactor_Veq0 > 0) ||
2418        !(tessFactor_Weq0 > 0) )
2419    {
2420        m_LastUnRoundedComputedTessFactors[0] = tessFactor_Ueq0;
2421        m_LastUnRoundedComputedTessFactors[1] = tessFactor_Veq0;
2422        m_LastUnRoundedComputedTessFactors[2] = tessFactor_Weq0;
2423        m_LastUnRoundedComputedTessFactors[3] =
2424        m_LastComputedTessFactors[0] =
2425        m_LastComputedTessFactors[1] =
2426        m_LastComputedTessFactors[2] =
2427        m_LastComputedTessFactors[3] = 0;
2428        return;
2429    }
2430
2431    CleanupFloatTessFactor(tessFactor_Ueq0); // clamp to [1.0f..INF], NaN->1.0f
2432    CleanupFloatTessFactor(tessFactor_Veq0);
2433    CleanupFloatTessFactor(tessFactor_Weq0);
2434
2435    // Save off TessFactors so they can be returned to app
2436    m_LastUnRoundedComputedTessFactors[0] = tessFactor_Ueq0;
2437    m_LastUnRoundedComputedTessFactors[1] = tessFactor_Veq0;
2438    m_LastUnRoundedComputedTessFactors[2] = tessFactor_Weq0;
2439
2440    // Process outside TessFactors
2441    float outsideTessFactor[TRI_EDGES] = {tessFactor_Ueq0, tessFactor_Veq0, tessFactor_Weq0};
2442    int edge;
2443    if( Pow2Partitioning() || IntegerPartitioning() )
2444    {
2445        for( edge = 0; edge < TRI_EDGES; edge++ )
2446        {
2447            RoundUpTessFactor(outsideTessFactor[edge]); // for pow2 this rounds to pow2
2448            ClampTessFactor(outsideTessFactor[edge]); // clamp unbounded user input based on tessellation mode
2449        }
2450    }
2451    else
2452    {
2453        for( edge = 0; edge < TRI_EDGES; edge++ )
2454        {
2455            ClampTessFactor(outsideTessFactor[edge]); // clamp unbounded user input based on tessellation mode
2456        }
2457    }
2458
2459    // Compute inside TessFactor
2460    float insideTessFactor;
2461    switch( m_insideTessFactorReduction )
2462    {
2463    case PIPE_TESSELLATOR_REDUCTION_MIN:
2464        insideTessFactor = tess_fmin(tess_fmin(tessFactor_Ueq0,tessFactor_Veq0),tessFactor_Weq0);
2465        break;
2466    case PIPE_TESSELLATOR_REDUCTION_MAX:
2467        insideTessFactor = tess_fmax(tess_fmax(tessFactor_Ueq0,tessFactor_Veq0),tessFactor_Weq0);
2468        break;
2469    case PIPE_TESSELLATOR_REDUCTION_AVERAGE:
2470        insideTessFactor = (tessFactor_Ueq0 + tessFactor_Veq0 + tessFactor_Weq0) / 3;
2471        break;
2472    default:
2473        unreachable("impossible m_insideTessFactorReduction");
2474    }
2475
2476    // Scale inside TessFactor based on user scale factor.
2477    ClampFloatTessFactorScale(insideTessFactorScale); // clamp scale value to [0..1], NaN->0
2478    insideTessFactor = insideTessFactor*tess_fmin(FLOAT_ONE,insideTessFactorScale);
2479
2480    ClampTessFactor(insideTessFactor); // clamp reduction + scale result that is based on unbounded user input
2481    m_LastUnRoundedComputedTessFactors[3] = insideTessFactor;// Save off TessFactors so they can be returned to app
2482    TESSELLATOR_PARITY parity;
2483    if( Pow2Partitioning() || IntegerPartitioning() )
2484    {
2485        RoundUpTessFactor(insideTessFactor);
2486        parity = (isEven(insideTessFactor) || (FLOAT_ONE == insideTessFactor))
2487                                        ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
2488    }
2489    else
2490    {
2491        parity = m_originalParity;
2492    }
2493
2494    if( (TESSELLATOR_PARITY_ODD == parity) &&
2495        (insideTessFactor < FLOAT_THREE))
2496    {
2497        // To prevent snapping on edges, the "picture frame" comes
2498        // in using avg or max (and ignore inside TessFactor scaling) until it is at least 3.
2499        if(PIPE_TESSELLATOR_REDUCTION_MAX == m_insideTessFactorReduction)
2500        {
2501            insideTessFactor = tess_fmin(FLOAT_THREE,tess_fmax(tessFactor_Ueq0,tess_fmax(tessFactor_Veq0,tessFactor_Weq0)));
2502        }
2503        else
2504        {
2505            insideTessFactor = tess_fmin(FLOAT_THREE,(tessFactor_Ueq0 + tessFactor_Veq0 + tessFactor_Weq0) / 3);
2506        }
2507        ClampTessFactor(insideTessFactor); // clamp reduction result that is based on unbounded user input
2508        m_LastUnRoundedComputedTessFactors[3] = insideTessFactor;// Save off TessFactors so they can be returned to app
2509        if( IntegerPartitioning())
2510        {
2511            RoundUpTessFactor(insideTessFactor);
2512        }
2513    }
2514
2515    // Save off TessFactors so they can be returned to app
2516    m_LastComputedTessFactors[0] = outsideTessFactor[Ueq0];
2517    m_LastComputedTessFactors[1] = outsideTessFactor[Veq0];
2518    m_LastComputedTessFactors[2] = outsideTessFactor[Weq0];
2519    m_LastComputedTessFactors[3] = insideTessFactor;
2520}
2521
2522//---------------------------------------------------------------------------------------------------------------------------------
2523// CHLSLTessellator::TessellateIsoLineDomain
2524// User calls this.
2525//---------------------------------------------------------------------------------------------------------------------------------
2526void CHLSLTessellator::TessellateIsoLineDomain( float TessFactor_U_LineDetail, float TessFactor_V_LineDensity )
2527{
2528    IsoLineHLSLProcessTessFactors(TessFactor_V_LineDensity,TessFactor_U_LineDetail);
2529    CHWTessellator::TessellateIsoLineDomain(m_LastComputedTessFactors[0],m_LastComputedTessFactors[1]);
2530}
2531
2532//---------------------------------------------------------------------------------------------------------------------------------
2533// CHLSLTessellator::IsoLineHLSLProcessTessFactors
2534//---------------------------------------------------------------------------------------------------------------------------------
2535void CHLSLTessellator::IsoLineHLSLProcessTessFactors( float TessFactor_V_LineDensity, float TessFactor_U_LineDetail )
2536{
2537    if( !(TessFactor_V_LineDensity > 0) || // NaN will pass
2538        !(TessFactor_U_LineDetail > 0) )
2539    {
2540        m_LastUnRoundedComputedTessFactors[0] = TessFactor_V_LineDensity;
2541        m_LastUnRoundedComputedTessFactors[1] = TessFactor_U_LineDetail;
2542        m_LastComputedTessFactors[0] =
2543        m_LastComputedTessFactors[1] = 0;
2544        return;
2545    }
2546
2547    CleanupFloatTessFactor(TessFactor_V_LineDensity); // clamp to [1.0f..INF], NaN->1.0f
2548    CleanupFloatTessFactor(TessFactor_U_LineDetail); // clamp to [1.0f..INF], NaN->1.0f
2549
2550    ClampTessFactor(TessFactor_U_LineDetail); // clamp unbounded user input based on tessellation mode
2551
2552    m_LastUnRoundedComputedTessFactors[1] = TessFactor_U_LineDetail;    // Save off TessFactors so they can be returned to app
2553
2554    if(Pow2Partitioning()||IntegerPartitioning())
2555    {
2556        RoundUpTessFactor(TessFactor_U_LineDetail);
2557    }
2558
2559    OverridePartitioning(PIPE_TESSELLATOR_PARTITIONING_INTEGER);
2560
2561    ClampTessFactor(TessFactor_V_LineDensity); // Clamp unbounded user input to integer
2562    m_LastUnRoundedComputedTessFactors[0] = TessFactor_V_LineDensity;    // Save off TessFactors so they can be returned to app
2563
2564    RoundUpTessFactor(TessFactor_V_LineDensity);
2565
2566    RestorePartitioning();
2567
2568    // Save off TessFactors so they can be returned to app
2569    m_LastComputedTessFactors[0] = TessFactor_V_LineDensity;
2570    m_LastComputedTessFactors[1] = TessFactor_U_LineDetail;
2571}
2572
2573//---------------------------------------------------------------------------------------------------------------------------------
2574// CHLSLTessellator::ClampTessFactor()
2575//---------------------------------------------------------------------------------------------------------------------------------
2576void CHLSLTessellator::ClampTessFactor(float& TessFactor)
2577{
2578    if( Pow2Partitioning() )
2579    {
2580        TessFactor = tess_fmin( PIPE_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR, tess_fmax( TessFactor, PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR) );
2581    }
2582    else if( IntegerPartitioning() )
2583    {
2584        TessFactor = tess_fmin( PIPE_TESSELLATOR_MAX_TESSELLATION_FACTOR, tess_fmax( TessFactor, PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR) );
2585    }
2586    else if( Odd() )
2587    {
2588        TessFactor = tess_fmin( PIPE_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR, tess_fmax( TessFactor, PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR) );
2589    }
2590    else // even
2591    {
2592        TessFactor = tess_fmin( PIPE_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR, tess_fmax( TessFactor, PIPE_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR) );
2593    }
2594}
2595
2596//---------------------------------------------------------------------------------------------------------------------------------
2597// CHLSLTessellator::CleanupFloatTessFactor()
2598//---------------------------------------------------------------------------------------------------------------------------------
2599static const int exponentMask = 0x7f800000;
2600static const int mantissaMask = 0x007fffff;
2601void CHLSLTessellator::CleanupFloatTessFactor(float& input)
2602{
2603    // If input is < 1.0f or NaN, clamp to 1.0f.
2604    // In other words, clamp input to [1.0f...+INF]
2605    int bits = *(int*)&input;
2606    if( ( ( ( bits & exponentMask ) == exponentMask ) && ( bits & mantissaMask ) ) ||// nan?
2607        (input < 1.0f) )
2608    {
2609        input = 1;
2610    }
2611}
2612
2613//---------------------------------------------------------------------------------------------------------------------------------
2614// CHLSLTessellator::ClampFloatTessFactorScale()
2615//---------------------------------------------------------------------------------------------------------------------------------
2616void CHLSLTessellator::ClampFloatTessFactorScale(float& input)
2617{
2618    // If input is < 0.0f or NaN, clamp to 0.0f.  > 1 clamps to 1.
2619    // In other words, clamp input to [0.0f...1.0f]
2620    int bits = *(int*)&input;
2621    if( ( ( ( bits & exponentMask ) == exponentMask ) && ( bits & mantissaMask ) ) ||// nan?
2622        (input < 0.0f) )
2623    {
2624        input = 0;
2625    }
2626    else if( input > 1 )
2627    {
2628        input = 1;
2629    }
2630}
2631
2632//---------------------------------------------------------------------------------------------------------------------------------
2633// CHLSLTessellator::RoundUpTessFactor()
2634//---------------------------------------------------------------------------------------------------------------------------------
2635static const int exponentLSB = 0x00800000;
2636void CHLSLTessellator::RoundUpTessFactor(float& TessFactor)
2637{
2638    // Assume TessFactor is in [1.0f..+INF]
2639    if( Pow2Partitioning() )
2640    {
2641        int bits = *(int*)&TessFactor;
2642        if( bits & mantissaMask )
2643        {
2644            *(int*)&TessFactor = (bits & exponentMask) + exponentLSB;
2645        }
2646    }
2647    else if( IntegerPartitioning() )
2648    {
2649        TessFactor = ceil(TessFactor);
2650    }
2651}
2652