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