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