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